From 77d5c628155cc5131c3baa3a7fd0fc8726fe409f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 24 Apr 2018 15:09:38 -0700 Subject: [PATCH 001/203] cmd/go: add Solaris assembler syntax for gccgo buildid file The Solaris assembler uses a different syntax for section directives. Fixes https://gcc.gnu.org/PR85429. Change-Id: I1e54dffee3290046dbb68ba4e90ab795c6b72571 Reviewed-on: https://go-review.googlesource.com/109140 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/go/internal/work/buildid.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index f1c538c309..04ff01a350 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -294,13 +294,32 @@ func (b *Builder) gccgoToolID(name, language string) (string, error) { return id, nil } +// Check if assembler used by gccgo is GNU as. +func assemblerIsGas() bool { + cmd := exec.Command(BuildToolchain.compiler(), "-print-prog-name=as") + assembler, err := cmd.Output() + if err == nil { + cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version") + out, err := cmd.Output() + return err == nil && strings.Contains(string(out), "GNU") + } else { + return false + } +} + // gccgoBuildIDELFFile creates an assembler file that records the // action's build ID in an SHF_EXCLUDE section. func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { sfile := a.Objdir + "_buildid.s" var buf bytes.Buffer - fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + if cfg.Goos != "solaris" || assemblerIsGas() { + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") + } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" { + fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n") + } else { // cfg.Goarch == "386" || cfg.Goarch == "amd64" + fmt.Fprintf(&buf, "\t"+`.section .go.buildid,#exclude`+"\n") + } fmt.Fprintf(&buf, "\t.byte ") for i := 0; i < len(a.buildID); i++ { if i > 0 { @@ -313,8 +332,10 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { fmt.Fprintf(&buf, "%#02x", a.buildID[i]) } fmt.Fprintf(&buf, "\n") - fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") - fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + if cfg.Goos != "solaris" { + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n") + fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n") + } if cfg.BuildN || cfg.BuildX { for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { From 1f137052e4a20dbd302f947b1cf34cdf4b427d65 Mon Sep 17 00:00:00 2001 From: Mark Rushakoff Date: Sat, 9 Jun 2018 00:01:42 +0000 Subject: [PATCH 002/203] strconv: add missing period to godoc comment Change-Id: I90ba0a6e0c6ccdce16938eed09424308a84fc6fb GitHub-Last-Rev: 66b6db1a674e6817209a69a7ccd1846d3b0e1900 GitHub-Pull-Request: golang/go#25801 Reviewed-on: https://go-review.googlesource.com/117575 Reviewed-by: Ian Lance Taylor --- src/strconv/atob.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strconv/atob.go b/src/strconv/atob.go index 879ceb385e..0a495008d7 100644 --- a/src/strconv/atob.go +++ b/src/strconv/atob.go @@ -17,7 +17,7 @@ func ParseBool(str string) (bool, error) { return false, syntaxError("ParseBool", str) } -// FormatBool returns "true" or "false" according to the value of b +// FormatBool returns "true" or "false" according to the value of b. func FormatBool(b bool) string { if b { return "true" From d67db881465320b46e8142d5eac1b808c3ac659d Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Sat, 2 Jun 2018 15:35:25 +1000 Subject: [PATCH 003/203] cmd/link: split pe .text section into .text and .rdata Fixes #24725 Change-Id: I2864b88315ab15be036e8940d0a5884d876698d6 Reviewed-on: https://go-review.googlesource.com/115975 Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/data.go | 10 ++++-- src/cmd/link/internal/ld/pe.go | 58 ++++++++++++++++++++++---------- src/cmd/nm/nm_test.go | 18 ++++++++++ 3 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index be65b7be06..3e4773102d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1352,9 +1352,8 @@ func (ctxt *Link) dodata() { /* * We finished data, begin read-only data. * Not all systems support a separate read-only non-executable data section. - * ELF systems do. + * ELF and Windows PE systems do. * OS X and Plan 9 do not. - * Windows PE may, but if so we have not implemented it. * And if we're using external linking mode, the point is moot, * since it's not our decision; that code expects the sections in * segtext. @@ -1362,6 +1361,8 @@ func (ctxt *Link) dodata() { var segro *sym.Segment if ctxt.IsELF && ctxt.LinkMode == LinkInternal { segro = &Segrodata + } else if ctxt.HeadType == objabi.Hwindows { + segro = &Segrodata } else { segro = &Segtext } @@ -1940,6 +1941,9 @@ func (ctxt *Link) address() { Segrodata.Vaddr = va Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff Segrodata.Filelen = 0 + if ctxt.HeadType == objabi.Hwindows { + Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN)) + } for _, s := range Segrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1974,7 +1978,7 @@ func (ctxt *Link) address() { Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff Segdata.Filelen = 0 if ctxt.HeadType == objabi.Hwindows { - Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN)) + Segdata.Fileoff = Segrodata.Fileoff + uint64(Rnd(int64(Segrodata.Length), PEFILEALIGN)) } if ctxt.HeadType == objabi.Hplan9 { Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 8005dc5228..85acb7a11b 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -395,6 +395,7 @@ type peFile struct { sections []*peSection stringTable peStringTable textSect *peSection + rdataSect *peSection dataSect *peSection bssSect *peSection ctorsSect *peSection @@ -548,21 +549,24 @@ func (f *peFile) emitRelocations(ctxt *Link) { return relocs } - f.textSect.emitRelocations(ctxt.Out, func() int { - n := relocsect(Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr) - for _, sect := range Segtext.Sections[1:] { - n += relocsect(sect, datap, Segtext.Vaddr) - } - return n - }) - - f.dataSect.emitRelocations(ctxt.Out, func() int { - var n int - for _, sect := range Segdata.Sections { - n += relocsect(sect, datap, Segdata.Vaddr) - } - return n - }) + sects := []struct { + peSect *peSection + seg *sym.Segment + syms []*sym.Symbol + }{ + {f.textSect, &Segtext, ctxt.Textp}, + {f.rdataSect, &Segrodata, datap}, + {f.dataSect, &Segdata, datap}, + } + for _, s := range sects { + s.peSect.emitRelocations(ctxt.Out, func() int { + var n int + for _, sect := range s.seg.Sections { + n += relocsect(sect, s.syms, s.seg.Vaddr) + } + return n + }) + } dwarfLoop: for _, sect := range Segdwarf.Sections { @@ -622,8 +626,11 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int if s.Sect.Seg == &Segtext { return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil } + if s.Sect.Seg == &Segrodata { + return f.rdataSect.index, int64(uint64(s.Value) - Segrodata.Vaddr), nil + } if s.Sect.Seg != &Segdata { - return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .data section", s.Name) + return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", s.Name) } v := uint64(s.Value) - Segdata.Vaddr if linkmode != LinkExternal { @@ -904,7 +911,11 @@ func Peinit(ctxt *Link) { } if ctxt.LinkMode == LinkExternal { - PESECTALIGN = 0 + // .rdata section will contain "masks" and "shifts" symbols, and they + // need to be aligned to 16-bytes. So make all sections aligned + // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external + // linker will honour that requirement. + PESECTALIGN = 32 PEFILEALIGN = 0 } @@ -1325,6 +1336,19 @@ func Asmbpe(ctxt *Link) { t.checkSegment(&Segtext) pefile.textSect = t + ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length)) + ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ + if ctxt.LinkMode == LinkExternal { + // some data symbols (e.g. masks) end up in the .rdata section, and they normally + // expect larger alignment requirement than the default text section alignment. + ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES + } else { + // TODO(brainman): should not need IMAGE_SCN_MEM_EXECUTE, but I do not know why it carshes without it + ro.characteristics |= IMAGE_SCN_MEM_EXECUTE + } + ro.checkSegment(&Segrodata) + pefile.rdataSect = ro + var d *peSection if ctxt.LinkMode != LinkExternal { d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen)) diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 4be5d0e74e..890df0f902 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -126,6 +126,15 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { names["main."+f[0]] = f[1] } + runtimeSyms := map[string]string{ + "runtime.text": "T", + "runtime.etext": "T", + "runtime.rodata": "R", + "runtime.erodata": "R", + "runtime.epclntab": "R", + "runtime.noptrdata": "D", + } + out, err = exec.Command(testnmpath, exe).CombinedOutput() if err != nil { t.Fatalf("go tool nm: %v\n%s", err, string(out)) @@ -147,6 +156,12 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { if _, found := dups[name]; found { t.Errorf("duplicate name of %q is found", name) } + if stype, found := runtimeSyms[name]; found { + if want, have := stype, strings.ToUpper(f[1]); have != want { + t.Errorf("want %s type for %s symbol, but have %s", want, name, have) + } + delete(runtimeSyms, name) + } } err = scanner.Err() if err != nil { @@ -155,6 +170,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { if len(names) > 0 { t.Errorf("executable is missing %v symbols", names) } + if len(runtimeSyms) > 0 { + t.Errorf("executable is missing %v symbols", runtimeSyms) + } } func TestGoExec(t *testing.T) { From a5f83037aeb74032870946c20780e6ba61f326a2 Mon Sep 17 00:00:00 2001 From: Caleb Spare Date: Sat, 9 Jun 2018 20:14:44 -0700 Subject: [PATCH 004/203] net/http/httptest: deprecate ResponseRecorder.HeaderMap Users of this field are better off using Result instead. Fixes #25763. Change-Id: I4391afa6ed3873107628630adc1d409d77fb3f20 Reviewed-on: https://go-review.googlesource.com/117675 Reviewed-by: Brad Fitzpatrick --- src/net/http/httptest/recorder.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go index 22170cf98b..1d0310625b 100644 --- a/src/net/http/httptest/recorder.go +++ b/src/net/http/httptest/recorder.go @@ -27,9 +27,11 @@ type ResponseRecorder struct { Code int // HeaderMap contains the headers explicitly set by the Handler. + // It is an internal detail. // - // To get the implicit headers set by the server (such as - // automatic Content-Type), use the Result method. + // Deprecated: HeaderMap exists for historical compatibility + // and should not be used. To access the headers returned by a handler, + // use the Response.Header map as returned by the Result method. HeaderMap http.Header // Body is the buffer to which the Handler's Write calls are sent. From b3562658fddef6e9008379cac16c04c26784b7ed Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Wed, 16 May 2018 19:29:41 +0530 Subject: [PATCH 005/203] net/http: add application/wasm mime type Although not part of http://mimesniff.spec.whatwg.org, for WASM streaming compilation to happen, the response needs to have the application/wasm MIME type as mentioned here: https://webassembly.github.io/spec/web-api/index.html#streaming-modules. And all current browsers prevent streaming compilation from happening if this MIME type is not present in the response. The magic number is mentioned here: https://webassembly.org/docs/binary-encoding Since we are already adding WASM support, it makes sense to support this MIME type. Change-Id: I8dd7b413a8c438a5c23c29d843b42f6da2a20ba4 Reviewed-on: https://go-review.googlesource.com/113396 Reviewed-by: Richard Musiol Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/net/http/sniff.go | 2 ++ src/net/http/sniff_test.go | 1 + 2 files changed, 3 insertions(+) diff --git a/src/net/http/sniff.go b/src/net/http/sniff.go index ff934ff357..c1494abb4c 100644 --- a/src/net/http/sniff.go +++ b/src/net/http/sniff.go @@ -147,6 +147,8 @@ var sniffSignatures = []sniffSig{ &exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"}, &exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"}, + &exactSig{[]byte("\x00\x61\x73\x6D"), "application/wasm"}, + mp4Sig{}, textSig{}, // should be last diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go index b9e9488610..b4d3c9f0cc 100644 --- a/src/net/http/sniff_test.go +++ b/src/net/http/sniff_test.go @@ -65,6 +65,7 @@ var sniffTests = []struct { {"woff sample I", []byte("\x77\x4f\x46\x46\x00\x01\x00\x00\x00\x00\x30\x54\x00\x0d\x00\x00"), "font/woff"}, {"woff2 sample", []byte("\x77\x4f\x46\x32\x00\x01\x00\x00\x00"), "font/woff2"}, + {"wasm sample", []byte("\x00\x61\x73\x6d\x01\x00"), "application/wasm"}, } func TestDetectContentType(t *testing.T) { From b74f7321e594e2c4bcdf1b048e755ddc90c4134d Mon Sep 17 00:00:00 2001 From: Thanabodee Charoenpiriyakij Date: Sun, 10 Jun 2018 01:01:27 +0700 Subject: [PATCH 006/203] syscall: update TOKEN_ALL_ACCESS according to WinNT.h TOKEN_ALL_ACCESS was changed at some stage by Microsoft. Updates #25775 Change-Id: I3e18914207a0020b2ebfb99f4e57aa55f9de813b Reviewed-on: https://go-review.googlesource.com/117635 TryBot-Result: Gobot Gobot Reviewed-by: Alex Brainman --- api/except.txt | 2 ++ src/syscall/security_windows.go | 4 +++- src/syscall/syscall_windows_test.go | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/api/except.txt b/api/except.txt index 997df042b6..b85003eda2 100644 --- a/api/except.txt +++ b/api/except.txt @@ -377,9 +377,11 @@ pkg syscall (windows-386), type CertContext struct, CertInfo uintptr pkg syscall (windows-386), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr +pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr pkg syscall (windows-amd64), type CertContext struct, CertInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr +pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295 diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go index dbaf6d3264..ae8b3a17bf 100644 --- a/src/syscall/security_windows.go +++ b/src/syscall/security_windows.go @@ -221,6 +221,7 @@ const ( TOKEN_ADJUST_PRIVILEGES TOKEN_ADJUST_GROUPS TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_SESSIONID TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | @@ -230,7 +231,8 @@ const ( TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | - TOKEN_ADJUST_DEFAULT + TOKEN_ADJUST_DEFAULT | + TOKEN_ADJUST_SESSIONID TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY TOKEN_WRITE = STANDARD_RIGHTS_WRITE | TOKEN_ADJUST_PRIVILEGES | diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go index 86842f2ad2..d146911073 100644 --- a/src/syscall/syscall_windows_test.go +++ b/src/syscall/syscall_windows_test.go @@ -70,3 +70,9 @@ func ExampleLoadLibrary() { build := uint16(r >> 16) print("windows version ", major, ".", minor, " (Build ", build, ")\n") } + +func TestTOKEN_ALL_ACCESS(t *testing.T) { + if syscall.TOKEN_ALL_ACCESS != 0xF01FF { + t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", syscall.TOKEN_ALL_ACCESS) + } +} From 679690f348a38591ccf180d9f699fc40a544e6af Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Mon, 11 Jun 2018 11:03:25 +1000 Subject: [PATCH 007/203] net: add TestSendfileParts Add test for freebsd issue #25809. This test also fails on my Windows 10 Version 1803. My hope is that adding new test will break one of our builders. Updates #25722 Updates #25809 Change-Id: Ia103bc708b8fa3b9af57613acc44893f90b3fa18 Reviewed-on: https://go-review.googlesource.com/117775 Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/sendfile_test.go | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index 75d4b4e9bf..3418d7f243 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -7,11 +7,13 @@ package net import ( + "bytes" "crypto/sha256" "encoding/hex" "fmt" "io" "os" + "runtime" "testing" ) @@ -90,3 +92,65 @@ func TestSendfile(t *testing.T) { t.Error(err) } } + +func TestSendfileParts(t *testing.T) { + if runtime.GOOS == "freebsd" { + t.Skipf("skipping on %s (see golang.org/issue/25809 for details)", runtime.GOOS) + } + + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + errc := make(chan error, 1) + go func(ln Listener) { + // Wait for a connection. + conn, err := ln.Accept() + if err != nil { + errc <- err + close(errc) + return + } + + go func() { + defer close(errc) + defer conn.Close() + + f, err := os.Open(twain) + if err != nil { + errc <- err + return + } + defer f.Close() + + for i := 0; i < 3; i++ { + // Return file data using io.CopyN, which should use + // sendFile if available. + _, err = io.CopyN(conn, f, 3) + if err != nil { + errc <- err + return + } + } + }() + }(ln) + + c, err := Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + buf := new(bytes.Buffer) + buf.ReadFrom(c) + + if want, have := "Produced ", buf.String(); have != want { + t.Errorf("unexpected server reply %q, want %q", have, want) + } + + for err := range errc { + t.Error(err) + } +} From 40fc4bbfb86ea82ecb16794cd093a36a87d38197 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 11 Jun 2018 09:40:45 +0200 Subject: [PATCH 008/203] net: skip TestSendfileParts on dragonfly and solaris Skip it like on freebsd until there is proper a fix for #25809 Updates #25809 Change-Id: Id53c433aee75f2a992ab6a8d58d98fd1f8a6c1c6 Reviewed-on: https://go-review.googlesource.com/117698 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Alex Brainman --- src/net/sendfile_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index 3418d7f243..acf1cd9955 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -94,7 +94,8 @@ func TestSendfile(t *testing.T) { } func TestSendfileParts(t *testing.T) { - if runtime.GOOS == "freebsd" { + switch runtime.GOOS { + case "dragonfly", "freebsd", "solaris": t.Skipf("skipping on %s (see golang.org/issue/25809 for details)", runtime.GOOS) } From 7ba0c6235f9968eb453e759105366bcaa0903326 Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Thu, 24 May 2018 13:20:21 +0100 Subject: [PATCH 009/203] crypto, internal/cpu: fix s390x AES feature detection and update SHA implementations Hardware AES support in Go on s390x currently requires ECB, CBC and CTR modes be available. It also requires that either the GHASH or GCM facilities are available. The existing checks missed some of these constraints. While we're here simplify the cpu package on s390x, moving masking code out of assembly and into Go code. Also, update SHA-{1,256,512} implementations to use the cpu package since that is now trivial. Finally I also added a test for internal/cpu on s390x which loads /proc/cpuinfo and checks it against the flags set by internal/cpu. Updates #25822 for changes to vet whitelist. Change-Id: Iac4183f571643209e027f730989c60a811c928eb Reviewed-on: https://go-review.googlesource.com/114397 Run-TryBot: Michael Munday TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/vet/all/whitelist/s390x.txt | 7 ++ src/crypto/aes/cipher_s390x.go | 11 +- src/crypto/aes/gcm_s390x.go | 2 +- src/crypto/sha1/sha1block_s390x.go | 7 +- src/crypto/sha1/sha1block_s390x.s | 36 ++---- src/crypto/sha256/sha256block_s390x.go | 7 +- src/crypto/sha256/sha256block_s390x.s | 36 ++---- src/crypto/sha512/sha512block_s390x.go | 7 +- src/crypto/sha512/sha512block_s390x.s | 36 ++---- src/crypto/tls/common.go | 3 +- src/internal/cpu/cpu.go | 26 ++-- src/internal/cpu/cpu_no_init.go | 1 + src/internal/cpu/cpu_s390x.go | 157 +++++++++++++++++++++++-- src/internal/cpu/cpu_s390x.s | 124 ++++++------------- src/internal/cpu/cpu_s390x_test.go | 63 ++++++++++ 15 files changed, 319 insertions(+), 204 deletions(-) create mode 100644 src/internal/cpu/cpu_s390x_test.go diff --git a/src/cmd/vet/all/whitelist/s390x.txt b/src/cmd/vet/all/whitelist/s390x.txt index 9fa4949575..5bc48e5afc 100644 --- a/src/cmd/vet/all/whitelist/s390x.txt +++ b/src/cmd/vet/all/whitelist/s390x.txt @@ -5,3 +5,10 @@ runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration +internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); cpu.facilityList is 32-byte value +internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value +internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go index 93e3b929b9..82f6f8f335 100644 --- a/src/crypto/aes/cipher_s390x.go +++ b/src/crypto/aes/cipher_s390x.go @@ -31,12 +31,11 @@ type aesCipherAsm struct { func cryptBlocks(c code, key, dst, src *byte, length int) func newCipher(key []byte) (cipher.Block, error) { - // Strictly speaking, this check should be for HasKM. - // The check for HasKMC and HasKMCTR provides compatibility - // with the existing optimized s390x CBC and CTR implementations - // in this package, which already assert that they meet the - // cbcEncAble, cbcDecAble, and ctrAble interfaces - if !(cpu.S390X.HasKM && cpu.S390X.HasKMC && cpu.S390X.HasKMCTR) { + // The aesCipherAsm type implements the cbcEncAble, cbcDecAble, + // ctrAble and gcmAble interfaces. We therefore need to check + // for all the features required to implement these modes. + // Keep in sync with crypto/tls/common.go. + if !(cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)) { return newCipherGeneric(key) } diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go index acac6ec7b6..ca06ae52ac 100644 --- a/src/crypto/aes/gcm_s390x.go +++ b/src/crypto/aes/gcm_s390x.go @@ -85,7 +85,7 @@ func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { nonceSize: nonceSize, tagSize: tagSize, } - if cpu.S390X.HasKMA { + if cpu.S390X.HasAESGCM { g := gcmKMA{g} return &g, nil } diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go index 340704aee2..446bf5d36e 100644 --- a/src/crypto/sha1/sha1block_s390x.go +++ b/src/crypto/sha1/sha1block_s390x.go @@ -4,9 +4,6 @@ package sha1 -// featureCheck reports whether the CPU supports the -// SHA-1 compute intermediate message digest (KIMD) -// function code. -func featureCheck() bool +import "internal/cpu" -var useAsm = featureCheck() +var useAsm = cpu.S390X.HasSHA1 diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s index 3c71998645..6ba6883cc3 100644 --- a/src/crypto/sha1/sha1block_s390x.s +++ b/src/crypto/sha1/sha1block_s390x.s @@ -4,31 +4,17 @@ #include "textflag.h" -// func featureCheck() bool -TEXT ·featureCheck(SB),NOSPLIT,$16-1 - LA tmp-16(SP), R1 - XOR R0, R0 // query function code is 0 - WORD $0xB93E0006 // KIMD (R6 is ignored) - MOVBZ tmp-16(SP), R4 // get the first byte - AND $0x40, R4 // bit 1 (big endian) for SHA-1 - CMPBEQ R4, $0, nosha1 - MOVB $1, ret+0(FP) - RET -nosha1: - MOVB $0, ret+0(FP) +// func block(dig *digest, p []byte) +TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + MOVBZ $1, R0 // SHA-1 function code + CMPBEQ R4, $0, generic + +loop: + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted RET -// func block(dig *digest, p []byte) -TEXT ·block(SB),NOSPLIT,$0-32 - MOVBZ ·useAsm(SB), R4 - LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) - CMPBNE R4, $1, generic - MOVBZ $1, R0 // SHA-1 function code -loop: - WORD $0xB93E0002 // KIMD R2 - BVS loop // continue if interrupted -done: - XOR R0, R0 // restore R0 - RET generic: - BR ·blockGeneric(SB) + BR ·blockGeneric(SB) diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go index b7beefef0c..1a376c5f93 100644 --- a/src/crypto/sha256/sha256block_s390x.go +++ b/src/crypto/sha256/sha256block_s390x.go @@ -4,9 +4,6 @@ package sha256 -// featureCheck reports whether the CPU supports the -// SHA256 compute intermediate message digest (KIMD) -// function code. -func featureCheck() bool +import "internal/cpu" -var useAsm = featureCheck() +var useAsm = cpu.S390X.HasSHA256 diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s index ee35991f50..81b1b382c7 100644 --- a/src/crypto/sha256/sha256block_s390x.s +++ b/src/crypto/sha256/sha256block_s390x.s @@ -4,31 +4,17 @@ #include "textflag.h" -// func featureCheck() bool -TEXT ·featureCheck(SB),NOSPLIT,$16-1 - LA tmp-16(SP), R1 - XOR R0, R0 // query function code is 0 - WORD $0xB93E0006 // KIMD (R6 is ignored) - MOVBZ tmp-16(SP), R4 // get the first byte - AND $0x20, R4 // bit 2 (big endian) for SHA256 - CMPBEQ R4, $0, nosha256 - MOVB $1, ret+0(FP) - RET -nosha256: - MOVB $0, ret+0(FP) +// func block(dig *digest, p []byte) +TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + MOVBZ $2, R0 // SHA-256 function code + CMPBEQ R4, $0, generic + +loop: + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted RET -// func block(dig *digest, p []byte) -TEXT ·block(SB),NOSPLIT,$0-32 - MOVBZ ·useAsm(SB), R4 - LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) - CMPBNE R4, $1, generic - MOVBZ $2, R0 // SHA256 function code -loop: - WORD $0xB93E0002 // KIMD R2 - BVS loop // continue if interrupted -done: - XOR R0, R0 // restore R0 - RET generic: - BR ·blockGeneric(SB) + BR ·blockGeneric(SB) diff --git a/src/crypto/sha512/sha512block_s390x.go b/src/crypto/sha512/sha512block_s390x.go index f05dc18e12..7df29fd298 100644 --- a/src/crypto/sha512/sha512block_s390x.go +++ b/src/crypto/sha512/sha512block_s390x.go @@ -4,9 +4,6 @@ package sha512 -// featureCheck reports whether the CPU supports the -// SHA512 compute intermediate message digest (KIMD) -// function code. -func featureCheck() bool +import "internal/cpu" -var useAsm = featureCheck() +var useAsm = cpu.S390X.HasSHA512 diff --git a/src/crypto/sha512/sha512block_s390x.s b/src/crypto/sha512/sha512block_s390x.s index aab81e2bcf..f221bd1399 100644 --- a/src/crypto/sha512/sha512block_s390x.s +++ b/src/crypto/sha512/sha512block_s390x.s @@ -4,31 +4,17 @@ #include "textflag.h" -// func featureCheck() bool -TEXT ·featureCheck(SB),NOSPLIT,$16-1 - LA tmp-16(SP), R1 - XOR R0, R0 // query function code is 0 - WORD $0xB93E0006 // KIMD (R6 is ignored) - MOVBZ tmp-16(SP), R4 // get the first byte - AND $0x10, R4 // bit 3 (big endian) for SHA512 - CMPBEQ R4, $0, nosha512 - MOVB $1, ret+0(FP) - RET -nosha512: - MOVB $0, ret+0(FP) +// func block(dig *digest, p []byte) +TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32 + MOVBZ ·useAsm(SB), R4 + LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) + MOVBZ $3, R0 // SHA-512 function code + CMPBEQ R4, $0, generic + +loop: + WORD $0xB93E0002 // KIMD R2 + BVS loop // continue if interrupted RET -// func block(dig *digest, p []byte) -TEXT ·block(SB),NOSPLIT,$0-32 - MOVBZ ·useAsm(SB), R4 - LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p) - CMPBNE R4, $1, generic - MOVBZ $3, R0 // SHA512 function code -loop: - WORD $0xB93E0002 // KIMD R2 - BVS loop // continue if interrupted -done: - XOR R0, R0 // restore R0 - RET generic: - BR ·blockGeneric(SB) + BR ·blockGeneric(SB) diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 423787b415..14996e6835 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -930,7 +930,8 @@ func initDefaultCipherSuites() { hasGCMAsmARM64 := false // hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL - hasGCMAsmS390X := cpu.S390X.HasKM && (cpu.S390X.HasKMA || (cpu.S390X.HasKMCTR && cpu.S390X.HasKIMD)) + // Keep in sync with crypto/aes/cipher_s390x.go. + hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index b1a8d9bf63..2569024245 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -98,14 +98,24 @@ type arm64 struct { var S390X s390x type s390x struct { - _ [CacheLineSize]byte - HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. - HasKM bool // cipher message (KM) - HasKMA bool // cipher message assist (KMA) - HasKMC bool // cipher message with chaining (KMC) - HasKMCTR bool // cipher message with counter (KMCTR) - HasKIMD bool // compute intermediate message digest (KIMD) - _ [CacheLineSize]byte + _ [CacheLineSize]byte + HasZArch bool // z architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended [mandatory] + HasLDisp bool // long (20-bit) displacements [mandatory] + HasEImm bool // 32-bit immediates [mandatory] + HasDFP bool // decimal floating point + HasETF3Enhanced bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. + _ [CacheLineSize]byte } // initialize examines the processor and sets the relevant variables above. diff --git a/src/internal/cpu/cpu_no_init.go b/src/internal/cpu/cpu_no_init.go index 010cbcdb5e..1be4f29ddd 100644 --- a/src/internal/cpu/cpu_no_init.go +++ b/src/internal/cpu/cpu_no_init.go @@ -8,6 +8,7 @@ // +build !arm64 // +build !ppc64 // +build !ppc64le +// +build !s390x package cpu diff --git a/src/internal/cpu/cpu_s390x.go b/src/internal/cpu/cpu_s390x.go index 7b78289467..389a058c32 100644 --- a/src/internal/cpu/cpu_s390x.go +++ b/src/internal/cpu/cpu_s390x.go @@ -6,17 +6,148 @@ package cpu const CacheLineSize = 256 -// the following cpu feature detection functions are defined in cpu_s390x.s -func hasKM() bool -func hasKMC() bool -func hasKMCTR() bool -func hasKMA() bool -func hasKIMD() bool - -func init() { - S390X.HasKM = hasKM() - S390X.HasKMC = hasKMC() - S390X.HasKMCTR = hasKMCTR() - S390X.HasKMA = hasKMA() - S390X.HasKIMD = hasKIMD() +// bitIsSet reports whether the bit at index is set. The bit index +// is in big endian order, so bit index 0 is the leftmost bit. +func bitIsSet(bits []uint64, index uint) bool { + return bits[index/64]&((1<<63)>>(index%64)) != 0 +} + +// function is the function code for the named function. +type function uint8 + +const ( + // KM{,A,C,CTR} function codes + aes128 function = 18 // AES-128 + aes192 = 19 // AES-192 + aes256 = 20 // AES-256 + + // K{I,L}MD function codes + sha1 = 1 // SHA-1 + sha256 = 2 // SHA-256 + sha512 = 3 // SHA-512 + + // KLMD function codes + ghash = 65 // GHASH +) + +// queryResult contains the result of a Query function +// call. Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type queryResult struct { + bits [2]uint64 +} + +// Has reports whether the given functions are present. +func (q *queryResult) Has(fns ...function) bool { + if len(fns) == 0 { + panic("no function codes provided") + } + for _, f := range fns { + if !bitIsSet(q.bits[:], uint(f)) { + return false + } + } + return true +} + +// facility is a bit index for the named facility. +type facility uint8 + +const ( + // mandatory facilities + zarch facility = 1 // z architecture mode is active + stflef = 7 // store-facility-list-extended + ldisp = 18 // long-displacement + eimm = 21 // extended-immediate + + // miscellaneous facilities + dfp = 42 // decimal-floating-point + etf3eh = 30 // extended-translation 3 enhancement + + // cryptography facilities + msa = 17 // message-security-assist + msa3 = 76 // message-security-assist extension 3 + msa4 = 77 // message-security-assist extension 4 + msa5 = 57 // message-security-assist extension 5 + msa8 = 146 // message-security-assist extension 8 + + // Note: vx and highgprs are excluded because they require + // kernel support and so must be fetched from HWCAP. +) + +// facilityList contains the result of an STFLE call. +// Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type facilityList struct { + bits [4]uint64 +} + +// Has reports whether the given facilities are present. +func (s *facilityList) Has(fs ...facility) bool { + if len(fs) == 0 { + panic("no facility bits provided") + } + for _, f := range fs { + if !bitIsSet(s.bits[:], uint(f)) { + return false + } + } + return true +} + +// The following feature detection functions are defined in cpu_s390x.s. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList +func kmQuery() queryResult +func kmcQuery() queryResult +func kmctrQuery() queryResult +func kmaQuery() queryResult +func kimdQuery() queryResult +func klmdQuery() queryResult + +func doinit() { + options = []option{ + {"zarch", &S390X.HasZArch}, + {"stfle", &S390X.HasSTFLE}, + {"ldisp", &S390X.HasLDisp}, + {"msa", &S390X.HasMSA}, + {"eimm", &S390X.HasEImm}, + {"dfp", &S390X.HasDFP}, + {"etf3eh", &S390X.HasETF3Enhanced}, + {"vx", &S390X.HasVX}, + } + + aes := []function{aes128, aes192, aes256} + facilities := stfle() + + S390X.HasZArch = facilities.Has(zarch) + S390X.HasSTFLE = facilities.Has(stflef) + S390X.HasLDisp = facilities.Has(ldisp) + S390X.HasEImm = facilities.Has(eimm) + S390X.HasDFP = facilities.Has(dfp) + S390X.HasETF3Enhanced = facilities.Has(etf3eh) + S390X.HasMSA = facilities.Has(msa) + + if S390X.HasMSA { + // cipher message + km, kmc := kmQuery(), kmcQuery() + S390X.HasAES = km.Has(aes...) + S390X.HasAESCBC = kmc.Has(aes...) + if facilities.Has(msa4) { + kmctr := kmctrQuery() + S390X.HasAESCTR = kmctr.Has(aes...) + } + if facilities.Has(msa8) { + kma := kmaQuery() + S390X.HasAESGCM = kma.Has(aes...) + } + + // compute message digest + kimd := kimdQuery() // intermediate (no padding) + klmd := klmdQuery() // last (padding) + S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) + S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) + S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) + S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist + } } diff --git a/src/internal/cpu/cpu_s390x.s b/src/internal/cpu/cpu_s390x.s index 04edb2ed0f..9678035ffb 100644 --- a/src/internal/cpu/cpu_s390x.s +++ b/src/internal/cpu/cpu_s390x.s @@ -4,98 +4,52 @@ #include "textflag.h" -// func hasKM() bool -TEXT ·hasKM(SB),NOSPLIT,$16-1 - XOR R0, R0 // set function code to 0 (query) - LA mask-16(SP), R1 // 16-byte stack variable for mask - MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian) - - // check for KM AES functions - WORD $0xB92E0024 // cipher message (KM) - MOVD mask-16(SP), R2 - AND R3, R2 - CMPBNE R2, R3, notfound - - MOVB $1, ret+0(FP) - RET -notfound: - MOVB $0, ret+0(FP) +// func stfle() facilityList +TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 + MOVD $ret+0(FP), R1 + MOVD $3, R0 // last doubleword index to store + XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) + WORD $0xb2b01000 // store facility list extended (STFLE) RET -// func hasKMC() bool -TEXT ·hasKMC(SB),NOSPLIT,$16-1 - XOR R0, R0 // set function code to 0 (query) - LA mask-16(SP), R1 // 16-byte stack variable for mask - MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian) - - // check for KMC AES functions - WORD $0xB92F0024 // cipher message with chaining (KMC) - MOVD mask-16(SP), R2 - AND R3, R2 - CMPBNE R2, R3, notfound - - MOVB $1, ret+0(FP) - RET -notfound: - MOVB $0, ret+0(FP) +// func kmQuery() queryResult +TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KM-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92E0024 // cipher message (KM) RET -// func hasKMCTR() bool -TEXT ·hasKMCTR(SB),NOSPLIT,$16-1 - XOR R0, R0 // set function code to 0 (query) - LA mask-16(SP), R1 // 16-byte stack variable for mask - MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian) - - // check for KMCTR AES functions - WORD $0xB92D4024 // cipher message with counter (KMCTR) - MOVD mask-16(SP), R2 - AND R3, R2 - CMPBNE R2, R3, notfound - - MOVB $1, ret+0(FP) - RET -notfound: - MOVB $0, ret+0(FP) +// func kmcQuery() queryResult +TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMC-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92F0024 // cipher message with chaining (KMC) RET -// func hasKMA() bool -TEXT ·hasKMA(SB),NOSPLIT,$24-1 - MOVD $tmp-24(SP), R1 - MOVD $2, R0 // store 24-bytes - XC $24, (R1), (R1) - WORD $0xb2b01000 // STFLE (R1) - MOVWZ 16(R1), R2 - ANDW $(1<<13), R2 // test bit 146 (message-security-assist 8) - BEQ no - - MOVD $0, R0 // KMA-Query - XC $16, (R1), (R1) - WORD $0xb9296024 // kma %r6,%r2,%r4 - MOVWZ (R1), R2 - WORD $0xa7213800 // TMLL R2, $0x3800 - BVS yes -no: - MOVB $0, ret+0(FP) - RET -yes: - MOVB $1, ret+0(FP) +// func kmctrQuery() queryResult +TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMCTR-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB92D4024 // cipher message with counter (KMCTR) RET -// func hasKIMD() bool -TEXT ·hasKIMD(SB),NOSPLIT,$16-1 - XOR R0, R0 // set function code to 0 (query) - LA mask-16(SP), R1 // 16-byte stack variable for mask - MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian) - - // check for KIMD GHASH function - WORD $0xB93E0024 // compute intermediate message digest (KIMD) - MOVD mask-8(SP), R2 // bits 64-127 - MOVD $(1<<62), R5 - AND R5, R2 - CMPBNE R2, R5, notfound - - MOVB $1, ret+0(FP) +// func kmaQuery() queryResult +TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KMA-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xb9296024 // cipher message with authentication (KMA) RET -notfound: - MOVB $0, ret+0(FP) + +// func kimdQuery() queryResult +TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KIMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93E0024 // compute intermediate message digest (KIMD) + RET + +// func klmdQuery() queryResult +TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 + MOVD $0, R0 // set function code to 0 (KLMD-Query) + MOVD $ret+0(FP), R1 // address of 16-byte return value + WORD $0xB93F0024 // compute last message digest (KLMD) RET diff --git a/src/internal/cpu/cpu_s390x_test.go b/src/internal/cpu/cpu_s390x_test.go new file mode 100644 index 0000000000..d910bbe695 --- /dev/null +++ b/src/internal/cpu/cpu_s390x_test.go @@ -0,0 +1,63 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cpu_test + +import ( + "errors" + . "internal/cpu" + "io/ioutil" + "regexp" + "testing" +) + +func getFeatureList() ([]string, error) { + cpuinfo, err := ioutil.ReadFile("/proc/cpuinfo") + if err != nil { + return nil, err + } + r := regexp.MustCompile("features\\s*:\\s*(.*)") + b := r.FindSubmatch(cpuinfo) + if len(b) < 2 { + return nil, errors.New("no feature list in /proc/cpuinfo") + } + return regexp.MustCompile("\\s+").Split(string(b[1]), -1), nil +} + +func TestS390XAgainstCPUInfo(t *testing.T) { + // mapping of linux feature strings to S390X fields + mapping := make(map[string]*bool) + for _, option := range Options { + mapping[option.Name] = option.Feature + } + + // these must be true on the machines Go supports + mandatory := make(map[string]bool) + mandatory["zarch"] = false + mandatory["eimm"] = false + mandatory["ldisp"] = false + mandatory["stfle"] = false + + features, err := getFeatureList() + if err != nil { + t.Error(err) + } + for _, feature := range features { + if _, ok := mandatory[feature]; ok { + mandatory[feature] = true + } + if flag, ok := mapping[feature]; ok { + if !*flag { + t.Errorf("feature '%v' not detected", feature) + } + } else { + t.Logf("no entry for '%v'", feature) + } + } + for k, v := range mandatory { + if !v { + t.Errorf("mandatory feature '%v' not detected", k) + } + } +} From 30a63ecee351c029ea99dce388a5953a150b4e02 Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Fri, 8 Jun 2018 11:07:18 -0400 Subject: [PATCH 010/203] runtime: restore r2 when restoring state from gobuf in gogo on ppc64x When using plugins with goroutines calling cgo, we hit a case where an intermittent SIGSEGV occurs when referencing an address that is based on r2 (TOC address). When the failure can be generated in gdb, the contents of r2 is wrong even though the value in the current stack's slot for r2 is correct. So that means it somehow switched to start running the code in this function without passing through the beginning of the function which had the correct value of r2 and stored it there. It was noted that in runtime.gogo when the state is restored from gobuf, r2 is not restored from its slot on the stack. Adding the instruction to restore r2 prevents the SIGSEGV. This adds a testcase under testplugin which reproduces the problem if the program is run multiple times. The team who reported this problem has verified it fixes the issue on their larger, more complex application. Fixes #25756 Change-Id: I6028b6f1f8775d5c23f4ebb57ae273330a28eb8f Reviewed-on: https://go-review.googlesource.com/117515 Run-TryBot: Lynn Boger Reviewed-by: Ian Lance Taylor TryBot-Result: Gobot Gobot --- misc/cgo/testplugin/src/issue25756/main.go | 52 +++++++++++++++++ .../testplugin/src/issue25756/plugin/c-life.c | 56 +++++++++++++++++++ .../testplugin/src/issue25756/plugin/life.go | 39 +++++++++++++ .../testplugin/src/issue25756/plugin/life.h | 7 +++ misc/cgo/testplugin/test.bash | 11 +++- src/runtime/asm_ppc64x.s | 1 + 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 misc/cgo/testplugin/src/issue25756/main.go create mode 100644 misc/cgo/testplugin/src/issue25756/plugin/c-life.c create mode 100644 misc/cgo/testplugin/src/issue25756/plugin/life.go create mode 100644 misc/cgo/testplugin/src/issue25756/plugin/life.h diff --git a/misc/cgo/testplugin/src/issue25756/main.go b/misc/cgo/testplugin/src/issue25756/main.go new file mode 100644 index 0000000000..817daf42f6 --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/main.go @@ -0,0 +1,52 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Run the game of life in C using Go for parallelization. + +package main + +import ( + "flag" + "fmt" + "plugin" +) + +const MAXDIM = 100 + +var dim = flag.Int("dim", 16, "board dimensions") +var gen = flag.Int("gen", 10, "generations") + +func main() { + flag.Parse() + + var a [MAXDIM * MAXDIM]int32 + for i := 2; i < *dim; i += 8 { + for j := 2; j < *dim-3; j += 8 { + for y := 0; y < 3; y++ { + a[i**dim+j+y] = 1 + } + } + } + + p, err := plugin.Open("life.so") + if err != nil { + panic(err) + } + f, err := p.Lookup("Run") + if err != nil { + panic(err) + } + f.(func(int, int, int, []int32))(*gen, *dim, *dim, a[:]) + + for i := 0; i < *dim; i++ { + for j := 0; j < *dim; j++ { + if a[i**dim+j] == 0 { + fmt.Print(" ") + } else { + fmt.Print("X") + } + } + fmt.Print("\n") + } +} diff --git a/misc/cgo/testplugin/src/issue25756/plugin/c-life.c b/misc/cgo/testplugin/src/issue25756/plugin/c-life.c new file mode 100644 index 0000000000..f853163e2f --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/plugin/c-life.c @@ -0,0 +1,56 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include +#include "life.h" +#include "_cgo_export.h" + +const int MYCONST = 0; + +// Do the actual manipulation of the life board in C. This could be +// done easily in Go, we are just using C for demonstration +// purposes. +void +Step(int x, int y, int *a, int *n) +{ + struct GoStart_return r; + + // Use Go to start 4 goroutines each of which handles 1/4 of the + // board. + r = GoStart(0, x, y, 0, x / 2, 0, y / 2, a, n); + assert(r.r0 == 0 && r.r1 == 100); // test multiple returns + r = GoStart(1, x, y, x / 2, x, 0, y / 2, a, n); + assert(r.r0 == 1 && r.r1 == 101); // test multiple returns + GoStart(2, x, y, 0, x / 2, y / 2, y, a, n); + GoStart(3, x, y, x / 2, x, y / 2, y, a, n); + GoWait(0); + GoWait(1); + GoWait(2); + GoWait(3); +} + +// The actual computation. This is called in parallel. +void +DoStep(int xdim, int ydim, int xstart, int xend, int ystart, int yend, int *a, int *n) +{ + int x, y, c, i, j; + + for(x = xstart; x < xend; x++) { + for(y = ystart; y < yend; y++) { + c = 0; + for(i = -1; i <= 1; i++) { + for(j = -1; j <= 1; j++) { + if(x+i >= 0 && x+i < xdim && + y+j >= 0 && y+j < ydim && + (i != 0 || j != 0)) + c += a[(x+i)*xdim + (y+j)] != 0; + } + } + if(c == 3 || (c == 2 && a[x*xdim + y] != 0)) + n[x*xdim + y] = 1; + else + n[x*xdim + y] = 0; + } + } +} diff --git a/misc/cgo/testplugin/src/issue25756/plugin/life.go b/misc/cgo/testplugin/src/issue25756/plugin/life.go new file mode 100644 index 0000000000..675a192fc1 --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/plugin/life.go @@ -0,0 +1,39 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// #include "life.h" +import "C" + +import "unsafe" + +func Run(gen, x, y int, a []int32) { + n := make([]int32, x*y) + for i := 0; i < gen; i++ { + C.Step(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&a[0])), (*C.int)(unsafe.Pointer(&n[0]))) + copy(a, n) + } +} + +// Keep the channels visible from Go. +var chans [4]chan bool + +//export GoStart +// Double return value is just for testing. +func GoStart(i, xdim, ydim, xstart, xend, ystart, yend C.int, a *C.int, n *C.int) (int, int) { + c := make(chan bool, int(C.MYCONST)) + go func() { + C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n) + c <- true + }() + chans[i] = c + return int(i), int(i + 100) +} + +//export GoWait +func GoWait(i C.int) { + <-chans[i] + chans[i] = nil +} diff --git a/misc/cgo/testplugin/src/issue25756/plugin/life.h b/misc/cgo/testplugin/src/issue25756/plugin/life.h new file mode 100644 index 0000000000..11d2b97226 --- /dev/null +++ b/misc/cgo/testplugin/src/issue25756/plugin/life.h @@ -0,0 +1,7 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +extern void Step(int, int, int *, int *); +extern void DoStep(int, int, int, int, int, int, int *, int *); +extern const int MYCONST; diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash index df38204a4e..bf8ed3cd19 100755 --- a/misc/cgo/testplugin/test.bash +++ b/misc/cgo/testplugin/test.bash @@ -15,7 +15,7 @@ goos=$(go env GOOS) goarch=$(go env GOARCH) function cleanup() { - rm -f plugin*.so unnamed*.so iface*.so issue* + rm -f plugin*.so unnamed*.so iface*.so life.so issue* rm -rf host pkg sub iface } trap cleanup EXIT @@ -90,3 +90,12 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/m GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go ./issue24351 + +# Test for issue 25756 +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o life.so issue25756/plugin +GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue25756 src/issue25756/main.go +# Fails intermittently, but 20 runs should cause the failure +for i in `seq 1 20`; +do + ./issue25756 > /dev/null +done diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 93f9110cc0..3708961d76 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -139,6 +139,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $16-8 MOVD 0(g), R4 MOVD gobuf_sp(R5), R1 MOVD gobuf_lr(R5), R31 + MOVD 24(R1), R2 // restore R2 MOVD R31, LR MOVD gobuf_ret(R5), R3 MOVD gobuf_ctxt(R5), R11 From bb222cde10f8a1fc4033f91399f830bd4a4bcb50 Mon Sep 17 00:00:00 2001 From: Alberto Donizetti Date: Mon, 11 Jun 2018 11:56:45 +0200 Subject: [PATCH 011/203] lib/time: update vendored tzdata to release 2018e It has been a long time since the last time the vendored zoneinfo in lib/time was updated, and we're well into the freeze. Update it to the lastest release from IANA. Updates #22487 Change-Id: Ib9a8eb409554848285fc88363dbb04ed9d6d9eb0 Reviewed-on: https://go-review.googlesource.com/117855 Reviewed-by: Brad Fitzpatrick --- lib/time/update.bash | 4 ++-- lib/time/zoneinfo.zip | Bin 364985 -> 365101 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/time/update.bash b/lib/time/update.bash index 26ad79d52d..629e74fce8 100755 --- a/lib/time/update.bash +++ b/lib/time/update.bash @@ -8,8 +8,8 @@ # Consult https://www.iana.org/time-zones for the latest versions. # Versions to use. -CODE=2017c -DATA=2017c +CODE=2018e +DATA=2018e set -e rm -rf work diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip index 0703e08e36e5250ef40c98fd327fd2d1333f7b05..08dca214181a8488412a66176752d9acd78a367e 100644 GIT binary patch delta 72702 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 VbvFq4*$npaVU?=&5vasd{V!a#H*)|0 delta 72251 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 Date: Sun, 10 Jun 2018 10:26:40 +0300 Subject: [PATCH 012/203] cmd/compile: add doc comment to the parseFiles function Change-Id: Ifa14557ba834865602c207297ccf0c63e93feb4c Reviewed-on: https://go-review.googlesource.com/117695 Run-TryBot: Yury Smolsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/noder.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index ec1654b83f..8a42fcefd1 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -19,6 +19,10 @@ import ( "cmd/internal/src" ) +// parseFiles concurrently parses files into *syntax.File structures. +// Each declaration in every *syntax.File is converted to a syntax tree +// and its root represented by *Node is appended to xtop. +// Returns the total count of parsed lines. func parseFiles(filenames []string) uint { var noders []*noder // Limit the number of simultaneously open files. From 1de0dcfc7b50a2e74e572374d3bbbf3d12d7ff4f Mon Sep 17 00:00:00 2001 From: Yury Smolsky Date: Sun, 10 Jun 2018 12:27:47 +0300 Subject: [PATCH 013/203] cmd/compile: fix wording in README "Syntax analysis" sounds more familiar and fits the item before, which says "lexical analysis". If there was specific intention to the original wording, I, as a reader, would like to see it instead of this confusing wording. Change-Id: Id32dbf75300a86b21cb9f35e54526184fe5df6cb Reviewed-on: https://go-review.googlesource.com/117696 Reviewed-by: Robert Griesemer --- src/cmd/compile/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/compile/README.md b/src/cmd/compile/README.md index c8369c7c8c..b78786e5f2 100644 --- a/src/cmd/compile/README.md +++ b/src/cmd/compile/README.md @@ -26,7 +26,7 @@ little to do with uppercase GC, which stands for garbage collection. * `cmd/compile/internal/syntax` (lexer, parser, syntax tree) In the first phase of compilation, source code is tokenized (lexical analysis), -parsed (syntactic analyses), and a syntax tree is constructed for each source +parsed (syntax analysis), and a syntax tree is constructed for each source file. Each syntax tree is an exact representation of the respective source file, with From 9e9ff565cdef4ef4db2955f0e96c9e83d452b4af Mon Sep 17 00:00:00 2001 From: Lynn Boger Date: Thu, 29 Mar 2018 11:15:18 -0400 Subject: [PATCH 014/203] runtime/race: implement race detector for ppc64le This adds the support to enable the race detector for ppc64le. Added runtime/race_ppc64le.s to manage the calls from Go to the LLVM tsan functions, mostly converting from the Go ABI to the PPC64 ABI expected by Clang generated code. Changed racewalk.go to call racefuncenterfp instead of racefuncenter on ppc64le to allow the caller pc to be obtained in the asm code before calling the tsan version. Changed the set up code for racecallbackthunk so it doesn't use the autogenerated save and restore of the link register since that sequence uses registers inconsistent with the normal ppc64 ABI. Made various changes to recognize that race is supported for ppc64le. Ensured that tls_g is updated and accessible from race_linux_ppc64le.s so that the race ctx can be obtained and passed to tsan functions. This enables the race tests for ppc64le in cmd/dist/test.go and increases the timeout when running the benchmarks with the -race option to avoid timing out. Updates #24354, #23731 Change-Id: Ib97dc7ac313e6313c836dc7d2fb698f9d8fba3ef Reviewed-on: https://go-review.googlesource.com/107935 Run-TryBot: Lynn Boger TryBot-Result: Gobot Gobot Reviewed-by: Bryan C. Mills Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/builtin.go | 1 + .../compile/internal/gc/builtin/runtime.go | 1 + src/cmd/compile/internal/gc/racewalk.go | 27 +- src/cmd/dist/test.go | 6 +- src/cmd/go/internal/work/init.go | 13 +- src/cmd/internal/obj/ppc64/obj9.go | 16 +- src/cmd/link/internal/ld/config.go | 7 + src/race.bash | 4 +- src/runtime/asm_ppc64x.s | 1 + src/runtime/race.go | 1 + src/runtime/race/race.go | 2 +- src/runtime/race_ppc64le.s | 568 ++++++++++++++++++ src/runtime/tls_ppc64x.s | 2 +- 13 files changed, 622 insertions(+), 27 deletions(-) create mode 100644 src/runtime/race_ppc64le.s diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go index 6b416c8a5c..ec8f1093b6 100644 --- a/src/cmd/compile/internal/gc/builtin.go +++ b/src/cmd/compile/internal/gc/builtin.go @@ -141,6 +141,7 @@ var runtimeDecls = [...]struct { {"uint32tofloat64", funcTag, 109}, {"complex128div", funcTag, 110}, {"racefuncenter", funcTag, 111}, + {"racefuncenterfp", funcTag, 5}, {"racefuncexit", funcTag, 5}, {"raceread", funcTag, 111}, {"racewrite", funcTag, 111}, diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go index d459c07cbe..140b7f3b2d 100644 --- a/src/cmd/compile/internal/gc/builtin/runtime.go +++ b/src/cmd/compile/internal/gc/builtin/runtime.go @@ -183,6 +183,7 @@ func complex128div(num complex128, den complex128) (quo complex128) // race detection func racefuncenter(uintptr) +func racefuncenterfp() func racefuncexit() func raceread(uintptr) func racewrite(uintptr) diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index 8ae080ab40..df0e5f4059 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -7,6 +7,7 @@ package gc import ( "cmd/compile/internal/types" "cmd/internal/src" + "cmd/internal/sys" ) // The racewalk pass is currently handled in two parts. @@ -58,17 +59,23 @@ func instrument(fn *Node) { lno := lineno lineno = src.NoXPos - // nodpc is the PC of the caller as extracted by - // getcallerpc. We use -widthptr(FP) for x86. - // BUG: this will not work on arm. - nodpc := nodfp.copy() - nodpc.Type = types.Types[TUINTPTR] - nodpc.Xoffset = int64(-Widthptr) - fn.Func.Dcl = append(fn.Func.Dcl, nodpc) - - fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc)) - fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil)) + if thearch.LinkArch.Arch == sys.ArchPPC64LE { + fn.Func.Enter.Prepend(mkcall("racefuncenterfp", nil, nil)) + fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil)) + } else { + // nodpc is the PC of the caller as extracted by + // getcallerpc. We use -widthptr(FP) for x86. + // BUG: This only works for amd64. This will not + // work on arm or others that might support + // race in the future. + nodpc := nodfp.copy() + nodpc.Type = types.Types[TUINTPTR] + nodpc.Xoffset = int64(-Widthptr) + fn.Func.Dcl = append(fn.Func.Dcl, nodpc) + fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc)) + fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil)) + } lineno = lno } } diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index a1c470cc97..ac43701d88 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -312,7 +312,6 @@ func (t *tester) registerStdTest(pkg string) { break } } - args := []string{ "test", short(), @@ -355,7 +354,8 @@ func (t *tester) registerRaceBenchTest(pkg string) { "test", short(), "-race", - "-run=^$", // nothing. only benchmarks. + t.timeout(1200), // longer timeout for race with benchmarks + "-run=^$", // nothing. only benchmarks. "-benchtime=.1s", "-cpu=4", } @@ -1318,7 +1318,7 @@ func (t *tester) raceDetectorSupported() bool { case "linux", "darwin", "freebsd", "windows": // The race detector doesn't work on Alpine Linux: // golang.org/issue/14481 - return t.cgoEnabled && goarch == "amd64" && gohostos == goos && !isAlpineLinux() + return t.cgoEnabled && (goarch == "amd64" || goarch == "ppc64le") && gohostos == goos && !isAlpineLinux() } return false } diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go index 4d3c5cbd17..1081e5147e 100644 --- a/src/cmd/go/internal/work/init.go +++ b/src/cmd/go/internal/work/init.go @@ -43,11 +43,16 @@ func instrumentInit() { fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) os.Exit(2) } - if cfg.BuildRace && (cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows") { - fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) - os.Exit(2) + if cfg.BuildRace { + platform := cfg.Goos + "/" + cfg.Goarch + switch platform { + default: + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + os.Exit(2) + case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "darwin/amd64", "windows/amd64": + // race supported on these platforms + } } - mode := "race" if cfg.BuildMSan { mode = "msan" diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go index 7bb21ab439..f42d675805 100644 --- a/src/cmd/internal/obj/ppc64/obj9.go +++ b/src/cmd/internal/obj/ppc64/obj9.go @@ -502,7 +502,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q = c.stacksplit(q, autosize) // emit split check } - if autosize != 0 { + // Special handling of the racecall thunk. Assume that its asm code will + // save the link register and update the stack, since that code is + // called directly from C/C++ and can't clobber REGTMP (R31). + if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" { // Save the link register and update the SP. MOVDU is used unless // the frame size is too large. The link register must be saved // even for non-empty leaf functions so that traceback works. @@ -678,7 +681,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { retTarget := p.To.Sym if c.cursym.Func.Text.Mark&LEAF != 0 { - if autosize == 0 { + if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" { p.As = ABR p.From = obj.Addr{} if retTarget == nil { @@ -747,8 +750,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.Link = q p = q } - - if autosize != 0 { + prev := p + if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" { q = c.newprog() q.As = AADD q.Pos = p.Pos @@ -759,7 +762,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q.Spadj = -autosize q.Link = p.Link - p.Link = q + prev.Link = q + prev = q } q1 = c.newprog() @@ -776,7 +780,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q1.Spadj = +autosize q1.Link = q.Link - q.Link = q1 + prev.Link = q1 case AADD: if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { p.Spadj = int32(-p.From.Offset) diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 6685ad50ac..18fbea62ee 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -196,6 +196,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { return true, objabi.GOARCH + " does not support internal cgo" } + // When the race flag is set, the LLVM tsan relocatable file is linked + // into the final binary, which means external linking is required because + // internal linking does not support it. + if *flagRace && ctxt.Arch.InFamily(sys.PPC64) { + return true, "race on ppc64le" + } + // Some build modes require work the internal linker cannot do (yet). switch ctxt.BuildMode { case BuildModeCArchive: diff --git a/src/race.bash b/src/race.bash index cafd834777..73cb1e583b 100755 --- a/src/race.bash +++ b/src/race.bash @@ -9,7 +9,7 @@ set -e function usage { - echo 'race detector is only supported on linux/amd64, freebsd/amd64 and darwin/amd64' 1>&2 + echo 'race detector is only supported on linux/amd64, linux/ppc64le, freebsd/amd64 and darwin/amd64' 1>&2 exit 1 } @@ -21,7 +21,7 @@ case $(uname) in fi ;; "Linux") - if [ $(uname -m) != "x86_64" ]; then + if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ]; then usage fi ;; diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index 3708961d76..b6a797640d 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -24,6 +24,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0 // create istack out of the given (operating system) stack. // _cgo_init may update stackguard. MOVD $runtime·g0(SB), g + BL runtime·save_g(SB) MOVD $(-64*1024), R31 ADD R31, R1, R3 MOVD R3, g_stackguard0(g) diff --git a/src/runtime/race.go b/src/runtime/race.go index 09a8356770..0124e231fa 100644 --- a/src/runtime/race.go +++ b/src/runtime/race.go @@ -292,6 +292,7 @@ var racearenastart uintptr var racearenaend uintptr func racefuncenter(uintptr) +func racefuncenterfp() func racefuncexit() func racereadrangepc1(uintptr, uintptr, uintptr) func racewriterangepc1(uintptr, uintptr, uintptr) diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go index 15e20112a8..f702c7a5d4 100644 --- a/src/runtime/race/race.go +++ b/src/runtime/race/race.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build race,linux,amd64 race,freebsd,amd64 race,darwin,amd64 race,windows,amd64 +// +build race,linux,amd64 race,freebsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le package race diff --git a/src/runtime/race_ppc64le.s b/src/runtime/race_ppc64le.s new file mode 100644 index 0000000000..5c723e0f51 --- /dev/null +++ b/src/runtime/race_ppc64le.s @@ -0,0 +1,568 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build race + +#include "go_asm.h" +#include "go_tls.h" +#include "funcdata.h" +#include "textflag.h" + +// The following functions allow calling the clang-compiled race runtime directly +// from Go code without going all the way through cgo. +// First, it's much faster (up to 50% speedup for real Go programs). +// Second, it eliminates race-related special cases from cgocall and scheduler. +// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go. + +// A brief recap of the ppc64le calling convention. +// Arguments are passed in R3, R4, R5 ... +// SP must be 16-byte aligned. + +// Note that for ppc64x, LLVM follows the standard ABI and +// expects arguments in registers, so these functions move +// the arguments from storage to the registers expected +// by the ABI. + +// When calling from Go to Clang tsan code: +// R3 is the 1st argument and is usually the ThreadState* +// R4-? are the 2nd, 3rd, 4th, etc. arguments + +// When calling racecalladdr: +// R8 is the call target address + +// The race ctx is passed in R3 and loaded in +// racecalladdr. +// +// The sequence used to get the race ctx: +// MOVD runtime·tls_g(SB), R10 // offset to TLS +// MOVD 0(R13)(R10*1), g // R13=TLS for this thread, g = R30 +// MOVD g_racectx(g), R3 // racectx == ThreadState + +// func runtime·RaceRead(addr uintptr) +// Called from instrumented Go code +TEXT runtime·raceread(SB), NOSPLIT, $0-8 + MOVD addr+0(FP), R4 + MOVD LR, R5 // caller of this? + // void __tsan_read(ThreadState *thr, void *addr, void *pc); + MOVD $__tsan_read(SB), R8 + BR racecalladdr<>(SB) + +TEXT runtime·RaceRead(SB), NOSPLIT, $0-8 + BR runtime·raceread(SB) + +// void runtime·racereadpc(void *addr, void *callpc, void *pc) +TEXT runtime·racereadpc(SB), NOSPLIT, $0-24 + MOVD addr+0(FP), R4 + MOVD callpc+8(FP), R5 + MOVD pc+16(FP), R6 + // void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc); + MOVD $__tsan_read_pc(SB), R8 + BR racecalladdr<>(SB) + +// func runtime·RaceWrite(addr uintptr) +// Called from instrumented Go code +TEXT runtime·racewrite(SB), NOSPLIT, $0-8 + MOVD addr+0(FP), R4 + MOVD LR, R5 // caller has set LR via BL inst + // void __tsan_write(ThreadState *thr, void *addr, void *pc); + MOVD $__tsan_write(SB), R8 + BR racecalladdr<>(SB) + +TEXT runtime·RaceWrite(SB), NOSPLIT, $0-8 + JMP runtime·racewrite(SB) + +// void runtime·racewritepc(void *addr, void *callpc, void *pc) +TEXT runtime·racewritepc(SB), NOSPLIT, $0-24 + MOVD addr+0(FP), R4 + MOVD callpc+8(FP), R5 + MOVD pc+16(FP), R6 + // void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc); + MOVD $__tsan_write_pc(SB), R8 + BR racecalladdr<>(SB) + +// func runtime·RaceReadRange(addr, size uintptr) +// Called from instrumented Go code. +TEXT runtime·racereadrange(SB), NOSPLIT, $0-16 + MOVD addr+0(FP), R4 + MOVD size+8(FP), R5 + MOVD LR, R6 + // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc); + MOVD $__tsan_read_range(SB), R8 + BR racecalladdr<>(SB) + +// void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc) +TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24 + MOVD addr+0(FP), R4 + MOVD size+8(FP), R5 + MOVD pc+16(FP), R6 + ADD $4, R6 // tsan wants return addr + // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc); + MOVD $__tsan_read_range(SB), R8 + BR racecalladdr<>(SB) + +TEXT runtime·RaceReadRange(SB), NOSPLIT, $0-24 + BR runtime·racereadrange(SB) + +// func runtime·RaceWriteRange(addr, size uintptr) +// Called from instrumented Go code. +TEXT runtime·racewriterange(SB), NOSPLIT, $0-16 + MOVD addr+0(FP), R4 + MOVD size+8(FP), R5 + MOVD LR, R6 + // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc); + MOVD $__tsan_write_range(SB), R8 + BR racecalladdr<>(SB) + +TEXT runtime·RaceWriteRange(SB), NOSPLIT, $0-16 + BR runtime·racewriterange(SB) + +// void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc) +// Called from instrumented Go code +TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24 + MOVD addr+0(FP), R4 + MOVD size+8(FP), R5 + MOVD pc+16(FP), R6 + ADD $4, R6 // add 4 to inst offset? + // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc); + MOVD $__tsan_write_range(SB), R8 + BR racecalladdr<>(SB) + +// Call a __tsan function from Go code. +// R8 = tsan function address +// R3 = *ThreadState a.k.a. g_racectx from g +// R4 = addr passed to __tsan function +// +// Otherwise, setup goroutine context and invoke racecall. Other arguments already set. +TEXT racecalladdr<>(SB), NOSPLIT, $0-0 + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + MOVD g_racectx(g), R3 // goroutine context + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). + MOVD runtime·racearenastart(SB), R9 + CMP R4, R9 + BLT data + MOVD runtime·racearenaend(SB), R9 + CMP R4, R9 + BLT call +data: + MOVD runtime·racedatastart(SB), R9 + CMP R4, R9 + BLT ret + MOVD runtime·racedataend(SB), R9 + CMP R4, R9 + BGT ret +call: + // Careful!! racecall will save LR on its + // stack, which is OK as long as racecalladdr + // doesn't change in a way that generates a stack. + // racecall should return to the caller of + // recalladdr. + BR racecall<>(SB) +ret: + RET + +// func runtime·racefuncenterfp() +// Called from instrumented Go code. +// Like racefuncenter but doesn't pass an arg, uses the caller pc +// from the first slot on the stack. +TEXT runtime·racefuncenterfp(SB), NOSPLIT, $0-0 + MOVD 0(R1), R8 + BR racefuncenter<>(SB) + +// func runtime·racefuncenter(pc uintptr) +// Called from instrumented Go code. +// Not used now since gc/racewalk.go doesn't pass the +// correct caller pc and racefuncenterfp can do it. +TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8 + MOVD callpc+0(FP), R8 + BR racefuncenter<>(SB) + +// Common code for racefuncenter/racefuncenterfp +// R11 = caller's return address +TEXT racefuncenter<>(SB), NOSPLIT, $0-0 + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + MOVD g_racectx(g), R3 // goroutine racectx aka *ThreadState + MOVD R8, R4 // caller pc set by caller in R8 + // void __tsan_func_enter(ThreadState *thr, void *pc); + MOVD $__tsan_func_enter(SB), R8 + BR racecall<>(SB) + RET + +// func runtime·racefuncexit() +// Called from Go instrumented code. +TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0 + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + MOVD g_racectx(g), R3 // goroutine racectx aka *ThreadState + // void __tsan_func_exit(ThreadState *thr); + MOVD $__tsan_func_exit(SB), R8 + BR racecall<>(SB) + +// Atomic operations for sync/atomic package. +// Some use the __tsan versions instead +// R6 = addr of arguments passed to this function +// R3, R4, R5 set in racecallatomic + +// Load atomic in tsan +TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic32_load(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + RET + +TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic64_load(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + RET + +TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-0 + BR sync∕atomic·LoadInt32(SB) + +TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-0 + BR sync∕atomic·LoadInt64(SB) + +TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-0 + BR sync∕atomic·LoadInt64(SB) + +TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-0 + BR sync∕atomic·LoadInt64(SB) + +// Store atomic in tsan +TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic32_store(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + +TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic64_store(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + +TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-0 + BR sync∕atomic·StoreInt32(SB) + +TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-0 + BR sync∕atomic·StoreInt64(SB) + +TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-0 + BR sync∕atomic·StoreInt64(SB) + +// Swap in tsan +TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic32_exchange(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + +TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a) + MOVD $__tsan_go_atomic64_exchange(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + +TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-0 + BR sync∕atomic·SwapInt32(SB) + +TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-0 + BR sync∕atomic·SwapInt64(SB) + +TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-0 + BR sync∕atomic·SwapInt64(SB) + +// Add atomic in tsan +TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic32_fetch_add(SB), R8 + ADD $64, R1, R6 // addr of caller's 1st arg + BL racecallatomic<>(SB) + // The tsan fetch_add result is not as expected by Go, + // so the 'add' must be added to the result. + MOVW add+8(FP), R3 // The tsa fetch_add does not return the + MOVW ret+16(FP), R4 // result as expected by go, so fix it. + ADD R3, R4, R3 + MOVW R3, ret+16(FP) + RET + +TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a); + MOVD $__tsan_go_atomic64_fetch_add(SB), R8 + ADD $64, R1, R6 // addr of caller's 1st arg + BL racecallatomic<>(SB) + // The tsan fetch_add result is not as expected by Go, + // so the 'add' must be added to the result. + MOVD add+8(FP), R3 + MOVD ret+16(FP), R4 + ADD R3, R4, R3 + MOVD R3, ret+16(FP) + RET + +TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-0 + BR sync∕atomic·AddInt32(SB) + +TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-0 + BR sync∕atomic·AddInt64(SB) + +TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-0 + BR sync∕atomic·AddInt64(SB) + +// CompareAndSwap in tsan +TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic32_compare_exchange( + // ThreadState *thr, uptr cpc, uptr pc, u8 *a) + MOVD $__tsan_go_atomic32_compare_exchange(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + +TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-0 + // void __tsan_go_atomic32_compare_exchange( + // ThreadState *thr, uptr cpc, uptr pc, u8 *a) + MOVD $__tsan_go_atomic64_compare_exchange(SB), R8 + ADD $32, R1, R6 // addr of caller's 1st arg + BR racecallatomic<>(SB) + +TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-0 + BR sync∕atomic·CompareAndSwapInt32(SB) + +TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-0 + BR sync∕atomic·CompareAndSwapInt64(SB) + +TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-0 + BR sync∕atomic·CompareAndSwapInt64(SB) + +// Common function used to call tsan's atomic functions +// R3 = *ThreadState +// R4 = TODO: What's this supposed to be? +// R5 = caller pc +// R6 = addr of incoming arg list +// R8 contains addr of target function. +TEXT racecallatomic<>(SB), NOSPLIT, $0-0 + // Trigger SIGSEGV early if address passed to atomic function is bad. + MOVD (R6), R7 // 1st arg is addr + MOVD (R7), R9 // segv here if addr is bad + // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend). + MOVD runtime·racearenastart(SB), R9 + CMP R7, R9 + BLT racecallatomic_data + MOVD runtime·racearenaend(SB), R9 + CMP R7, R9 + BLT racecallatomic_ok +racecallatomic_data: + MOVD runtime·racedatastart(SB), R9 + CMP R7, R9 + BLT racecallatomic_ignore + MOVD runtime·racedataend(SB), R9 + CMP R7, R9 + BGE racecallatomic_ignore +racecallatomic_ok: + // Addr is within the good range, call the atomic function. + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + MOVD g_racectx(g), R3 // goroutine racectx aka *ThreadState + MOVD R8, R5 // pc is the function called + MOVD (R1), R4 // caller pc from stack + BL racecall<>(SB) // BL needed to maintain stack consistency + RET // +racecallatomic_ignore: + // Addr is outside the good range. + // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op. + // An attempt to synchronize on the address would cause crash. + MOVD R8, R15 // save the original function + MOVD R6, R17 // save the original arg list addr + MOVD $__tsan_go_ignore_sync_begin(SB), R8 // func addr to call + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + MOVD g_racectx(g), R3 // goroutine context + BL racecall<>(SB) + MOVD R15, R8 // restore the original function + MOVD R17, R6 // restore arg list addr + // Call the atomic function. + // racecall will call LLVM race code which might clobber r30 (g) + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + + MOVD g_racectx(g), R3 + MOVD R8, R4 // pc being called same TODO as above + MOVD (R1), R5 // caller pc from latest LR + BL racecall<>(SB) + // Call __tsan_go_ignore_sync_end. + MOVD $__tsan_go_ignore_sync_end(SB), R8 + MOVD g_racectx(g), R3 // goroutine context g should sitll be good? + BL racecall<>(SB) + RET + +// void runtime·racecall(void(*f)(...), ...) +// Calls C function f from race runtime and passes up to 4 arguments to it. +// The arguments are never heap-object-preserving pointers, so we pretend there are no arguments. +TEXT runtime·racecall(SB), NOSPLIT, $0-0 + MOVD fn+0(FP), R8 + MOVD arg0+8(FP), R3 + MOVD arg1+16(FP), R4 + MOVD arg2+24(FP), R5 + MOVD arg3+32(FP), R6 + JMP racecall<>(SB) + +// Finds g0 and sets its stack +// Arguments were loaded for call from Go to C +TEXT racecall<>(SB), NOSPLIT, $0-0 + // Set the LR slot for the ppc64 ABI + MOVD LR, R10 + MOVD R10, 0(R1) // Go expectation + MOVD R10, 16(R1) // C ABI + // Get info from the current goroutine + MOVD runtime·tls_g(SB), R10 // g offset in TLS + MOVD 0(R13)(R10*1), g // R13 = current TLS + MOVD g_m(g), R7 // m for g + MOVD R1, R16 // callee-saved, preserved across C call + MOVD m_g0(R7), R10 // g0 for m + CMP R10, g // same g0? + BEQ call // already on g0 + MOVD (g_sched+gobuf_sp)(R10), R1 // switch R1 +call: + MOVD R8, CTR // R8 = caller addr + MOVD R8, R12 // expected by PPC64 ABI + BL (CTR) + XOR R0, R0 // clear R0 on return from Clang + MOVD R16, R1 // restore R1; R16 nonvol in Clang + MOVD runtime·tls_g(SB), R10 // find correct g + MOVD 0(R13)(R10*1), g + MOVD 16(R1), R10 // LR was saved away, restore for return + MOVD R10, LR + RET + +// C->Go callback thunk that allows to call runtime·racesymbolize from C code. +// Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g. +// The overall effect of Go->C->Go call chain is similar to that of mcall. +// RARG0 contains command code. RARG1 contains command-specific context. +// See racecallback for command codes. +TEXT runtime·racecallbackthunk(SB), NOSPLIT, $-8 + // Handle command raceGetProcCmd (0) here. + // First, code below assumes that we are on curg, while raceGetProcCmd + // can be executed on g0. Second, it is called frequently, so will + // benefit from this fast path. + XOR R0, R0 // clear R0 since we came from C code + CMP R3, $0 + BNE rest + // g0 TODO: Don't modify g here since R30 is nonvolatile + MOVD g, R9 + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + MOVD g_m(g), R3 + MOVD m_p(R3), R3 + MOVD p_racectx(R3), R3 + MOVD R3, (R4) + MOVD R9, g // restore R30 ?? + RET + + // This is all similar to what cgo does + // Save registers according to the ppc64 ABI +rest: + MOVD LR, R10 // save link register + MOVD R10, 16(R1) + MOVW CR, R10 + MOVW R10, 8(R1) + MOVDU R1, -336(R1) // Allocate frame needed for register save area + + MOVD R14, 40(R1) + MOVD R15, 48(R1) + MOVD R16, 56(R1) + MOVD R17, 64(R1) + MOVD R18, 72(R1) + MOVD R19, 80(R1) + MOVD R20, 88(R1) + MOVD R21, 96(R1) + MOVD R22, 104(R1) + MOVD R23, 112(R1) + MOVD R24, 120(R1) + MOVD R25, 128(R1) + MOVD R26, 136(R1) + MOVD R27, 144(R1) + MOVD R28, 152(R1) + MOVD R29, 160(R1) + MOVD g, 168(R1) // R30 + MOVD R31, 176(R1) + FMOVD F14, 184(R1) + FMOVD F15, 192(R1) + FMOVD F16, 200(R1) + FMOVD F17, 208(R1) + FMOVD F18, 216(R1) + FMOVD F19, 224(R1) + FMOVD F20, 232(R1) + FMOVD F21, 240(R1) + FMOVD F22, 248(R1) + FMOVD F23, 256(R1) + FMOVD F24, 264(R1) + FMOVD F25, 272(R1) + FMOVD F26, 280(R1) + FMOVD F27, 288(R1) + FMOVD F28, 296(R1) + FMOVD F29, 304(R1) + FMOVD F30, 312(R1) + FMOVD F31, 320(R1) + + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + + MOVD g_m(g), R7 + MOVD m_g0(R7), g // set g = m-> g0 + MOVD R3, cmd+0(FP) // can't use R1 here ?? use input args and assumer caller expects those? + MOVD R4, ctx+8(FP) // can't use R1 here ?? + BL runtime·racecallback(SB) + // All registers are clobbered after Go code, reload. + MOVD runtime·tls_g(SB), R10 + MOVD 0(R13)(R10*1), g + + MOVD g_m(g), R7 + MOVD m_curg(R7), g // restore g = m->curg + MOVD 40(R1), R14 + MOVD 48(R1), R15 + MOVD 56(R1), R16 + MOVD 64(R1), R17 + MOVD 72(R1), R18 + MOVD 80(R1), R19 + MOVD 88(R1), R20 + MOVD 96(R1), R21 + MOVD 104(R1), R22 + MOVD 112(R1), R23 + MOVD 120(R1), R24 + MOVD 128(R1), R25 + MOVD 136(R1), R26 + MOVD 144(R1), R27 + MOVD 152(R1), R28 + MOVD 160(R1), R29 + MOVD 168(R1), g // R30 + MOVD 176(R1), R31 + FMOVD 184(R1), F14 + FMOVD 192(R1), F15 + FMOVD 200(R1), F16 + FMOVD 208(R1), F17 + FMOVD 216(R1), F18 + FMOVD 224(R1), F19 + FMOVD 232(R1), F20 + FMOVD 240(R1), F21 + FMOVD 248(R1), F22 + FMOVD 256(R1), F23 + FMOVD 264(R1), F24 + FMOVD 272(R1), F25 + FMOVD 280(R1), F26 + FMOVD 288(R1), F27 + FMOVD 296(R1), F28 + FMOVD 304(R1), F29 + FMOVD 312(R1), F30 + FMOVD 320(R1), F31 + + ADD $336, R1 + MOVD 8(R1), R10 + MOVFL R10, $0xff // Restore of CR + MOVD 16(R1), R10 // needed? + MOVD R10, LR + RET + +// tls_g, g value for each thread in TLS +GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8 diff --git a/src/runtime/tls_ppc64x.s b/src/runtime/tls_ppc64x.s index 69c0d9eb99..ed94989b69 100644 --- a/src/runtime/tls_ppc64x.s +++ b/src/runtime/tls_ppc64x.s @@ -46,4 +46,4 @@ TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0 MOVD 0(R13)(R31*1), g RET -GLOBL runtime·tls_g+0(SB), TLSBSS, $8 +GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8 From b111f3cc679f44961dc8a78b24a502fb12d6dde2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 20 Apr 2018 12:16:58 -0400 Subject: [PATCH 015/203] cmd/vet: add support for vet-specific export data An upcoming change to cmd/go will enable this functionality, which allows vet to write down information about one package for use by later invocation of vet that analyze code importing that package. We've intended to do this for a long time, but the build caching was necessary to have a decent way to manage the vet-specific export data. This is also an experiment in building scalable whole-program analyses. In the long term we'd like to allow other analyses to be invoked this way. Change-Id: I34e4b70445786b2e8707ff6a0c00947bf1491511 Reviewed-on: https://go-review.googlesource.com/117099 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Bryan C. Mills --- src/cmd/vet/asmdecl.go | 4 +- src/cmd/vet/doc.go | 25 ++++------ src/cmd/vet/main.go | 108 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 20 deletions(-) diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go index d3335c69f5..43c4203809 100644 --- a/src/cmd/vet/asmdecl.go +++ b/src/cmd/vet/asmdecl.go @@ -104,6 +104,8 @@ func init() { arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer])) arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64])) } + + registerPkgCheck("asmdecl", asmCheck) } var ( @@ -119,7 +121,7 @@ var ( ) func asmCheck(pkg *Package) { - if !vet("asmdecl") { + if vcfg.VetxOnly { return } diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go index 3df975cacc..d9af0a8875 100644 --- a/src/cmd/vet/doc.go +++ b/src/cmd/vet/doc.go @@ -119,22 +119,17 @@ Printf family Flag: -printf -Suspicious calls to functions in the Printf family, including any functions -with these names, disregarding case: - Print Printf Println - Fprint Fprintf Fprintln - Sprint Sprintf Sprintln - Error Errorf - Fatal Fatalf - Log Logf - Panic Panicf Panicln -The -printfuncs flag can be used to redefine this list. -If the function name ends with an 'f', the function is assumed to take -a format descriptor string in the manner of fmt.Printf. If not, vet -complains about arguments that look like format descriptor strings. +Suspicious calls to fmt.Print, fmt.Printf, and related functions. +The check applies to known functions (for example, those in package fmt) +as well as any detected wrappers of known functions. -It also checks for errors such as using a Writer as the first argument of -Printf. +The -printfuncs flag specifies a comma-separated list of names of +additional known formatting functions. Each name can be of the form +pkg.Name or pkg.Type.Name, where pkg is a complete import path, +or else can be a case-insensitive unqualified identifier like "errorf". +If a listed name ends in f, the function is assumed to be Printf-like, +taking a format string before the argument list. Otherwise it is +assumed to be Print-like, taking a list of arguments with no format string. Range loop variables diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index 50af846c59..959a536d25 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -4,10 +4,12 @@ // Vet is a simple checker for static errors in Go source code. // See doc.go for more information. + package main import ( "bytes" + "encoding/gob" "encoding/json" "flag" "fmt" @@ -24,6 +26,8 @@ import ( "path/filepath" "strconv" "strings" + + "cmd/internal/objabi" ) // Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go. @@ -154,9 +158,25 @@ var ( // checkers is a two-level map. // The outer level is keyed by a nil pointer, one of the AST vars above. // The inner level is keyed by checker name. - checkers = make(map[ast.Node]map[string]func(*File, ast.Node)) + checkers = make(map[ast.Node]map[string]func(*File, ast.Node)) + pkgCheckers = make(map[string]func(*Package)) + exporters = make(map[string]func() interface{}) ) +// Vet can provide its own "export information" +// about package A to future invocations of vet +// on packages importing A. If B imports A, +// then running "go vet B" actually invokes vet twice: +// first, it runs vet on A, in "vetx-only" mode, which +// skips most checks and only computes export data +// describing A. Then it runs vet on B, making A's vetx +// data available for consultation. The vet of B +// computes vetx data for B in addition to its +// usual vet checks. + +// register registers the named check function, +// to be called with AST nodes of the given types. +// The registered functions are not called in vetx-only mode. func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) { report[name] = triStateFlag(name, unset, usage) for _, typ := range types { @@ -169,6 +189,25 @@ func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) { } } +// registerPkgCheck registers a package-level checking function, +// to be invoked with the whole package being vetted +// before any of the per-node handlers. +// The registered function fn is called even in vetx-only mode +// (see comment above), so fn must take care not to report +// errors when vcfg.VetxOnly is true. +func registerPkgCheck(name string, fn func(*Package)) { + pkgCheckers[name] = fn +} + +// registerExport registers a function to return vetx export data +// that should be saved and provided to future invocations of vet +// when checking packages importing this one. +// The value returned by fn should be nil or else valid to encode using gob. +// Typically a registerExport call is paired with a call to gob.Register. +func registerExport(name string, fn func() interface{}) { + exporters[name] = fn +} + // Usage is a replacement usage function for the flags package. func Usage() { fmt.Fprintf(os.Stderr, "Usage of vet:\n") @@ -209,6 +248,7 @@ type File struct { } func main() { + objabi.AddVersionFlag() flag.Usage = Usage flag.Parse() @@ -295,6 +335,9 @@ type vetConfig struct { ImportMap map[string]string PackageFile map[string]string Standard map[string]bool + PackageVetx map[string]string // map from import path to vetx data file + VetxOnly bool // only compute vetx output; don't run ordinary checks + VetxOutput string // file where vetx output should be written SucceedOnTypecheckFailure bool @@ -355,6 +398,21 @@ func doPackageCfg(cfgFile string) { inittypes() mustTypecheck = true doPackage(vcfg.GoFiles, nil) + if vcfg.VetxOutput != "" { + out := make(map[string]interface{}) + for name, fn := range exporters { + out[name] = fn() + } + var buf bytes.Buffer + if err := gob.NewEncoder(&buf).Encode(out); err != nil { + errorf("encoding vet output: %v", err) + return + } + if err := ioutil.WriteFile(vcfg.VetxOutput, buf.Bytes(), 0666); err != nil { + errorf("saving vet output: %v", err) + return + } + } } // doPackageDir analyzes the single package found in the directory, if there is one, @@ -461,6 +519,19 @@ func doPackage(names []string, basePkg *Package) *Package { } // Check. + for _, file := range files { + file.pkg = pkg + file.basePkg = basePkg + } + for name, fn := range pkgCheckers { + if vet(name) { + fn(pkg) + } + } + if vcfg.VetxOnly { + return pkg + } + chk := make(map[ast.Node][]func(*File, ast.Node)) for typ, set := range checkers { for name, fn := range set { @@ -470,14 +541,11 @@ func doPackage(names []string, basePkg *Package) *Package { } } for _, file := range files { - file.pkg = pkg - file.basePkg = basePkg file.checkers = chk if file.file != nil { file.walkFile(file.name, file.file) } } - asmCheck(pkg) return pkg } @@ -630,3 +698,35 @@ func (f *File) gofmt(x ast.Expr) string { printer.Fprint(&f.b, f.fset, x) return f.b.String() } + +// imported[path][key] is previously written export data. +var imported = make(map[string]map[string]interface{}) + +// readVetx reads export data written by a previous +// invocation of vet on an imported package (path). +// The key is the name passed to registerExport +// when the data was originally generated. +// readVetx returns nil if the data is unavailable. +func readVetx(path, key string) interface{} { + if path == "unsafe" || vcfg.ImportPath == "" { + return nil + } + m := imported[path] + if m == nil { + file := vcfg.PackageVetx[path] + if file == "" { + return nil + } + data, err := ioutil.ReadFile(file) + if err != nil { + return nil + } + m = make(map[string]interface{}) + err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m) + if err != nil { + return nil + } + imported[path] = m + } + return m[key] +} From 131d7e0d0ee4471dc97f24d223aeef47ba6809d5 Mon Sep 17 00:00:00 2001 From: Paul Jolly Date: Fri, 11 May 2018 15:02:45 +0100 Subject: [PATCH 016/203] cmd/go: set DepOnly on package when calling go list -deps Currently .DepOnly is set when go list -test is invoked to help distinguish those packages that matched the command line spec from those which are dependencies (of test packages). This is also useful when calling go list -deps for the same reason. Change-Id: Ifc0e68dad0fd01355928793ef803691dee5f4f29 Reviewed-on: https://go-review.googlesource.com/112755 Run-TryBot: Paul Jolly TryBot-Result: Gobot Gobot Reviewed-by: Bryan C. Mills Reviewed-by: Russ Cox --- src/cmd/go/go_test.go | 4 ++++ src/cmd/go/internal/list/list.go | 1 + 2 files changed, 5 insertions(+) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index a44866f6b2..abe23ff52d 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -1975,6 +1975,10 @@ func TestGoListTest(t *testing.T) { tg.run("list", "-test", "runtime/cgo") tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo") + + tg.run("list", "-deps", "-f", "{{if .DepOnly}}{{.ImportPath}}{{end}}", "sort") + tg.grepStdout(`^reflect$`, "missing reflect") + tg.grepStdoutNot(`^sort`, "unexpected sort") } func TestGoListCgo(t *testing.T) { diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 7261d24839..d519dcc5e0 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -335,6 +335,7 @@ func runList(cmd *base.Command, args []string) { // Show vendor-expanded paths in listing p.TestImports = p.Resolve(p.TestImports) p.XTestImports = p.Resolve(p.XTestImports) + p.DepOnly = !cmdline[p] } if *listTest { From 92f8acd192dc2dc9191cc633666c26137c12a6cd Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Mon, 11 Jun 2018 22:34:03 +0200 Subject: [PATCH 017/203] cmd/nm: fix TestGoExec on Plan 9 CL 115975 changed TestGoExec to check symbol types. However, this test is failing on Plan 9, because there is no read-only data segment symbol on Plan 9. This change fixes TestGoExec to replace the check of read-only data segment symbol (R) by data segment symbol (D) on Plan 9. Fixes #25820. Change-Id: I7164cd9056fa1dfcd1dc1b0f87653290c14c85fa Reviewed-on: https://go-review.googlesource.com/118035 Run-TryBot: David du Colombier <0intro@gmail.com> Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/nm/nm_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 890df0f902..ccf5682d69 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -157,6 +157,10 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) { t.Errorf("duplicate name of %q is found", name) } if stype, found := runtimeSyms[name]; found { + if runtime.GOOS == "plan9" && stype == "R" { + // no read-only data segment symbol on Plan 9 + stype = "D" + } if want, have := stype, strings.ToUpper(f[1]); have != want { t.Errorf("want %s type for %s symbol, but have %s", want, name, have) } From f864d89ef7142687fabcbc28e9058868bce82468 Mon Sep 17 00:00:00 2001 From: Iskander Sharipov Date: Fri, 1 Jun 2018 18:55:36 +0300 Subject: [PATCH 018/203] runtime: remove TODO notes suggesting jump tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For memmove/memclr using jump tables only reduces overall function performance for both amd64 and 386. Benchmarks for 32-bit memclr: name old time/op new time/op delta Memclr/5-8 8.01ns ± 0% 8.94ns ± 2% +11.59% (p=0.000 n=9+9) Memclr/16-8 9.05ns ± 0% 9.49ns ± 0% +4.81% (p=0.000 n=8+8) Memclr/64-8 9.15ns ± 0% 9.49ns ± 0% +3.76% (p=0.000 n=9+10) Memclr/256-8 16.6ns ± 0% 16.6ns ± 0% ~ (p=1.140 n=10+9) Memclr/4096-8 179ns ± 0% 166ns ± 0% -7.26% (p=0.000 n=9+8) Memclr/65536-8 3.36µs ± 1% 3.31µs ± 1% -1.48% (p=0.000 n=10+9) Memclr/1M-8 59.5µs ± 3% 60.5µs ± 2% +1.67% (p=0.009 n=10+10) Memclr/4M-8 239µs ± 3% 245µs ± 0% +2.49% (p=0.004 n=10+8) Memclr/8M-8 618µs ± 2% 614µs ± 1% ~ (p=0.315 n=10+8) Memclr/16M-8 1.49ms ± 2% 1.47ms ± 1% -1.11% (p=0.029 n=10+10) Memclr/64M-8 7.06ms ± 1% 7.05ms ± 0% ~ (p=0.573 n=10+8) [Geo mean] 3.36µs 3.39µs +1.14% For less predictable data, like loop iteration dependant sizes, branch table still shows 2-5% worse results. It also makes code slightly more complicated. This CL removes TODO note that directly suggest trying this optimization out. That encourages people to spend their time in a quite hopeless endeavour. The code used to implement branch table used a 32/64-entry table with pointers to TEXT blocks that implemented every associated label work. Most last entries point to "loop" code that is a fallthrough for all other sizes that do not map into specialized routines. The only inefficiency is extra MOVL/MOVQ required to fetch table pointer itself as MOVL $sym<>(SB)(AX*4) is not valid in Go asm (it works in other assemblers): TEXT ·memclrNew(SB), NOSPLIT, $0-8 MOVL ptr+0(FP), DI MOVL n+4(FP), BX // Handle 0 separately. TESTL BX, BX JEQ _0 LEAL -1(BX), CX // n-1 BSRL CX, CX // AX or X0 zeroed inside every text block. MOVL $memclrTable<>(SB), AX JMP (AX)(CX*4) _0: RET Change-Id: I4f706931b8127f85a8439b95834d5c2485a5d1bf Reviewed-on: https://go-review.googlesource.com/115678 Run-TryBot: Iskander Sharipov TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick Reviewed-by: Keith Randall --- src/runtime/memclr_386.s | 2 +- src/runtime/memclr_amd64.s | 2 +- src/runtime/memmove_386.s | 2 +- src/runtime/memmove_amd64.s | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s index 7d5dd38c0a..a6703b3641 100644 --- a/src/runtime/memclr_386.s +++ b/src/runtime/memclr_386.s @@ -16,6 +16,7 @@ TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-8 // MOVOU seems always faster than REP STOSL. tail: + // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing. TESTL BX, BX JEQ _0 CMPL BX, $2 @@ -38,7 +39,6 @@ tail: JBE _65through128 CMPL BX, $256 JBE _129through256 - // TODO: use branch table and BSR to make this just a single dispatch loop: MOVOU X0, 0(DI) diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s index 63730eebfb..d79078fd00 100644 --- a/src/runtime/memclr_amd64.s +++ b/src/runtime/memclr_amd64.s @@ -17,6 +17,7 @@ TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-16 // MOVOU seems always faster than REP STOSQ. tail: + // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing. TESTQ BX, BX JEQ _0 CMPQ BX, $2 @@ -39,7 +40,6 @@ tail: JBE _129through256 CMPB internal∕cpu·X86+const_offsetX86HasAVX2(SB), $1 JE loop_preheader_avx2 - // TODO: use branch table and BSR to make this just a single dispatch // TODO: for really big clears, use MOVNTDQ, even without AVX2. loop: diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s index 1bf86a5453..172ea40820 100644 --- a/src/runtime/memmove_386.s +++ b/src/runtime/memmove_386.s @@ -39,6 +39,7 @@ TEXT runtime·memmove(SB), NOSPLIT, $0-12 // 128 because that is the maximum SSE register load (loading all data // into registers lets us ignore copy direction). tail: + // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing. TESTL BX, BX JEQ move_0 CMPL BX, $2 @@ -58,7 +59,6 @@ tail: JBE move_33through64 CMPL BX, $128 JBE move_65through128 - // TODO: use branch table and BSR to make this just a single dispatch nosse2: /* diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s index a671baf383..cb5cd02e45 100644 --- a/src/runtime/memmove_amd64.s +++ b/src/runtime/memmove_amd64.s @@ -43,6 +43,8 @@ tail: // registers before writing it back. move_256through2048 on the other // hand can be used only when the memory regions don't overlap or the copy // direction is forward. + // + // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing. TESTQ BX, BX JEQ move_0 CMPQ BX, $2 @@ -63,7 +65,6 @@ tail: JBE move_65through128 CMPQ BX, $256 JBE move_129through256 - // TODO: use branch table and BSR to make this just a single dispatch TESTB $1, runtime·useAVXmemmove(SB) JNZ avxUnaligned From d0d47bb94fcc018d03f47faa51f981b8902fc7cd Mon Sep 17 00:00:00 2001 From: Michael Fraenkel Date: Wed, 23 May 2018 17:23:35 -0400 Subject: [PATCH 019/203] cmd/doc: continue to search when package import fails Keep searching for a package that is both findable and importable. The current code would always guarantee that a package was findable but exited if it was not importable. Fixes #25478 Change-Id: I237b7dfafb930cae02538c4a2e4d5ce0c1058478 Reviewed-on: https://go-review.googlesource.com/114295 Reviewed-by: Bryan C. Mills Reviewed-by: Rob Pike Run-TryBot: Bryan C. Mills TryBot-Result: Gobot Gobot --- src/cmd/doc/doc_test.go | 20 ++++++++++++++- src/cmd/doc/main.go | 29 +++++++++++++++------- src/cmd/doc/testdata/nested/ignore.go | 4 +++ src/cmd/doc/testdata/nested/nested/real.go | 4 +++ 4 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 src/cmd/doc/testdata/nested/ignore.go create mode 100644 src/cmd/doc/testdata/nested/nested/real.go diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index f1072b5e41..e68e95f3fb 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -26,7 +26,7 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } - dirsInit(testdataDir) + dirsInit(testdataDir, filepath.Join(testdataDir, "nested"), filepath.Join(testdataDir, "nested", "nested")) os.Exit(m.Run()) } @@ -510,6 +510,24 @@ var tests = []test{ "\\)\n+const", // This will appear if the const decl appears twice. }, }, + { + "non-imported: pkg.sym", + []string{"nested.Foo"}, + []string{"Foo struct"}, + nil, + }, + { + "non-imported: pkg only", + []string{"nested"}, + []string{"Foo struct"}, + nil, + }, + { + "non-imported: pkg sym", + []string{"nested", "Foo"}, + []string{"Foo struct"}, + nil, + }, } func TestDoc(t *testing.T) { diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index 9f947146a4..bf0c7723f8 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -189,11 +189,16 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo // Done below. case 2: // Package must be findable and importable. - packagePath, ok := findPackage(arg) - if !ok { - return nil, args[0], args[1], false + for { + packagePath, ok := findNextPackage(arg) + if !ok { + break + } + if pkg, err := build.ImportDir(packagePath, build.ImportComment); err == nil { + return pkg, arg, args[1], true + } } - return importDir(packagePath), arg, args[1], true + return nil, args[0], args[1], false } // Usual case: one argument. // If it contains slashes, it begins with a package path. @@ -241,9 +246,15 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo } // See if we have the basename or tail of a package, as in json for encoding/json // or ivy/value for robpike.io/ivy/value. - path, ok := findPackage(arg[0:period]) - if ok { - return importDir(path), arg[0:period], symbol, true + pkgName := arg[:period] + for { + path, ok := findNextPackage(pkgName) + if !ok { + break + } + if pkg, err = build.ImportDir(path, build.ImportComment); err == nil { + return pkg, arg[0:period], symbol, true + } } dirs.Reset() // Next iteration of for loop must scan all the directories again. } @@ -338,9 +349,9 @@ func isUpper(name string) bool { return unicode.IsUpper(ch) } -// findPackage returns the full file name path that first matches the +// findNextPackage returns the next full file name path that matches the // (perhaps partial) package path pkg. The boolean reports if any match was found. -func findPackage(pkg string) (string, bool) { +func findNextPackage(pkg string) (string, bool) { if pkg == "" || isUpper(pkg) { // Upper case symbol cannot be a package name. return "", false } diff --git a/src/cmd/doc/testdata/nested/ignore.go b/src/cmd/doc/testdata/nested/ignore.go new file mode 100644 index 0000000000..c497f1b5bc --- /dev/null +++ b/src/cmd/doc/testdata/nested/ignore.go @@ -0,0 +1,4 @@ +// +build ignore + +// Ignored package +package nested diff --git a/src/cmd/doc/testdata/nested/nested/real.go b/src/cmd/doc/testdata/nested/nested/real.go new file mode 100644 index 0000000000..1e5546081c --- /dev/null +++ b/src/cmd/doc/testdata/nested/nested/real.go @@ -0,0 +1,4 @@ +package nested + +type Foo struct { +} From f861f66d1db9f1abcdf91fc54d0d84bd3f9e9310 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 11 Jun 2018 16:46:23 -0700 Subject: [PATCH 020/203] cmd/link: treat cgo exported symbols as C symbols Fixes #25827 Change-Id: I6736c3ac061ca32aac2eb68b01ba53a179d68cf4 Reviewed-on: https://go-review.googlesource.com/118076 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/cmd/link/internal/ld/pcln.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 50ac6d0743..7b7f7068e7 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -11,6 +11,7 @@ import ( "log" "os" "path/filepath" + "strings" ) // iteration over encoded pcdata tables. @@ -159,13 +160,15 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) { *d = out } -// onlycsymbol reports whether this is a cgo symbol provided by the -// runtime and only used from C code. +// onlycsymbol reports whether this is a symbol that is referenced by C code. func onlycsymbol(s *sym.Symbol) bool { switch s.Name { case "_cgo_topofstack", "_cgo_panic", "crosscall2": return true } + if strings.HasPrefix(s.Name, "_cgoexp_") { + return true + } return false } From 2630085afed763777021ab87d095ff3b7039e2b5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 20 Apr 2018 12:16:36 -0400 Subject: [PATCH 021/203] cmd/go: add support for vet-specific export data This CL makes it possible for vet to write down notes about one package and then access those notes later, when analyzing other code importing that package. This is much like what the compiler does with its own export data for type-checking, so we call it "vet-export" data or vetx data. The next CL in the stack makes vet actually use this functionality. Change-Id: Ic70043ab407dfbfdb3f30eaea7c0e3c8197009cf Reviewed-on: https://go-review.googlesource.com/108558 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/cache/cache.go | 15 ++++++ src/cmd/go/internal/vet/vetflag.go | 2 +- src/cmd/go/internal/work/action.go | 31 +++++++++--- src/cmd/go/internal/work/buildid.go | 28 ++++++----- src/cmd/go/internal/work/exec.go | 77 +++++++++++++++++++++++------ 5 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go index edb58826f1..0cf01550ff 100644 --- a/src/cmd/go/internal/cache/cache.go +++ b/src/cmd/go/internal/cache/cache.go @@ -189,6 +189,21 @@ func (c *Cache) get(id ActionID) (Entry, error) { return Entry{buf, size, time.Unix(0, tm)}, nil } +// GetFile looks up the action ID in the cache and returns +// the name of the corresponding data file. +func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) { + entry, err = c.Get(id) + if err != nil { + return "", Entry{}, err + } + file = c.OutputFile(entry.OutputID) + info, err := os.Stat(file) + if err != nil || info.Size() != entry.Size { + return "", Entry{}, errMissing + } + return file, entry, nil +} + // GetBytes looks up the action ID in the cache and returns // the corresponding output bytes. // GetBytes should only be used for data that can be expected to fit in memory. diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index 03770ea920..bdfe033018 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -90,7 +90,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) { } switch f.Name { // Flags known to the build but not to vet, so must be dropped. - case "x", "n", "vettool", "compiler": + case "a", "x", "n", "vettool", "compiler": if extraWord { args = append(args[:i], args[i+2:]...) extraWord = false diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go index 3b5c4d65fd..8edf55ffa1 100644 --- a/src/cmd/go/internal/work/action.go +++ b/src/cmd/go/internal/work/action.go @@ -82,9 +82,10 @@ type Action struct { actionID cache.ActionID // cache ID of action input buildID string // build ID of action output - needVet bool // Mode=="build": need to fill in vet config - vetCfg *vetConfig // vet config - output []byte // output redirect buffer (nil means use b.Print) + VetxOnly bool // Mode=="vet": only being called to supply info about dependencies + needVet bool // Mode=="build": need to fill in vet config + vetCfg *vetConfig // vet config + output []byte // output redirect buffer (nil means use b.Print) // Execution state. pending int // number of deps yet to complete @@ -141,6 +142,7 @@ type actionJSON struct { Priority int `json:",omitempty"` Failed bool `json:",omitempty"` Built string `json:",omitempty"` + VetxOnly bool `json:",omitempty"` } // cacheKey is the key for the action cache. @@ -180,6 +182,7 @@ func actionGraphJSON(a *Action) string { Failed: a.Failed, Priority: a.priority, Built: a.built, + VetxOnly: a.VetxOnly, } if a.Package != nil { // TODO(rsc): Make this a unique key for a.Package somehow. @@ -383,6 +386,12 @@ func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Actio // If the caller may be causing p to be installed, it is up to the caller // to make sure that the install depends on (runs after) vet. func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { + a := b.vetAction(mode, depMode, p) + a.VetxOnly = false + return a +} + +func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { // Construct vet action. a := b.cacheAction("vet", p, func() *Action { a1 := b.CompileAction(mode, depMode, p) @@ -394,11 +403,18 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { stk.Pop() aFmt := b.CompileAction(ModeBuild, depMode, p1) + deps := []*Action{a1, aFmt} + for _, p1 := range load.PackageList(p.Internal.Imports) { + deps = append(deps, b.vetAction(mode, depMode, p1)) + } + a := &Action{ - Mode: "vet", - Package: p, - Deps: []*Action{a1, aFmt}, - Objdir: a1.Objdir, + Mode: "vet", + Package: p, + Deps: deps, + Objdir: a1.Objdir, + VetxOnly: true, + IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems) } if a1.Func == nil { // Built-in packages like unsafe. @@ -406,7 +422,6 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action { } a1.needVet = true a.Func = (*Builder).vet - return a }) return a diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 04ff01a350..9a2528b914 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -174,20 +174,29 @@ func (b *Builder) toolID(name string) string { return id } - cmdline := str.StringList(cfg.BuildToolexec, base.Tool(name), "-V=full") + path := base.Tool(name) + desc := "go tool " + name + + // Special case: undocumented -vettool overrides usual vet, for testing vet. + if name == "vet" && VetTool != "" { + path = VetTool + desc = VetTool + } + + cmdline := str.StringList(cfg.BuildToolexec, path, "-V=full") cmd := exec.Command(cmdline[0], cmdline[1:]...) cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { - base.Fatalf("go tool %s: %v\n%s%s", name, err, stdout.Bytes(), stderr.Bytes()) + base.Fatalf("%s: %v\n%s%s", desc, err, stdout.Bytes(), stderr.Bytes()) } line := stdout.String() f := strings.Fields(line) - if len(f) < 3 || f[0] != name || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { - base.Fatalf("go tool %s -V=full: unexpected output:\n\t%s", name, line) + if len(f) < 3 || f[0] != name && path != VetTool || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { + base.Fatalf("%s -V=full: unexpected output:\n\t%s", desc, line) } if f[2] == "devel" { // On the development branch, use the content ID part of the build ID. @@ -509,14 +518,9 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID // but we're still happy to use results from the build artifact cache. if c := cache.Default(); c != nil { if !cfg.BuildA { - entry, err := c.Get(actionHash) - if err == nil { - file := c.OutputFile(entry.OutputID) - info, err1 := os.Stat(file) - buildID, err2 := buildid.ReadFile(file) - if err1 == nil && err2 == nil && info.Size() == entry.Size { - stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")) - if err == nil { + if file, _, err := c.GetFile(actionHash); err == nil { + if buildID, err := buildid.ReadFile(file); err == nil { + if stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")); err == nil { if len(stdout) > 0 { if cfg.BuildX || cfg.BuildN { b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID)))) diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 5fd2f66b86..1013e1a11f 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -718,16 +718,11 @@ func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error } func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) { - entry, err := c.Get(cache.Subkey(a.actionID, name)) + file, _, err := c.GetFile(cache.Subkey(a.actionID, name)) if err != nil { return "", err } - out := c.OutputFile(entry.OutputID) - info, err := os.Stat(out) - if err != nil || info.Size() != entry.Size { - return "", fmt.Errorf("not in cache") - } - return out, nil + return file, nil } func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error { @@ -833,16 +828,21 @@ func (b *Builder) loadCachedCgoFiles(a *Action) bool { return true } +// vetConfig is the configuration passed to vet describing a single package. type vetConfig struct { - Compiler string - Dir string - GoFiles []string - ImportMap map[string]string - PackageFile map[string]string - Standard map[string]bool - ImportPath string + Compiler string // compiler name (gc, gccgo) + Dir string // directory containing package + ImportPath string // canonical import path ("package path") + GoFiles []string // absolute paths to package source files - SucceedOnTypecheckFailure bool + ImportMap map[string]string // map import path in source code to package path + PackageFile map[string]string // map package path to .a file with export data + Standard map[string]bool // map package path to whether it's in the standard library + PackageVetx map[string]string // map package path to vetx data from earlier vet run + VetxOnly bool // only compute vetx data; don't report detected problems + VetxOutput string // write vetx data to this output file + + SucceedOnTypecheckFailure bool // awful hack; see #18395 and below } func buildVetConfig(a *Action, gofiles []string) { @@ -903,6 +903,8 @@ func (b *Builder) vet(a *Action) error { // a.Deps[0] is the build of the package being vetted. // a.Deps[1] is the build of the "fmt" package. + a.Failed = false // vet of dependency may have failed but we can still succeed + vcfg := a.Deps[0].vetCfg if vcfg == nil { // Vet config should only be missing if the build failed. @@ -912,6 +914,38 @@ func (b *Builder) vet(a *Action) error { return nil } + vcfg.VetxOnly = a.VetxOnly + vcfg.VetxOutput = a.Objdir + "vet.out" + vcfg.PackageVetx = make(map[string]string) + + h := cache.NewHash("vet " + a.Package.ImportPath) + fmt.Fprintf(h, "vet %q\n", b.toolID("vet")) + + // Note: We could decide that vet should compute export data for + // all analyses, in which case we don't need to include the flags here. + // But that would mean that if an analysis causes problems like + // unexpected crashes there would be no way to turn it off. + // It seems better to let the flags disable export analysis too. + fmt.Fprintf(h, "vetflags %q\n", VetFlags) + + fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID) + for _, a1 := range a.Deps { + if a1.Mode == "vet" && a1.built != "" { + fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built)) + vcfg.PackageVetx[a1.Package.ImportPath] = a1.built + } + } + key := cache.ActionID(h.Sum()) + + if vcfg.VetxOnly { + if c := cache.Default(); c != nil && !cfg.BuildA { + if file, _, err := c.GetFile(key); err == nil { + a.built = file + return nil + } + } + } + if vcfg.ImportMap["fmt"] == "" { a1 := a.Deps[1] vcfg.ImportMap["fmt"] = "fmt" @@ -949,7 +983,18 @@ func (b *Builder) vet(a *Action) error { if tool == "" { tool = base.Tool("vet") } - return b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg") + runErr := b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg") + + // If vet wrote export data, save it for input to future vets. + if f, err := os.Open(vcfg.VetxOutput); err == nil { + a.built = vcfg.VetxOutput + if c := cache.Default(); c != nil { + c.Put(key, f) + } + f.Close() + } + + return runErr } // linkActionID computes the action ID for a link action. From 1352de3829df049f669d5a889832f4e06d4dab5b Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 12 Jun 2018 01:24:00 +0000 Subject: [PATCH 022/203] cmd/go/internal/cfg: note the copy of this code in x/tools/cmd/godoc Updates #23445 Change-Id: I4b09073e53b1cf04de698b711fb5fb0d08bc02df Reviewed-on: https://go-review.googlesource.com/118077 Reviewed-by: Ian Lance Taylor --- src/cmd/go/internal/cfg/cfg.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index 3df5905d02..b7906bb1db 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -103,6 +103,16 @@ func init() { } } +// There is a copy of findGOROOT, isSameDir, and isGOROOT in +// x/tools/cmd/godoc/goroot.go. +// Try to keep them in sync for now. + +// findGOROOT returns the GOROOT value, using either an explicitly +// provided environment variable, a GOROOT that contains the current +// os.Executable value, or else the GOROOT that the binary was built +// with from runtime.GOROOT(). +// +// There is a copy of this code in x/tools/cmd/godoc/goroot.go. func findGOROOT() string { if env := os.Getenv("GOROOT"); env != "" { return filepath.Clean(env) @@ -162,6 +172,8 @@ func isSameDir(dir1, dir2 string) bool { // It does this by looking for the path/pkg/tool directory, // which is necessary for useful operation of the cmd/go tool, // and is not typically present in a GOPATH. +// +// There is a copy of this code in x/tools/cmd/godoc/goroot.go. func isGOROOT(path string) bool { stat, err := os.Stat(filepath.Join(path, "pkg", "tool")) if err != nil { From c00603607511701ecc9f56fd82ac528ecf6b8fc6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 Jun 2018 10:55:28 -0400 Subject: [PATCH 023/203] cmd/vet: use vet-specific export data to record detected printf wrappers This CL takes advantage of the ability to record vet-specific export data, added in CL 108558, to save information about observed printf wrappers. Then calls to those wrappers from other packages can be format-checked. This found a few real mistakes using previously-unrecognized printf wrappers in cmd/compile. It will no doubt find real mistakes in external code. Change-Id: I9c29c92d89bbdc984571a174a96e6054585e9cd4 Reviewed-on: https://go-review.googlesource.com/108559 Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot Reviewed-by: Alan Donovan --- src/cmd/vet/print.go | 375 +++++++++++++++++++++++++--------- src/cmd/vet/testdata/print.go | 71 ++++++- 2 files changed, 353 insertions(+), 93 deletions(-) diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 6728d88d45..1edd3dd228 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -8,6 +8,7 @@ package main import ( "bytes" + "encoding/gob" "flag" "fmt" "go/ast" @@ -27,6 +28,9 @@ func init() { "check printf-like invocations", checkFmtPrintfCall, funcDecl, callExpr) + registerPkgCheck("printf", findPrintfLike) + registerExport("printf", exportPrintfLike) + gob.Register(map[string]int(nil)) } func initPrintFlags() { @@ -44,73 +48,244 @@ func initPrintFlags() { name = name[:colon] } - isPrint[strings.ToLower(name)] = true + if !strings.Contains(name, ".") { + name = strings.ToLower(name) + } + isPrint[name] = true } } -// TODO(rsc): Incorporate user-defined printf wrappers again. -// The general plan is to allow vet of one package P to output -// additional information to supply to later vets of packages -// importing P. Then vet of P can record a list of printf wrappers -// and the later vet using P.Printf will find it in the list and check it. -// That's not ready for Go 1.10. -// When that does happen, uncomment the user-defined printf -// wrapper tests in testdata/print.go. +var localPrintfLike = make(map[string]int) + +type printfWrapper struct { + name string + fn *ast.FuncDecl + format *ast.Field + args *ast.Field + callers []printfCaller + printfLike bool +} + +type printfCaller struct { + w *printfWrapper + call *ast.CallExpr +} + +// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper +// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper +// function describing the declaration. Later processing will analyze the +// graph of potential printf wrappers to pick out the ones that are true wrappers. +// A function may be a Printf or Print wrapper if its last argument is ...interface{}. +// If the next-to-last argument is a string, then this may be a Printf wrapper. +// Otherwise it may be a Print wrapper. +func maybePrintfWrapper(decl ast.Decl) *printfWrapper { + // Look for functions with final argument type ...interface{}. + fn, ok := decl.(*ast.FuncDecl) + if !ok || fn.Body == nil { + return nil + } + name := fn.Name.Name + if fn.Recv != nil { + // For (*T).Name or T.name, use "T.name". + rcvr := fn.Recv.List[0].Type + if ptr, ok := rcvr.(*ast.StarExpr); ok { + rcvr = ptr.X + } + id, ok := rcvr.(*ast.Ident) + if !ok { + return nil + } + name = id.Name + "." + name + } + params := fn.Type.Params.List + if len(params) == 0 { + return nil + } + args := params[len(params)-1] + if len(args.Names) != 1 { + return nil + } + ddd, ok := args.Type.(*ast.Ellipsis) + if !ok { + return nil + } + iface, ok := ddd.Elt.(*ast.InterfaceType) + if !ok || len(iface.Methods.List) > 0 { + return nil + } + var format *ast.Field + if len(params) >= 2 { + p := params[len(params)-2] + if len(p.Names) == 1 { + if id, ok := p.Type.(*ast.Ident); ok && id.Name == "string" { + format = p + } + } + } + + return &printfWrapper{ + name: name, + fn: fn, + format: format, + args: args, + } +} + +// findPrintfLike scans the entire package to find printf-like functions. +func findPrintfLike(pkg *Package) { + if vcfg.ImportPath == "" { // no type or vetx information; don't bother + return + } + + // Gather potential wrappesr and call graph between them. + byName := make(map[string]*printfWrapper) + var wrappers []*printfWrapper + for _, file := range pkg.files { + if file.file == nil { + continue + } + for _, decl := range file.file.Decls { + w := maybePrintfWrapper(decl) + if w == nil { + continue + } + byName[w.name] = w + wrappers = append(wrappers, w) + } + } + + // Walk the graph to figure out which are really printf wrappers. + for _, w := range wrappers { + // Scan function for calls that could be to other printf-like functions. + ast.Inspect(w.fn.Body, func(n ast.Node) bool { + call, ok := n.(*ast.CallExpr) + if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) { + return true + } + + pkgpath, name, kind := printfNameAndKind(pkg, call.Fun) + if kind != 0 { + checkPrintfFwd(pkg, w, call, kind) + return true + } + + // If the call is to another function in this package, + // maybe we will find out it is printf-like later. + // Remember this call for later checking. + if pkgpath == "" && byName[name] != nil { + callee := byName[name] + callee.callers = append(callee.callers, printfCaller{w, call}) + } + + return true + }) + } +} + +func match(arg ast.Expr, param *ast.Field) bool { + id, ok := arg.(*ast.Ident) + return ok && id.Obj != nil && id.Obj.Decl == param +} + +const ( + kindPrintf = 1 + kindPrint = 2 +) + +// printfLike reports whether a call to fn should be considered a call to a printf-like function. +// It returns 0 (indicating not a printf-like function), kindPrintf, or kindPrint. +func printfLike(pkg *Package, fn ast.Expr, byName map[string]*printfWrapper) int { + if id, ok := fn.(*ast.Ident); ok && id.Obj != nil { + if w := byName[id.Name]; w != nil && id.Obj.Decl == w.fn { + // Found call to function in same package. + return localPrintfLike[id.Name] + } + } + if sel, ok := fn.(*ast.SelectorExpr); ok { + if id, ok := sel.X.(*ast.Ident); ok && id.Name == "fmt" && strings.Contains(sel.Sel.Name, "rint") { + if strings.HasSuffix(sel.Sel.Name, "f") { + return kindPrintf + } + return kindPrint + } + } + return 0 +} + +// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly. +// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...). +func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int) { + matched := kind == kindPrint || + kind == kindPrintf && len(call.Args) >= 2 && match(call.Args[len(call.Args)-2], w.format) + if !matched { + return + } + + if !call.Ellipsis.IsValid() { + if !vcfg.VetxOnly { + desc := "printf" + if kind == kindPrint { + desc = "print" + } + pkg.files[0].Badf(call.Pos(), "missing ... in args forwarded to %s-like function", desc) + } + return + } + name := w.name + if localPrintfLike[name] == 0 { + localPrintfLike[name] = kind + for _, caller := range w.callers { + checkPrintfFwd(pkg, caller.w, caller.call, kind) + } + } +} + +func exportPrintfLike() interface{} { + return localPrintfLike +} // isPrint records the print functions. // If a key ends in 'f' then it is assumed to be a formatted print. var isPrint = map[string]bool{ - "fmt.Errorf": true, - "fmt.Fprint": true, - "fmt.Fprintf": true, - "fmt.Fprintln": true, - "fmt.Print": true, - "fmt.Printf": true, - "fmt.Println": true, - "fmt.Sprint": true, - "fmt.Sprintf": true, - "fmt.Sprintln": true, - "log.Fatal": true, - "log.Fatalf": true, - "log.Fatalln": true, - "log.Logger.Fatal": true, - "log.Logger.Fatalf": true, - "log.Logger.Fatalln": true, - "log.Logger.Panic": true, - "log.Logger.Panicf": true, - "log.Logger.Panicln": true, - "log.Logger.Printf": true, - "log.Logger.Println": true, - "log.Panic": true, - "log.Panicf": true, - "log.Panicln": true, - "log.Print": true, - "log.Printf": true, - "log.Println": true, - "testing.B.Error": true, - "testing.B.Errorf": true, - "testing.B.Fatal": true, - "testing.B.Fatalf": true, - "testing.B.Log": true, - "testing.B.Logf": true, - "testing.B.Skip": true, - "testing.B.Skipf": true, - "testing.T.Error": true, - "testing.T.Errorf": true, - "testing.T.Fatal": true, - "testing.T.Fatalf": true, - "testing.T.Log": true, - "testing.T.Logf": true, - "testing.T.Skip": true, - "testing.T.Skipf": true, - "testing.TB.Error": true, - "testing.TB.Errorf": true, - "testing.TB.Fatal": true, - "testing.TB.Fatalf": true, - "testing.TB.Log": true, - "testing.TB.Logf": true, - "testing.TB.Skip": true, - "testing.TB.Skipf": true, + "fmt.Errorf": true, + "fmt.Fprint": true, + "fmt.Fprintf": true, + "fmt.Fprintln": true, + "fmt.Print": true, + "fmt.Printf": true, + "fmt.Println": true, + "fmt.Sprint": true, + "fmt.Sprintf": true, + "fmt.Sprintln": true, + + // testing.B, testing.T not auto-detected + // because the methods are picked up by embedding. + "testing.B.Error": true, + "testing.B.Errorf": true, + "testing.B.Fatal": true, + "testing.B.Fatalf": true, + "testing.B.Log": true, + "testing.B.Logf": true, + "testing.B.Skip": true, + "testing.B.Skipf": true, + "testing.T.Error": true, + "testing.T.Errorf": true, + "testing.T.Fatal": true, + "testing.T.Fatalf": true, + "testing.T.Log": true, + "testing.T.Logf": true, + "testing.T.Skip": true, + "testing.T.Skipf": true, + + // testing.TB is an interface, so can't detect wrapping. + "testing.TB.Error": true, + "testing.TB.Errorf": true, + "testing.TB.Fatal": true, + "testing.TB.Fatalf": true, + "testing.TB.Log": true, + "testing.TB.Logf": true, + "testing.TB.Skip": true, + "testing.TB.Skipf": true, } // formatString returns the format string argument and its index within @@ -206,66 +381,84 @@ func checkFmtPrintfCall(f *File, node ast.Node) { } // Construct name like pkg.Printf or pkg.Type.Printf for lookup. - var name string - switch x := call.Fun.(type) { + _, name, kind := printfNameAndKind(f.pkg, call.Fun) + if kind == kindPrintf { + f.checkPrintf(call, name) + } + if kind == kindPrint { + f.checkPrint(call, name) + } +} + +func printfName(pkg *Package, called ast.Expr) (pkgpath, name string) { + switch x := called.(type) { case *ast.Ident: - if fn, ok := f.pkg.uses[x].(*types.Func); ok { - var pkg string - if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg { - pkg = vcfg.ImportPath + if fn, ok := pkg.uses[x].(*types.Func); ok { + if fn.Pkg() == nil || fn.Pkg() == pkg.typesPkg { + pkgpath = "" } else { - pkg = fn.Pkg().Path() + pkgpath = fn.Pkg().Path() } - name = pkg + "." + x.Name - break + return pkgpath, x.Name } case *ast.SelectorExpr: // Check for "fmt.Printf". if id, ok := x.X.(*ast.Ident); ok { - if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok { - name = pkgName.Imported().Path() + "." + x.Sel.Name - break + if pkgName, ok := pkg.uses[id].(*types.PkgName); ok { + return pkgName.Imported().Path(), x.Sel.Name } } // Check for t.Logf where t is a *testing.T. - if sel := f.pkg.selectors[x]; sel != nil { + if sel := pkg.selectors[x]; sel != nil { recv := sel.Recv() if p, ok := recv.(*types.Pointer); ok { recv = p.Elem() } if named, ok := recv.(*types.Named); ok { obj := named.Obj() - var pkg string - if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg { - pkg = vcfg.ImportPath + if obj.Pkg() == nil || obj.Pkg() == pkg.typesPkg { + pkgpath = "" } else { - pkg = obj.Pkg().Path() + pkgpath = obj.Pkg().Path() } - name = pkg + "." + obj.Name() + "." + x.Sel.Name - break + return pkgpath, obj.Name() + "." + x.Sel.Name } } } + return "", "" +} + +func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kind int) { + pkgpath, name = printfName(pkg, called) if name == "" { - return + return pkgpath, name, 0 } - shortName := name[strings.LastIndex(name, ".")+1:] - - _, ok = isPrint[name] - if !ok { - // Next look up just "printf", for use with -printfuncs. - _, ok = isPrint[strings.ToLower(shortName)] + if pkgpath == "" { + kind = localPrintfLike[name] + } else { + printfLike, _ := readVetx(pkgpath, "printf").(map[string]int) + kind = printfLike[name] } - if ok { - if strings.HasSuffix(name, "f") { - f.checkPrintf(call, shortName) - } else { - f.checkPrint(call, shortName) + + if kind == 0 { + _, ok := isPrint[pkgpath+"."+name] + if !ok { + // Next look up just "printf", for use with -printfuncs. + short := name[strings.LastIndex(name, ".")+1:] + _, ok = isPrint[strings.ToLower(short)] + } + if ok { + if strings.HasSuffix(name, "f") { + kind = kindPrintf + } else { + kind = kindPrint + } } } + return pkgpath, name, kind } // isStringer returns true if the provided declaration is a "String() string" diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index 34f4e2865a..16f46a4897 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -14,6 +14,7 @@ package testdata import ( "fmt" . "fmt" + logpkg "log" // renamed to make it harder to see "math" "os" "testing" @@ -175,6 +176,18 @@ func PrintfTests() { f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args" f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r" f.Warnf(0, "%#s", "hello") // ERROR "Warnf format %#s has unrecognized flag #" + f.Warn2(0, "%s", "hello", 3) // ERROR "Warn2 call has possible formatting directive %s" + f.Warnf2(0, "%s", "hello", 3) // ERROR "Warnf2 call needs 1 arg but has 2 args" + f.Warnf2(0, "%r", "hello") // ERROR "Warnf2 format %r has unknown verb r" + f.Warnf2(0, "%#s", "hello") // ERROR "Warnf2 format %#s has unrecognized flag #" + f.Wrap(0, "%s", "hello", 3) // ERROR "Wrap call has possible formatting directive %s" + f.Wrapf(0, "%s", "hello", 3) // ERROR "Wrapf call needs 1 arg but has 2 args" + f.Wrapf(0, "%r", "hello") // ERROR "Wrapf format %r has unknown verb r" + f.Wrapf(0, "%#s", "hello") // ERROR "Wrapf format %#s has unrecognized flag #" + f.Wrap2(0, "%s", "hello", 3) // ERROR "Wrap2 call has possible formatting directive %s" + f.Wrapf2(0, "%s", "hello", 3) // ERROR "Wrapf2 call needs 1 arg but has 2 args" + f.Wrapf2(0, "%r", "hello") // ERROR "Wrapf2 format %r has unknown verb r" + f.Wrapf2(0, "%#s", "hello") // ERROR "Wrapf2 format %#s has unrecognized flag #" fmt.Printf("%#s", FormatterVal(true)) // correct (the type is responsible for formatting) Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string" Printf("%d", percentDV) @@ -283,6 +296,28 @@ func PrintfTests() { Printf(someString(), "hello") // OK + // Printf wrappers in package log should be detected automatically + logpkg.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d" + logpkg.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string" + logpkg.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d" + logpkg.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d" + logpkg.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string" + logpkg.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d" + logpkg.Print("%d", 1) // ERROR "Print call has possible formatting directive %d" + logpkg.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string" + logpkg.Println("%d", 1) // ERROR "Println call has possible formatting directive %d" + + // Methods too. + var l *logpkg.Logger + l.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d" + l.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string" + l.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d" + l.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d" + l.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string" + l.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d" + l.Print("%d", 1) // ERROR "Print call has possible formatting directive %d" + l.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string" + l.Println("%d", 1) // ERROR "Println call has possible formatting directive %d" } func someString() string { return "X" } @@ -368,14 +403,46 @@ func (*ptrStringer) String() string { return "string" } -func (*ptrStringer) Warn(int, ...interface{}) string { +func (p *ptrStringer) Warn2(x int, args ...interface{}) string { + return p.Warn(x, args...) +} + +func (p *ptrStringer) Warnf2(x int, format string, args ...interface{}) string { + return p.Warnf(x, format, args...) +} + +func (*ptrStringer) Warn(x int, args ...interface{}) string { return "warn" } -func (*ptrStringer) Warnf(int, string, ...interface{}) string { +func (*ptrStringer) Warnf(x int, format string, args ...interface{}) string { return "warnf" } +func (p *ptrStringer) Wrap2(x int, args ...interface{}) string { + return p.Wrap(x, args...) +} + +func (p *ptrStringer) Wrapf2(x int, format string, args ...interface{}) string { + return p.Wrapf(x, format, args...) +} + +func (*ptrStringer) Wrap(x int, args ...interface{}) string { + return fmt.Sprint(args...) +} + +func (*ptrStringer) Wrapf(x int, format string, args ...interface{}) string { + return fmt.Sprintf(format, args...) +} + +func (*ptrStringer) BadWrap(x int, args ...interface{}) string { + return fmt.Sprint(args) // ERROR "missing ... in args forwarded to print-like function" +} + +func (*ptrStringer) BadWrapf(x int, format string, args ...interface{}) string { + return fmt.Sprintf(format, args) // ERROR "missing ... in args forwarded to printf-like function" +} + type embeddedStringer struct { foo string ptrStringer From 6b3e3434086133ecba3fa8cc45bf7cca88c64cdb Mon Sep 17 00:00:00 2001 From: Joe Cortopassi Date: Mon, 30 Apr 2018 22:32:33 +0000 Subject: [PATCH 024/203] doc: remove GOROOT custom install instruction Setting GOROOT is no longer necessary for custom installation as of 1.10 (reference: https://go-review.googlesource.com/c/go/+/42533). Fixes #25002 Change-Id: Ic3980833ac437b7a20b951df33805ad1071a40ce GitHub-Last-Rev: 156bf6510a21266bfb8397e564635278aa3bb1e5 GitHub-Pull-Request: golang/go#25190 Reviewed-on: https://go-review.googlesource.com/110435 Reviewed-by: Ian Lance Taylor --- doc/install.html | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/doc/install.html b/doc/install.html index ee1516ac47..f3b3f97fb8 100644 --- a/doc/install.html +++ b/doc/install.html @@ -114,31 +114,6 @@ or execute them from the profile using a command such as source $HOME/.profile.

-

Installing to a custom location

- -

-The Go binary distributions assume they will be installed in -/usr/local/go (or c:\Go under Windows), -but it is possible to install the Go tools to a different location. -In this case you must set the GOROOT environment variable -to point to the directory in which it was installed. -

- -

-For example, if you installed Go to your home directory you should add -commands like the following to $HOME/.profile: -

- -
-export GOROOT=$HOME/go1.X
-export PATH=$PATH:$GOROOT/bin
-
- -

-Note: GOROOT must be set only when installing to a custom -location. -

-
From 9ef9765c168c8561b98dc41c25eb8ae83abfcd7a Mon Sep 17 00:00:00 2001 From: Suriyaa Sundararuban Date: Tue, 12 Jun 2018 09:40:24 +0000 Subject: [PATCH 025/203] .github: use HTTPS for Stack Overflow link in SUPPORT.md Change-Id: I4e339b7c359a7cdb0933f7624ce190086c9c3599 Reviewed-on: https://go-review.googlesource.com/118155 Reviewed-by: Tobias Klauser --- .github/SUPPORT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md index 9a4d7b2759..23fec84fb6 100644 --- a/.github/SUPPORT.md +++ b/.github/SUPPORT.md @@ -9,6 +9,6 @@ For asking questions, see: * [Gophers Slack](https://gophers.slack.com), use the [invite app](https://invite.slack.golangbridge.org/) for access -* [Stack Overflow](http://stackoverflow.com/questions/tagged/go) with questions tagged "go" +* [Stack Overflow](https://stackoverflow.com/questions/tagged/go) with questions tagged "go" * **IRC** channel #go-nuts on Freenode From 29b631e6f4fb3729cf4b369bcf47316f0d426845 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 11 Jun 2018 14:41:58 +0200 Subject: [PATCH 026/203] net: update file read position after sendfile syscall On dragonfly, freebsd and solaris the sendfile syscall does not update the read position of the source fd. Update it after sendfile so successive calls start at the correct position. Fixes #25809 Change-Id: Iaac79f89704b75b8038d4bb60eaf793a262cdd8f Reviewed-on: https://go-review.googlesource.com/117895 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/sendfile_test.go | 6 ------ src/net/sendfile_unix_alt.go | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index acf1cd9955..ecc00d3c2a 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -13,7 +13,6 @@ import ( "fmt" "io" "os" - "runtime" "testing" ) @@ -94,11 +93,6 @@ func TestSendfile(t *testing.T) { } func TestSendfileParts(t *testing.T) { - switch runtime.GOOS { - case "dragonfly", "freebsd", "solaris": - t.Skipf("skipping on %s (see golang.org/issue/25809 for details)", runtime.GOOS) - } - ln, err := newLocalListener("tcp") if err != nil { t.Fatal(err) diff --git a/src/net/sendfile_unix_alt.go b/src/net/sendfile_unix_alt.go index 97aeebbed2..9b3ba4ee62 100644 --- a/src/net/sendfile_unix_alt.go +++ b/src/net/sendfile_unix_alt.go @@ -63,5 +63,11 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { if lr != nil { lr.N = remain - written } + + _, err1 := f.Seek(written, io.SeekCurrent) + if err1 != nil && err == nil { + return written, err1, written > 0 + } + return written, wrapSyscallError("sendfile", err), written > 0 } From d88b13786d3f1645ee59c2be555cb18cf49fe2e5 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 6 Jun 2018 22:50:01 +0000 Subject: [PATCH 027/203] net/http, net/http/httptrace: make Transport support 1xx responses properly Previously the Transport had good support for 100 Continue responses, but other 1xx informational responses were returned as-is. But per https://tools.ietf.org/html/rfc7231#section-6.2: > A client MUST be able to parse one or more 1xx responses received > prior to a final response, even if the client does not expect one. A > user agent MAY ignore unexpected 1xx responses. We weren't doing that. Instead, we were returning any 1xx that wasn't 100 as the final result. With this change we instead loop over up to 5 (arbitrary) 1xx responses until we find the final one, returning an error if there's more than 5. The limit is just there to guard against malicious servers and to have _some_ limit. By default we ignore the 1xx responses, unless the user defines the new httptrace.ClientTrace.Got1xxResponse hook, which is an expanded version of the previous ClientTrace.Got100Continue. Still remaining: * httputil.ReverseProxy work. (From rfc7231#section-6.2: "A proxy MUST forward 1xx responses unless the proxy itself requested the generation of the 1xx response."). Which would require: * Support for an http.Handler to generate 1xx informational responses. Those can happen later. Fixing the Transport to be resilient to others using 1xx in the future without negotiation (as is being discussed with HTTP status 103) is most important for now. Updates #17739 Change-Id: I55aae8cd978164643fccb9862cd60a230e430486 Reviewed-on: https://go-review.googlesource.com/116855 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/go/build/deps_test.go | 2 +- src/net/http/httptrace/trace.go | 7 ++++ src/net/http/transport.go | 49 ++++++++++++++++-------- src/net/http/transport_test.go | 68 ++++++++++++++++++++++++++++++--- 4 files changed, 103 insertions(+), 23 deletions(-) diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 67d1115017..9d667b6107 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -416,7 +416,7 @@ var pkgDeps = map[string][]string{ "syscall/js", }, "net/http/internal": {"L4"}, - "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"}, + "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "net/textproto", "reflect", "time"}, // HTTP-using packages. "expvar": {"L4", "OS", "encoding/json", "net/http"}, diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go index ea7b38c8fc..8033535670 100644 --- a/src/net/http/httptrace/trace.go +++ b/src/net/http/httptrace/trace.go @@ -11,6 +11,7 @@ import ( "crypto/tls" "internal/nettrace" "net" + "net/textproto" "reflect" "time" ) @@ -107,6 +108,12 @@ type ClientTrace struct { // Continue" response. Got100Continue func() + // Got1xxResponse is called for each 1xx informational response header + // returned before the final non-1xx response. Got1xxResponse is called + // for "100 Continue" responses, even if Got100Continue is also defined. + // If it returns an error, the client request is aborted with that error value. + Got1xxResponse func(code int, header textproto.MIMEHeader) error + // DNSStart is called when a DNS lookup begins. DNSStart func(DNSStartInfo) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 3890f19af3..9b5ea52c9b 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -21,6 +21,7 @@ import ( "log" "net" "net/http/httptrace" + "net/textproto" "net/url" "os" "strings" @@ -1641,26 +1642,42 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr trace.GotFirstResponseByte() } } - resp, err = ReadResponse(pc.br, rc.req) - if err != nil { - return - } - if rc.continueCh != nil { - if resp.StatusCode == 100 { - if trace != nil && trace.Got100Continue != nil { - trace.Got100Continue() - } - rc.continueCh <- struct{}{} - } else { - close(rc.continueCh) - } - } - if resp.StatusCode == 100 { - pc.readLimit = pc.maxHeaderResponseSize() // reset the limit + num1xx := 0 // number of informational 1xx headers received + const max1xxResponses = 5 // arbitrary bound on number of informational responses + + continueCh := rc.continueCh + for { resp, err = ReadResponse(pc.br, rc.req) if err != nil { return } + resCode := resp.StatusCode + if continueCh != nil { + if resCode == 100 { + if trace != nil && trace.Got100Continue != nil { + trace.Got100Continue() + } + continueCh <- struct{}{} + continueCh = nil + } else if resCode >= 200 { + close(continueCh) + continueCh = nil + } + } + if 100 <= resCode && resCode <= 199 { + num1xx++ + if num1xx > max1xxResponses { + return nil, errors.New("net/http: too many 1xx informational responses") + } + pc.readLimit = pc.maxHeaderResponseSize() // reset the limit + if trace != nil && trace.Got1xxResponse != nil { + if err := trace.Got1xxResponse(resCode, textproto.MIMEHeader(resp.Header)); err != nil { + return nil, err + } + } + continue + } + break } resp.TLS = pc.tlsState return diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 57309bbac1..01a209c633 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -31,6 +31,7 @@ import ( "net/http/httptrace" "net/http/httputil" "net/http/internal" + "net/textproto" "net/url" "os" "reflect" @@ -2287,6 +2288,7 @@ Content-Length: %d c := &Client{Transport: tr} testResponse := func(req *Request, name string, wantCode int) { + t.Helper() res, err := c.Do(req) if err != nil { t.Fatalf("%s: Do: %v", name, err) @@ -2309,13 +2311,67 @@ Content-Length: %d req.Header.Set("Request-Id", reqID(i)) testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200) } +} - // And some other informational 1xx but non-100 responses, to test - // we return them but don't re-use the connection. - for i := 1; i <= numReqs; i++ { - req, _ := NewRequest("POST", "http://other.tld/", strings.NewReader(reqBody(i))) - req.Header.Set("X-Want-Response-Code", "123 Sesame Street") - testResponse(req, fmt.Sprintf("123, %d/%d", i, numReqs), 123) +// Issue 17739: the HTTP client must ignore any unknown 1xx +// informational responses before the actual response. +func TestTransportIgnore1xxResponses(t *testing.T) { + setParallel(t) + defer afterTest(t) + cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { + conn, buf, _ := w.(Hijacker).Hijack() + buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\nFoo: bar\r\n\r\nHTTP/1.1 200 OK\r\nBar: baz\r\nContent-Length: 5\r\n\r\nHello")) + buf.Flush() + conn.Close() + })) + defer cst.close() + cst.tr.DisableKeepAlives = true // prevent log spam; our test server is hanging up anyway + + var got bytes.Buffer + + req, _ := NewRequest("GET", cst.ts.URL, nil) + req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ + Got1xxResponse: func(code int, header textproto.MIMEHeader) error { + fmt.Fprintf(&got, "1xx: code=%v, header=%v\n", code, header) + return nil + }, + })) + res, err := cst.c.Do(req) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + res.Write(&got) + want := "1xx: code=123, header=map[Foo:[bar]]\nHTTP/1.1 200 OK\r\nContent-Length: 5\r\nBar: baz\r\n\r\nHello" + if got.String() != want { + t.Errorf(" got: %q\nwant: %q\n", got.Bytes(), want) + } +} + +func TestTransportLimits1xxResponses(t *testing.T) { + setParallel(t) + defer afterTest(t) + cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { + conn, buf, _ := w.(Hijacker).Hijack() + for i := 0; i < 10; i++ { + buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\n\r\n")) + } + buf.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n")) + buf.Flush() + conn.Close() + })) + defer cst.close() + cst.tr.DisableKeepAlives = true // prevent log spam; our test server is hanging up anyway + + res, err := cst.c.Get(cst.ts.URL) + if res != nil { + defer res.Body.Close() + } + got := fmt.Sprint(err) + wantSub := "too many 1xx informational responses" + if !strings.Contains(got, wantSub) { + t.Errorf("Get error = %v; want substring %q", err, wantSub) } } From 33d058308f036ff02c76ace5c08860149e80775f Mon Sep 17 00:00:00 2001 From: Suriyaa Sundararuban Date: Tue, 12 Jun 2018 12:17:51 +0000 Subject: [PATCH 028/203] doc: use HTTPS for clang.llvm.org link in go1.6.html Change-Id: I67aac387359378cf7aa8f7cafa6557ebf1338baf Reviewed-on: https://go-review.googlesource.com/118176 Reviewed-by: Brad Fitzpatrick --- doc/go1.6.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.6.html b/doc/go1.6.html index 9594736e65..902a82d517 100644 --- a/doc/go1.6.html +++ b/doc/go1.6.html @@ -116,7 +116,7 @@ instead of generated from yacc.

The compiler, linker, and go command have a new flag -msan, analogous to -race and only available on linux/amd64, -that enables interoperation with the Clang MemorySanitizer. +that enables interoperation with the Clang MemorySanitizer. Such interoperation is useful mainly for testing a program containing suspect C or C++ code.

From 43a3cdf8c7ce08b5351cd4e8823c00f1fb125188 Mon Sep 17 00:00:00 2001 From: Suriyaa Sundararuban Date: Tue, 12 Jun 2018 12:11:58 +0000 Subject: [PATCH 029/203] doc: use HTTPS for man.openbsd.org link in go1.7.html Change-Id: I88855dfa3166e90386c90bf6220be0596dab3c0d Reviewed-on: https://go-review.googlesource.com/118175 Reviewed-by: Brad Fitzpatrick --- doc/go1.7.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/go1.7.html b/doc/go1.7.html index 2b0f01d8fb..db60702776 100644 --- a/doc/go1.7.html +++ b/doc/go1.7.html @@ -89,7 +89,7 @@ POWER5 architecture.

-The OpenBSD port now requires OpenBSD 5.6 or later, for access to the getentropy(2) system call. +The OpenBSD port now requires OpenBSD 5.6 or later, for access to the getentropy(2) system call.

Known Issues

From f027d1a8782387fb7e354054a669a202524335e4 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 12 Jun 2018 11:10:49 +0200 Subject: [PATCH 030/203] runtime: convert a darwin/arm64 syscall to libc Change-Id: I5704a07375fc672ac70c1f4e8df6f4fff760b4bf Reviewed-on: https://go-review.googlesource.com/118117 Run-TryBot: Elias Naur TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/runtime/rt0_darwin_arm64.s | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s index 960de06044..719944e626 100644 --- a/src/runtime/rt0_darwin_arm64.s +++ b/src/runtime/rt0_darwin_arm64.s @@ -8,8 +8,7 @@ // supports external linking. TEXT _rt0_arm64_darwin(SB),NOSPLIT|NOFRAME,$0 MOVD $42, R0 - MOVD $1, R16 // SYS_exit - SVC $0x80 + BL libc_exit(SB) // When linking with -buildmode=c-archive or -buildmode=c-shared, // this symbol is called from a global initialization function. From adeb7e640b04526c38c481aff85b923ca14fc92b Mon Sep 17 00:00:00 2001 From: Thomas Wanielista Date: Fri, 22 Dec 2017 16:17:56 -0500 Subject: [PATCH 031/203] go/doc: classify function returning slice or array of T as constructor Previously, go/doc would only consider functions and slices that return types of T or any number of pointers to T: *T, **T, etc. This change expands the definition of a constructor to include functions that return arrays of a type (or pointer to that type) in its first return. With this change, the following return types also classify a function as a constructor of type T: [1]T [1]*T [1]**T (and so on) Fixes #22856. Change-Id: I37957c5f2d6a7b2ceeb3fbaef359057f2039393d Reviewed-on: https://go-review.googlesource.com/85355 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/go/doc/reader.go | 6 +++--- ...issue18063.0.golden => issue22856.0.golden} | 18 +++++++++--------- ...issue18063.1.golden => issue22856.1.golden} | 18 +++++++++--------- ...issue18063.2.golden => issue22856.2.golden} | 18 +++++++++--------- .../testdata/{issue18063.go => issue22856.go} | 12 +++--------- 5 files changed, 33 insertions(+), 39 deletions(-) rename src/go/doc/testdata/{issue18063.0.golden => issue22856.0.golden} (73%) rename src/go/doc/testdata/{issue18063.1.golden => issue22856.1.golden} (73%) rename src/go/doc/testdata/{issue18063.2.golden => issue22856.2.golden} (73%) rename src/go/doc/testdata/{issue18063.go => issue22856.go} (74%) diff --git a/src/go/doc/reader.go b/src/go/doc/reader.go index 5d6f6e8fb0..05c3786ef6 100644 --- a/src/go/doc/reader.go +++ b/src/go/doc/reader.go @@ -399,9 +399,9 @@ func (r *reader) readFunc(fun *ast.FuncDecl) { // with the first type in result signature (there may // be more than one result) factoryType := res.Type - if t, ok := factoryType.(*ast.ArrayType); ok && t.Len == nil { - // We consider functions that return slices of type T (or - // pointers to T) as factory functions of T. + if t, ok := factoryType.(*ast.ArrayType); ok { + // We consider functions that return slices or arrays of type + // T (or pointers to T) as factory functions of T. factoryType = t.Elt } if n, imp := baseTypeName(factoryType); !imp && r.isVisible(n) { diff --git a/src/go/doc/testdata/issue18063.0.golden b/src/go/doc/testdata/issue22856.0.golden similarity index 73% rename from src/go/doc/testdata/issue18063.0.golden rename to src/go/doc/testdata/issue22856.0.golden index 0afbc169c2..a88f43f4bd 100644 --- a/src/go/doc/testdata/issue18063.0.golden +++ b/src/go/doc/testdata/issue22856.0.golden @@ -1,19 +1,13 @@ // -PACKAGE issue18063 +PACKAGE issue22856 IMPORTPATH - testdata/issue18063 + testdata/issue22856 FILENAMES - testdata/issue18063.go + testdata/issue22856.go FUNCTIONS - // NewArray is not a factory function because arrays of type T are ... - func NewArray() [1]T - - // NewPointerArray is not a factory function because arrays of ... - func NewPointerArray() [1]*T - // NewPointerSliceOfSlice is not a factory function because slices ... func NewPointerSliceOfSlice() [][]*T @@ -31,9 +25,15 @@ TYPES // func New() T + // + func NewArray() [1]T + // func NewPointer() *T + // + func NewPointerArray() [1]*T + // func NewPointerOfPointer() **T diff --git a/src/go/doc/testdata/issue18063.1.golden b/src/go/doc/testdata/issue22856.1.golden similarity index 73% rename from src/go/doc/testdata/issue18063.1.golden rename to src/go/doc/testdata/issue22856.1.golden index 0afbc169c2..a88f43f4bd 100644 --- a/src/go/doc/testdata/issue18063.1.golden +++ b/src/go/doc/testdata/issue22856.1.golden @@ -1,19 +1,13 @@ // -PACKAGE issue18063 +PACKAGE issue22856 IMPORTPATH - testdata/issue18063 + testdata/issue22856 FILENAMES - testdata/issue18063.go + testdata/issue22856.go FUNCTIONS - // NewArray is not a factory function because arrays of type T are ... - func NewArray() [1]T - - // NewPointerArray is not a factory function because arrays of ... - func NewPointerArray() [1]*T - // NewPointerSliceOfSlice is not a factory function because slices ... func NewPointerSliceOfSlice() [][]*T @@ -31,9 +25,15 @@ TYPES // func New() T + // + func NewArray() [1]T + // func NewPointer() *T + // + func NewPointerArray() [1]*T + // func NewPointerOfPointer() **T diff --git a/src/go/doc/testdata/issue18063.2.golden b/src/go/doc/testdata/issue22856.2.golden similarity index 73% rename from src/go/doc/testdata/issue18063.2.golden rename to src/go/doc/testdata/issue22856.2.golden index 0afbc169c2..a88f43f4bd 100644 --- a/src/go/doc/testdata/issue18063.2.golden +++ b/src/go/doc/testdata/issue22856.2.golden @@ -1,19 +1,13 @@ // -PACKAGE issue18063 +PACKAGE issue22856 IMPORTPATH - testdata/issue18063 + testdata/issue22856 FILENAMES - testdata/issue18063.go + testdata/issue22856.go FUNCTIONS - // NewArray is not a factory function because arrays of type T are ... - func NewArray() [1]T - - // NewPointerArray is not a factory function because arrays of ... - func NewPointerArray() [1]*T - // NewPointerSliceOfSlice is not a factory function because slices ... func NewPointerSliceOfSlice() [][]*T @@ -31,9 +25,15 @@ TYPES // func New() T + // + func NewArray() [1]T + // func NewPointer() *T + // + func NewPointerArray() [1]*T + // func NewPointerOfPointer() **T diff --git a/src/go/doc/testdata/issue18063.go b/src/go/doc/testdata/issue22856.go similarity index 74% rename from src/go/doc/testdata/issue18063.go rename to src/go/doc/testdata/issue22856.go index 1193af51e7..f4569981aa 100644 --- a/src/go/doc/testdata/issue18063.go +++ b/src/go/doc/testdata/issue22856.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package issue18063 +package issue22856 type T struct{} @@ -11,14 +11,8 @@ func NewPointer() *T { return &T{} } func NewPointerSlice() []*T { return []*T{&T{}} } func NewSlice() []T { return []T{T{}} } func NewPointerOfPointer() **T { x := &T{}; return &x } - -// NewArray is not a factory function because arrays of type T are not -// factory functions of type T. -func NewArray() [1]T { return [1]T{T{}} } - -// NewPointerArray is not a factory function because arrays of type *T are not -// factory functions of type T. -func NewPointerArray() [1]*T { return [1]*T{&T{}} } +func NewArray() [1]T { return [1]T{T{}} } +func NewPointerArray() [1]*T { return [1]*T{&T{}} } // NewSliceOfSlice is not a factory function because slices of a slice of // type *T are not factory functions of type T. From ec989337c5d3203d52de1a2314813996c711fce6 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 20 May 2018 08:57:53 -0700 Subject: [PATCH 032/203] runtime: use libc's signal functions on Darwin sigaction, sigprocmask, sigaltstack, and raiseproc. Fix bug in mstart_stub where we weren't saving callee-saved registers, so if an m finished the pthread library calling mstart_stub would sometimes fail. Update #17490 Update #22805 Change-Id: Ie297ede0997910aa956834e49e85711b90cdfaa7 Reviewed-on: https://go-review.googlesource.com/116875 Run-TryBot: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- src/runtime/defs_darwin.go | 1 + src/runtime/os_darwin.go | 29 ++----- src/runtime/sys_darwin.go | 40 +++++++++ src/runtime/sys_darwin_386.s | 151 ++++++++++++++++++++++----------- src/runtime/sys_darwin_amd64.s | 139 +++++++++++++++++++----------- 5 files changed, 243 insertions(+), 117 deletions(-) diff --git a/src/runtime/defs_darwin.go b/src/runtime/defs_darwin.go index e3a25c5312..92f7822796 100644 --- a/src/runtime/defs_darwin.go +++ b/src/runtime/defs_darwin.go @@ -158,6 +158,7 @@ type Sighandler C.union___sigaction_u type Sigaction C.struct___sigaction // used in syscalls type Usigaction C.struct_sigaction // used by sigaction second argument +type Sigset C.sigset_t type Sigval C.union_sigval type Siginfo C.siginfo_t type Timeval C.struct_timeval diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 55f938cd80..cf57cc9020 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -206,7 +206,6 @@ func mpreinit(mp *m) { func minit() { // The alternate signal stack is buggy on arm and arm64. // The signal handler handles it directly. - // The sigaltstack assembly function does nothing. if GOARCH != "arm" && GOARCH != "arm64" { minitSignalStack() } @@ -499,24 +498,9 @@ const ( _SS_DISABLE = 4 ) -//go:noescape -func sigprocmask(how int32, new, old *sigset) - -//go:noescape -func sigaction(mode uint32, new *sigactiont, old *usigactiont) - -//go:noescape -func sigaltstack(new, old *stackt) - -// darwin/arm64 uses registers instead of stack-based arguments. -// TODO: does this matter? -func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer) - //go:noescape func setitimer(mode int32, new, old *itimerval) -func raiseproc(sig uint32) - //extern SigTabTT runtime·sigtab[]; type sigset uint32 @@ -526,14 +510,20 @@ var sigset_all = ^sigset(0) //go:nosplit //go:nowritebarrierrec func setsig(i uint32, fn uintptr) { - var sa sigactiont + var sa usigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = ^uint32(0) - sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler + if fn == funcPC(sighandler) { + fn = funcPC(sigtramp) + } *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn sigaction(i, &sa, nil) } +// sigtramp is the callback from libc when a signal is received. +// It is called with the C calling convention. +func sigtramp() + //go:nosplit //go:nowritebarrierrec func setsigstack(i uint32) { @@ -543,9 +533,8 @@ func setsigstack(i uint32) { if osa.sa_flags&_SA_ONSTACK != 0 { return } - var sa sigactiont + var sa usigactiont *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler - sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) sa.sa_mask = osa.sa_mask sa.sa_flags = osa.sa_flags | _SA_ONSTACK sigaction(i, &sa, nil) diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index d8b5441b31..7b4e927b36 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -179,6 +179,41 @@ func walltime() (int64, int32) { } func walltime_trampoline() +//go:nosplit +//go:cgo_unsafe_args +func sigaction(sig uint32, new *usigactiont, old *usigactiont) { + asmcgocall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig)) +} +func sigaction_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func sigprocmask(how uint32, new *sigset, old *sigset) { + asmcgocall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how)) +} +func sigprocmask_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func sigaltstack(new *stackt, old *stackt) { + if new != nil && new.ss_flags&_SS_DISABLE != 0 && new.ss_size == 0 { + // Despite the fact that Darwin's sigaltstack man page says it ignores the size + // when SS_DISABLE is set, it doesn't. sigaltstack returns ENOMEM + // if we don't give it a reasonable size. + // ref: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20140421/214296.html + new.ss_size = 32768 + } + asmcgocall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new)) +} +func sigaltstack_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func raiseproc(sig uint32) { + asmcgocall(unsafe.Pointer(funcPC(raiseproc_trampoline)), unsafe.Pointer(&sig)) +} +func raiseproc_trampoline() + // Not used on Darwin, but must be defined. func exitThread(wait *uint32) { } @@ -207,6 +242,11 @@ func exitThread(wait *uint32) { //go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" // Magic incantation to get libSystem actually dynamically linked. // TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210 diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s index 5b29dfe604..cb60d070b5 100644 --- a/src/runtime/sys_darwin_386.s +++ b/src/runtime/sys_darwin_386.s @@ -84,17 +84,6 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0 POPL BP RET -TEXT runtime·raiseproc(SB),NOSPLIT,$16 - MOVL $20, AX // getpid - INT $0x80 - MOVL AX, 4(SP) // pid - MOVL sig+0(FP), AX - MOVL AX, 8(SP) // signal - MOVL $1, 12(SP) // posix - MOVL $37, AX // kill - INT $0x80 - RET - TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 PUSHL BP MOVL SP, BP @@ -211,18 +200,73 @@ initialized: POPL BP RET -TEXT runtime·sigprocmask(SB),NOSPLIT,$0 - MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process) - INT $0x80 - JAE 2(PC) +TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $24, SP + MOVL 32(SP), CX + MOVL 0(CX), AX // arg 1 sig + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 new + MOVL AX, 4(SP) + MOVL 8(CX), AX // arg 3 old + MOVL AX, 8(SP) + CALL libc_sigaction(SB) + TESTL AX, AX + JEQ 2(PC) MOVL $0xf1, 0xf1 // crash + MOVL BP, SP + POPL BP RET -TEXT runtime·sigaction(SB),NOSPLIT,$0 - MOVL $46, AX - INT $0x80 - JAE 2(PC) +TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $24, SP + MOVL 32(SP), CX + MOVL 0(CX), AX // arg 1 how + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 new + MOVL AX, 4(SP) + MOVL 8(CX), AX // arg 3 old + MOVL AX, 8(SP) + CALL libc_pthread_sigmask(SB) + TESTL AX, AX + JEQ 2(PC) MOVL $0xf1, 0xf1 // crash + MOVL BP, SP + POPL BP + RET + +TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $8, SP + MOVL 16(SP), CX + MOVL 0(CX), AX // arg 1 new + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 old + MOVL AX, 4(SP) + CALL libc_sigaltstack(SB) + TESTL AX, AX + JEQ 2(PC) + MOVL $0xf1, 0xf1 // crash + MOVL BP, SP + POPL BP + RET + +TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $8, SP + CALL libc_getpid(SB) + MOVL AX, 0(SP) // arg 1 pid + MOVL 16(SP), CX + MOVL 0(CX), AX + MOVL AX, 4(SP) // arg 2 signal + CALL libc_kill(SB) + MOVL BP, SP + POPL BP RET TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 @@ -243,38 +287,32 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 RET // Sigtramp's job is to call the actual signal handler. -// It is called with the following arguments on the stack: -// 0(SP) "return address" - ignored -// 4(SP) actual handler -// 8(SP) siginfo style -// 12(SP) signal number -// 16(SP) siginfo -// 20(SP) context -TEXT runtime·sigtramp(SB),NOSPLIT,$20 - MOVL sig+8(FP), BX - MOVL BX, 0(SP) - MOVL info+12(FP), BX - MOVL BX, 4(SP) - MOVL ctx+16(FP), BX - MOVL BX, 8(SP) +// It is called with the C calling convention, and calls out +// to sigtrampgo with the Go calling convention. +TEXT runtime·sigtramp(SB),NOSPLIT,$0 + SUBL $28, SP + + // Save callee-save registers. + MOVL BP, 12(SP) + MOVL BX, 16(SP) + MOVL SI, 20(SP) + MOVL DI, 24(SP) + + MOVL 32(SP), AX + MOVL AX, 0(SP) // arg 1 signal number + MOVL 36(SP), AX + MOVL AX, 4(SP) // arg 2 siginfo + MOVL 40(SP), AX + MOVL AX, 8(SP) // arg 3 ctxt CALL runtime·sigtrampgo(SB) - // call sigreturn - MOVL ctx+16(FP), CX - MOVL infostyle+4(FP), BX - MOVL $0, 0(SP) // "caller PC" - ignored - MOVL CX, 4(SP) - MOVL BX, 8(SP) - MOVL $184, AX // sigreturn(ucontext, infostyle) - INT $0x80 - MOVL $0xf1, 0xf1 // crash - RET + // Restore callee-save registers. + MOVL 12(SP), BP + MOVL 16(SP), BX + MOVL 20(SP), SI + MOVL 24(SP), DI -TEXT runtime·sigaltstack(SB),NOSPLIT,$0 - MOVL $53, AX - INT $0x80 - JAE 2(PC) - MOVL $0xf1, 0xf1 // crash + ADDL $28, SP RET TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 @@ -409,8 +447,15 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 // The value at SP+4 points to the m. // We are already on m's g0 stack. + // Save callee-save registers. + SUBL $16, SP + MOVL BP, 0(SP) + MOVL BX, 4(SP) + MOVL SI, 8(SP) + MOVL DI, 12(SP) + MOVL SP, AX // hide argument read from vet (vet thinks this function is using the Go calling convention) - MOVL 4(AX), DI // m + MOVL 20(AX), DI // m MOVL m_g0(DI), DX // g // Initialize TLS entry. @@ -422,10 +467,18 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 CALL runtime·mstart(SB) + // Restore callee-save registers. + MOVL 0(SP), BP + MOVL 4(SP), BX + MOVL 8(SP), SI + MOVL 12(SP), DI + // Go is all done with this OS thread. // Tell pthread everything is ok (we never join with this thread, so // the value here doesn't really matter). XORL AX, AX + + ADDL $16, SP RET TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0 diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index 320d56499a..b52e0b52cd 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -63,16 +63,6 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·raiseproc(SB),NOSPLIT,$24 - MOVL $(0x2000000+20), AX // getpid - SYSCALL - MOVQ AX, DI // arg 1 - pid - MOVL sig+0(FP), SI // arg 2 - signal - MOVL $1, DX // arg 3 - posix - MOVL $(0x2000000+37), AX // kill - SYSCALL - RET - TEXT runtime·setitimer(SB), NOSPLIT, $0 MOVL mode+0(FP), DI MOVQ new+8(FP), SI @@ -132,26 +122,53 @@ TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·sigprocmask(SB),NOSPLIT,$0 - MOVL how+0(FP), DI - MOVQ new+8(FP), SI - MOVQ old+16(FP), DX - MOVL $(0x2000000+329), AX // pthread_sigmask (on OS X, sigprocmask==entire process) - SYSCALL - JCC 2(PC) +TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVQ 8(DI), SI // arg 2 new + MOVQ 16(DI), DX // arg 3 old + MOVL 0(DI), DI // arg 1 sig + CALL libc_sigaction(SB) + TESTL AX, AX + JEQ 2(PC) MOVL $0xf1, 0xf1 // crash + POPQ BP RET -TEXT runtime·sigaction(SB),NOSPLIT,$0-24 - MOVL mode+0(FP), DI // arg 1 sig - MOVQ new+8(FP), SI // arg 2 act - MOVQ old+16(FP), DX // arg 3 oact - MOVQ old+16(FP), CX // arg 3 oact - MOVQ old+16(FP), R10 // arg 3 oact - MOVL $(0x2000000+46), AX // syscall entry - SYSCALL - JCC 2(PC) +TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVQ 8(DI), SI // arg 2 new + MOVQ 16(DI), DX // arg 3 old + MOVL 0(DI), DI // arg 1 how + CALL libc_pthread_sigmask(SB) + TESTL AX, AX + JEQ 2(PC) MOVL $0xf1, 0xf1 // crash + POPQ BP + RET + +TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVQ 8(DI), SI // arg 2 old + MOVQ 0(DI), DI // arg 1 new + CALL libc_sigaltstack(SB) + TESTQ AX, AX + JEQ 2(PC) + MOVL $0xf1, 0xf1 // crash + POPQ BP + RET + +TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVL 0(DI), BX // signal + CALL libc_getpid(SB) + MOVL AX, DI // arg 1 pid + MOVL BX, SI // arg 2 signal + CALL libc_kill(SB) + POPQ BP RET TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 @@ -167,21 +184,39 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 POPQ BP RET -TEXT runtime·sigtramp(SB),NOSPLIT,$40 - MOVL SI, 24(SP) // save infostyle for sigreturn below - MOVQ R8, 32(SP) // save ctx - MOVL DX, 0(SP) // sig - MOVQ CX, 8(SP) // info - MOVQ R8, 16(SP) // ctx - MOVQ $runtime·sigtrampgo(SB), AX - CALL AX - MOVQ 32(SP), DI // ctx - MOVL 24(SP), SI // infostyle - MOVL $(0x2000000+184), AX - SYSCALL - INT $3 // not reached +// This is the function registered during sigaction and is invoked when +// a signal is received. It just redirects to the Go function sigtrampgo. +TEXT runtime·sigtramp(SB),NOSPLIT,$0 + // This runs on the signal stack, so we have lots of stack available. + // We allocate our own stack space, because if we tell the linker + // how much we're using, the NOSPLIT check fails. + PUSHQ BP + MOVQ SP, BP + SUBQ $64, SP + // Save callee-save registers. + MOVQ BX, 24(SP) + MOVQ R12, 32(SP) + MOVQ R13, 40(SP) + MOVQ R14, 48(SP) + MOVQ R15, 56(SP) + // Call into the Go signal handler + MOVL DI, 0(SP) // sig + MOVQ SI, 8(SP) // info + MOVQ DX, 16(SP) // ctx + CALL runtime·sigtrampgo(SB) + + // Restore callee-save registers. + MOVQ 24(SP), BX + MOVQ 32(SP), R12 + MOVQ 40(SP), R13 + MOVQ 48(SP), R14 + MOVQ 56(SP), R15 + + MOVQ BP, SP + POPQ BP + RET TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 PUSHQ BP // make a frame; keep stack aligned @@ -218,15 +253,6 @@ TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·sigaltstack(SB),NOSPLIT,$0 - MOVQ new+0(FP), DI - MOVQ old+8(FP), SI - MOVQ $(0x2000000+53), AX - SYSCALL - JCC 2(PC) - MOVL $0xf1, 0xf1 // crash - RET - TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 PUSHQ BP MOVQ SP, BP @@ -372,6 +398,14 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 // DI points to the m. // We are already on m's g0 stack. + // Save callee-save registers. + SUBQ $40, SP + MOVQ BX, 0(SP) + MOVQ R12, 8(SP) + MOVQ R13, 16(SP) + MOVQ R14, 24(SP) + MOVQ R15, 32(SP) + MOVQ m_g0(DI), DX // g // Initialize TLS entry. @@ -383,10 +417,19 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0 CALL runtime·mstart(SB) + // Restore callee-save registers. + MOVQ 0(SP), BX + MOVQ 8(SP), R12 + MOVQ 16(SP), R13 + MOVQ 24(SP), R14 + MOVQ 32(SP), R15 + // Go is all done with this OS thread. // Tell pthread everything is ok (we never join with this thread, so // the value here doesn't really matter). XORL AX, AX + + ADDQ $40, SP RET // These trampolines help convert from Go calling convention to C calling convention. From 021c39d7a3361290d9e29497cf2a4a8fd2ee7b5c Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 7 Jun 2018 12:19:42 +0200 Subject: [PATCH 033/203] runtime: use libc for signal functions on iOS Also: - Add extra SystemStack space for darwin/arm64 just like for darwin/arm. - Removed redundant stack alignment; the arm64 hardware enforces the 16 byte alignment. - Save and restore the g registers at library initialization. - Zero g registers since libpreinit can call libc functions that in turn use asmcgocall. asmcgocall requires an initialized g. - Change asmcgocall to work even if no g is set. The change mimics amd64. Change-Id: I1b8c63b07cfec23b909c0d215b50dc229f8adbc8 Reviewed-on: https://go-review.googlesource.com/117176 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/vet/all/whitelist/darwin_arm.txt | 6 - src/cmd/vet/all/whitelist/darwin_arm64.txt | 2 - src/runtime/asm_arm.s | 71 ++++++--- src/runtime/asm_arm64.s | 34 ++++- src/runtime/rt0_darwin_arm64.s | 37 +++-- src/runtime/stack.go | 4 +- src/runtime/sys_darwin_arm.s | 147 +++++++++---------- src/runtime/sys_darwin_arm64.s | 163 +++++++++++---------- 8 files changed, 261 insertions(+), 203 deletions(-) diff --git a/src/cmd/vet/all/whitelist/darwin_arm.txt b/src/cmd/vet/all/whitelist/darwin_arm.txt index 8e935b6ff2..1c25c6a939 100644 --- a/src/cmd/vet/all/whitelist/darwin_arm.txt +++ b/src/cmd/vet/all/whitelist/darwin_arm.txt @@ -1,11 +1,5 @@ // darwin/arm-specific vet whitelist. See readme.txt for details. -// False positives due to comments in assembly. -// To be removed. See CL 27154. - -runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP) - - // Ok. runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration diff --git a/src/cmd/vet/all/whitelist/darwin_arm64.txt b/src/cmd/vet/all/whitelist/darwin_arm64.txt index 8cab997961..a1edb71383 100644 --- a/src/cmd/vet/all/whitelist/darwin_arm64.txt +++ b/src/cmd/vet/all/whitelist/darwin_arm64.txt @@ -1,5 +1,3 @@ // darwin/arm64-specific vet whitelist. See readme.txt for details. -runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) -runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP) runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 545e58e9b0..6722ba760f 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -36,25 +36,28 @@ TEXT _rt0_arm_lib(SB),NOSPLIT,$104 MOVW R6, 20(R13) MOVW R7, 24(R13) MOVW R8, 28(R13) - MOVW R11, 32(R13) + MOVW g, 32(R13) + MOVW R11, 36(R13) // Skip floating point registers on GOARM < 6. MOVB runtime·goarm(SB), R11 CMP $6, R11 BLT skipfpsave - MOVD F8, (32+8*1)(R13) - MOVD F9, (32+8*2)(R13) - MOVD F10, (32+8*3)(R13) - MOVD F11, (32+8*4)(R13) - MOVD F12, (32+8*5)(R13) - MOVD F13, (32+8*6)(R13) - MOVD F14, (32+8*7)(R13) - MOVD F15, (32+8*8)(R13) + MOVD F8, (40+8*0)(R13) + MOVD F9, (40+8*1)(R13) + MOVD F10, (40+8*2)(R13) + MOVD F11, (40+8*3)(R13) + MOVD F12, (40+8*4)(R13) + MOVD F13, (40+8*5)(R13) + MOVD F14, (40+8*6)(R13) + MOVD F15, (40+8*7)(R13) skipfpsave: // Save argc/argv. MOVW R0, _rt0_arm_lib_argc<>(SB) MOVW R1, _rt0_arm_lib_argv<>(SB) + MOVW $0, g // Initialize g. + // Synchronous initialization. CALL runtime·libpreinit(SB) @@ -77,21 +80,22 @@ rr: MOVB runtime·goarm(SB), R11 CMP $6, R11 BLT skipfprest - MOVD (32+8*1)(R13), F8 - MOVD (32+8*2)(R13), F9 - MOVD (32+8*3)(R13), F10 - MOVD (32+8*4)(R13), F11 - MOVD (32+8*5)(R13), F12 - MOVD (32+8*6)(R13), F13 - MOVD (32+8*7)(R13), F14 - MOVD (32+8*8)(R13), F15 + MOVD (40+8*0)(R13), F8 + MOVD (40+8*1)(R13), F9 + MOVD (40+8*2)(R13), F10 + MOVD (40+8*3)(R13), F11 + MOVD (40+8*4)(R13), F12 + MOVD (40+8*5)(R13), F13 + MOVD (40+8*6)(R13), F14 + MOVD (40+8*7)(R13), F15 skipfprest: MOVW 12(R13), R4 MOVW 16(R13), R5 MOVW 20(R13), R6 MOVW 24(R13), R7 MOVW 28(R13), R8 - MOVW 32(R13), R11 + MOVW 32(R13), g + MOVW 36(R13), R11 RET // _rt0_arm_lib_go initializes the Go runtime. @@ -582,6 +586,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12 MOVW arg+4(FP), R0 MOVW R13, R2 + CMP $0, g + BEQ nosave MOVW g, R4 // Figure out if we need to switch to m->g0 stack. @@ -590,10 +596,10 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12 MOVW g_m(g), R8 MOVW m_gsignal(R8), R3 CMP R3, g - BEQ noswitch + BEQ nosave MOVW m_g0(R8), R3 CMP R3, g - BEQ noswitch + BEQ nosave BL gosave<>(SB) MOVW R0, R5 MOVW R3, R0 @@ -602,7 +608,6 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12 MOVW (g_sched+gobuf_sp)(g), R13 // Now on a scheduling stack (a pthread-created stack). -noswitch: SUB $24, R13 BIC $0x7, R13 // alignment for gcc ABI MOVW R4, 20(R13) // save old g @@ -624,6 +629,30 @@ noswitch: MOVW R0, ret+8(FP) RET +nosave: + // Running on a system stack, perhaps even without a g. + // Having no g can happen during thread creation or thread teardown + // (see needm/dropm on Solaris, for example). + // This code is like the above sequence but without saving/restoring g + // and without worrying about the stack moving out from under us + // (because we're on a system stack, not a goroutine stack). + // The above code could be used directly if already on a system stack, + // but then the only path through this code would be a rare case on Solaris. + // Using this code for all "already on system stack" calls exercises it more, + // which should help keep it correct. + SUB $24, R13 + BIC $0x7, R13 // alignment for gcc ABI + // save null g in case someone looks during debugging. + MOVW $0, R4 + MOVW R4, 20(R13) + MOVW R2, 16(R13) // Save old stack pointer. + BL (R1) + // Restore stack pointer. + MOVW 16(R13), R2 + MOVW R2, R13 + MOVW R0, ret+8(FP) + RET + // cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt) // Turn the fn into a Go func (by taking its address) and call // cgocallback_gofunc. diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index d1b90b056c..af389be9fe 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -863,6 +863,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 MOVD arg+8(FP), R0 MOVD RSP, R2 // save original stack pointer + CMP $0, g + BEQ nosave MOVD g, R4 // Figure out if we need to switch to m->g0 stack. @@ -871,10 +873,12 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 MOVD g_m(g), R8 MOVD m_gsignal(R8), R3 CMP R3, g - BEQ noswitch + BEQ nosave MOVD m_g0(R8), R3 CMP R3, g - BEQ noswitch + BEQ nosave + + // Switch to system stack. MOVD R0, R9 // gosave<> and save_g might clobber R0 BL gosave<>(SB) MOVD R3, g @@ -884,12 +888,10 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 MOVD R9, R0 // Now on a scheduling stack (a pthread-created stack). -noswitch: // Save room for two of our pointers /*, plus 32 bytes of callee // save area that lives on the caller stack. */ MOVD RSP, R13 SUB $16, R13 - BIC $0xf, R13 // alignment for gcc ABI MOVD R13, RSP MOVD R4, 0(RSP) // save old g on stack MOVD (g_stack+stack_hi)(R4), R4 @@ -910,6 +912,30 @@ noswitch: MOVW R0, ret+16(FP) RET +nosave: + // Running on a system stack, perhaps even without a g. + // Having no g can happen during thread creation or thread teardown + // (see needm/dropm on Solaris, for example). + // This code is like the above sequence but without saving/restoring g + // and without worrying about the stack moving out from under us + // (because we're on a system stack, not a goroutine stack). + // The above code could be used directly if already on a system stack, + // but then the only path through this code would be a rare case on Solaris. + // Using this code for all "already on system stack" calls exercises it more, + // which should help keep it correct. + MOVD RSP, R13 + SUB $16, R13 + MOVD R13, RSP + MOVD $0, R4 + MOVD R4, 0(RSP) // Where above code stores g, in case someone looks during debugging. + MOVD R2, 8(RSP) // Save original stack pointer. + BL (R1) + // Restore stack pointer. + MOVD 8(RSP), R2 + MOVD R2, RSP + MOVD R0, ret+16(FP) + RET + // cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt) // Turn the fn into a Go func (by taking its address) and call // cgocallback_gofunc. diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s index 719944e626..d039a8e0ab 100644 --- a/src/runtime/rt0_darwin_arm64.s +++ b/src/runtime/rt0_darwin_arm64.s @@ -26,18 +26,21 @@ TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$168 MOVD R25, 72(RSP) MOVD R26, 80(RSP) MOVD R27, 88(RSP) - FMOVD F8, 96(RSP) - FMOVD F9, 104(RSP) - FMOVD F10, 112(RSP) - FMOVD F11, 120(RSP) - FMOVD F12, 128(RSP) - FMOVD F13, 136(RSP) - FMOVD F14, 144(RSP) - FMOVD F15, 152(RSP) + MOVD g, 96(RSP) + FMOVD F8, 104(RSP) + FMOVD F9, 112(RSP) + FMOVD F10, 120(RSP) + FMOVD F11, 128(RSP) + FMOVD F12, 136(RSP) + FMOVD F13, 144(RSP) + FMOVD F14, 152(RSP) + FMOVD F15, 160(RSP) MOVD R0, _rt0_arm64_darwin_lib_argc<>(SB) MOVD R1, _rt0_arm64_darwin_lib_argv<>(SB) + MOVD $0, g // initialize g to nil + // Synchronous initialization. MOVD $runtime·libpreinit(SB), R4 BL (R4) @@ -58,14 +61,16 @@ TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$168 MOVD 72(RSP), R25 MOVD 80(RSP), R26 MOVD 88(RSP), R27 - FMOVD 96(RSP), F8 - FMOVD 104(RSP), F9 - FMOVD 112(RSP), F10 - FMOVD 120(RSP), F11 - FMOVD 128(RSP), F12 - FMOVD 136(RSP), F13 - FMOVD 144(RSP), F14 - FMOVD 152(RSP), F15 + MOVD 96(RSP), g + FMOVD 104(RSP), F8 + FMOVD 112(RSP), F9 + FMOVD 120(RSP), F10 + FMOVD 128(RSP), F11 + FMOVD 136(RSP), F12 + FMOVD 144(RSP), F13 + FMOVD 152(RSP), F14 + FMOVD 160(RSP), F15 + RET TEXT _rt0_arm64_darwin_lib_go(SB),NOSPLIT,$0 diff --git a/src/runtime/stack.go b/src/runtime/stack.go index e40fa9cc1b..d83e9d6722 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -64,8 +64,8 @@ const ( // StackSystem is a number of additional bytes to add // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows, Plan 9, - // and Darwin/ARM because they do not use a separate stack. - _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosDarwin*sys.GoarchArm*1024 + // and iOS because they do not use a separate stack. + _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosDarwin*sys.GoarchArm*1024 + sys.GoosDarwin*sys.GoarchArm64*1024 // The minimum size of stack used by Go code _StackMin = 2048 diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s index a940d95732..5f6c903437 100644 --- a/src/runtime/sys_darwin_arm.s +++ b/src/runtime/sys_darwin_arm.s @@ -61,14 +61,12 @@ TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0 MOVW $1002, R1 MOVW R0, (R1) // fail hard -TEXT runtime·raiseproc(SB),NOSPLIT,$24 - MOVW $SYS_getpid, R12 - SWI $0x80 +TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 + MOVW 0(R0), R8 // signal + BL libc_getpid(SB) // arg 1 pid already in R0 from getpid - MOVW sig+0(FP), R1 // arg 2 - signal - MOVW $1, R2 // arg 3 - posix - MOVW $SYS_kill, R12 - SWI $0x80 + MOVW R8, R1 // arg 2 signal + BL libc_kill(SB) RET TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 @@ -174,91 +172,89 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16 MOVW R4, R13 RET -// Sigtramp's job is to call the actual signal handler. -// It is called with the following arguments on the stack: -// LR "return address" - ignored -// R0 actual handler -// R1 siginfo style - ignored -// R2 signal number -// R3 siginfo -// -4(FP) context, beware that 0(FP) is the saved LR TEXT runtime·sigtramp(SB),NOSPLIT,$0 + // Reserve space for callee-save registers and arguments. + SUB $36, R13 + + MOVW R4, 12(R13) + MOVW R5, 16(R13) + MOVW R6, 20(R13) + MOVW R7, 24(R13) + MOVW R8, 28(R13) + MOVW R11, 32(R13) + + // Save arguments. + MOVW R0, 4(R13) // sig + MOVW R1, 8(R13) // info + MOVW R2, 12(R13) // ctx + // this might be called in external code context, // where g is not set. - // first save R0, because runtime·load_g will clobber it - MOVM.DB.W [R0], (R13) MOVB runtime·iscgo(SB), R0 CMP $0, R0 BL.NE runtime·load_g(SB) - CMP $0, g - BNE cont - // fake function call stack frame for badsignal - // we only need to pass R2 (signal number), but - // badsignal will expect R2 at 4(R13), so we also - // push R1 onto stack. turns out we do need R1 - // to do sigreturn. - MOVM.DB.W [R1,R2], (R13) - MOVW $runtime·badsignal(SB), R11 - BL (R11) - MOVM.IA.W [R1], (R13) // saved infostype - ADD $(4+4), R13 // +4: also need to remove the pushed R0. - MOVW ucontext-4(FP), R0 // load ucontext - B ret + MOVW R13, R6 + CMP $0, g + BEQ nog -cont: - // Restore R0 - MOVM.IA.W (R13), [R0] - - // NOTE: some Darwin/ARM kernels always use the main stack to run the - // signal handler. We need to switch to gsignal ourselves. + // iOS always use the main stack to run the signal handler. + // We need to switch to gsignal ourselves. MOVW g_m(g), R11 MOVW m_gsignal(R11), R5 MOVW (g_stack+stack_hi)(R5), R6 - SUB $28, R6 - // copy arguments for call to sighandler - MOVW R2, 4(R6) // signal num - MOVW R3, 8(R6) // signal info - MOVW g, 16(R6) // old_g - MOVW context-4(FP), R4 - MOVW R4, 12(R6) // context +nog: + // Restore arguments. + MOVW 4(R13), R0 + MOVW 8(R13), R1 + MOVW 12(R13), R2 - // Backup ucontext and infostyle - MOVW R4, 20(R6) - MOVW R1, 24(R6) + // Reserve space for args and the stack pointer on the + // gsignal stack. + SUB $24, R6 + // Save stack pointer. + MOVW R13, R4 + MOVW R4, 16(R6) + // Switch to gsignal stack. + MOVW R6, R13 - // switch stack and g - MOVW R6, R13 // sigtramp is not re-entrant, so no need to back up R13. - MOVW R5, g + // Call sigtrampgo + MOVW R0, 4(R13) + MOVW R1, 8(R13) + MOVW R2, 12(R13) + BL runtime·sigtrampgo(SB) - BL (R0) + // Switch to old stack. + MOVW 16(R13), R5 + MOVW R5, R13 - // call sigreturn - MOVW 20(R13), R0 // saved ucontext - MOVW 24(R13), R1 // saved infostyle -ret: - MOVW $SYS_sigreturn, R12 // sigreturn(ucontext, infostyle) - SWI $0x80 + // Restore callee-save registers. + MOVW 12(R13), R4 + MOVW 16(R13), R5 + MOVW 20(R13), R6 + MOVW 24(R13), R7 + MOVW 28(R13), R8 + MOVW 32(R13), R11 - // if sigreturn fails, we can do nothing but exit - B runtime·exit(SB) + ADD $36, R13 -TEXT runtime·sigprocmask(SB),NOSPLIT,$0 - MOVW how+0(FP), R0 - MOVW new+4(FP), R1 - MOVW old+8(FP), R2 - MOVW $SYS_pthread_sigmask, R12 - SWI $0x80 - BL.CS notok<>(SB) RET -TEXT runtime·sigaction(SB),NOSPLIT,$0 - MOVW mode+0(FP), R0 - MOVW new+4(FP), R1 - MOVW old+8(FP), R2 - MOVW $SYS_sigaction, R12 - SWI $0x80 +TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 new + MOVW 8(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 how + BL libc_pthread_sigmask(SB) + CMP $0, R0 + BL.NE notok<>(SB) + RET + +TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 new + MOVW 8(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 how + BL libc_sigaction(SB) RET TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 @@ -387,10 +383,11 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0 SWI $0x80 RET -// sigaltstack on some darwin/arm version is buggy and will always -// run the signal handler on the main stack, so our sigtramp has +// sigaltstack is not supported on iOS, so our sigtramp has // to do the stack switch ourselves. -TEXT runtime·sigaltstack(SB),NOSPLIT,$0 +TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 + MOVW $43, R0 + BL libc_exit(SB) RET // Thread related functions diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s index d13e44afcf..c21a5566fa 100644 --- a/src/runtime/sys_darwin_arm64.s +++ b/src/runtime/sys_darwin_arm64.s @@ -61,14 +61,12 @@ TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0 MOVD $1002, R1 MOVD R0, (R1) // fail hard -TEXT runtime·raiseproc(SB),NOSPLIT,$0 - MOVW $SYS_getpid, R16 - SVC $0x80 +TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0 + MOVD 0(R0), R19 // signal + BL libc_getpid(SB) // arg 1 pid already in R0 from getpid - MOVW sig+0(FP), R1 // arg 2 - signal - MOVW $1, R2 // arg 3 - posix - MOVW $SYS_kill, R16 - SVC $0x80 + MOVD R19, R1 // arg 2 signal + BL libc_kill(SB) RET TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0 @@ -158,95 +156,104 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 BL (R11) RET -// Sigtramp's job is to call the actual signal handler. -// It is called with the following arguments on the stack: -// LR "return address" - ignored -// R0 actual handler -// R1 siginfo style - ignored -// R2 signal number -// R3 siginfo -// R4 context TEXT runtime·sigtramp(SB),NOSPLIT,$0 + // Reserve space for callee-save registers and arguments. + SUB $(8*16), RSP + + // Save callee-save registers. + MOVD R19, (8*4)(RSP) + MOVD R20, (8*5)(RSP) + MOVD R21, (8*6)(RSP) + MOVD R22, (8*7)(RSP) + MOVD R23, (8*8)(RSP) + MOVD R24, (8*9)(RSP) + MOVD R25, (8*10)(RSP) + MOVD R26, (8*11)(RSP) + MOVD R27, (8*12)(RSP) + MOVD g, (8*13)(RSP) + MOVD R29, (8*14)(RSP) + + // Save arguments. + MOVW R0, (8*1)(RSP) // sig + MOVD R1, (8*2)(RSP) // info + MOVD R2, (8*3)(RSP) // ctx + // this might be called in external code context, // where g is not set. - // first save R0, because runtime·load_g will clobber it - MOVD.W R0, -16(RSP) // note: stack must be 16-byte aligned MOVB runtime·iscgo(SB), R0 CMP $0, R0 BEQ 2(PC) BL runtime·load_g(SB) - CMP $0, g - BNE cont - // fake function call stack frame for badsignal - // we only need to pass R2 (signal number), but - // badsignal will expect R2 at 8(RSP), so we also - // push R1 onto stack. turns out we do need R1 - // to do sigreturn. - MOVD.W R1, -16(RSP) - MOVD R2, 8(RSP) - MOVD R4, 24(RSP) // save ucontext, badsignal might clobber R4 - MOVD $runtime·badsignal(SB), R26 - BL (R26) - MOVD 0(RSP), R1 // saved infostype - MOVD 24(RSP), R0 // the ucontext - ADD $(16+16), RSP - B ret - -cont: - // Restore R0 - MOVD.P 16(RSP), R0 - - // NOTE: some Darwin/ARM kernels always use the main stack to run the - // signal handler. We need to switch to gsignal ourselves. + MOVD RSP, R6 + CMP $0, g + BEQ nog + // iOS always use the main stack to run the signal handler. + // We need to switch to gsignal ourselves. MOVD g_m(g), R11 MOVD m_gsignal(R11), R5 MOVD (g_stack+stack_hi)(R5), R6 - SUB $64, R6 - // copy arguments for call to sighandler - MOVD R2, 8(R6) // signal num - MOVD R3, 16(R6) // signal info - MOVD R4, 24(R6) // context - MOVD g, 32(R6) // old_g +nog: + // Restore arguments. + MOVW (8*1)(RSP), R0 + MOVD (8*2)(RSP), R1 + MOVD (8*3)(RSP), R2 - // Backup ucontext and infostyle - MOVD R4, 40(R6) - MOVD R1, 48(R6) + // Reserve space for args and the stack pointer on the + // gsignal stack. + SUB $48, R6 + // Save stack pointer. + MOVD RSP, R4 + MOVD R4, (8*4)(R6) + // Switch to gsignal stack. + MOVD R6, RSP - // switch stack and g - MOVD R6, RSP // sigtramp is not re-entrant, so no need to back up RSP. - MOVD R5, g + // Call sigtrampgo. + MOVW R0, (8*1)(RSP) + MOVD R1, (8*2)(RSP) + MOVD R2, (8*3)(RSP) + MOVD $runtime·sigtrampgo(SB), R11 + BL (R11) - BL (R0) + // Switch to old stack. + MOVD (8*4)(RSP), R5 + MOVD R5, RSP - // call sigreturn - MOVD 40(RSP), R0 // saved ucontext - MOVD 48(RSP), R1 // saved infostyle -ret: - MOVW $SYS_sigreturn, R16 // sigreturn(ucontext, infostyle) - SVC $0x80 + // Restore callee-save registers. + MOVD (8*4)(RSP), R19 + MOVD (8*5)(RSP), R20 + MOVD (8*6)(RSP), R21 + MOVD (8*7)(RSP), R22 + MOVD (8*8)(RSP), R23 + MOVD (8*9)(RSP), R24 + MOVD (8*10)(RSP), R25 + MOVD (8*11)(RSP), R26 + MOVD (8*12)(RSP), R27 + MOVD (8*13)(RSP), g + MOVD (8*14)(RSP), R29 - // if sigreturn fails, we can do nothing but exit - B runtime·exit(SB) + ADD $(8*16), RSP -TEXT runtime·sigprocmask(SB),NOSPLIT,$0 - MOVW how+0(FP), R0 - MOVD new+8(FP), R1 - MOVD old+16(FP), R2 - MOVW $SYS_pthread_sigmask, R16 - SVC $0x80 - BCC 2(PC) + RET + +TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0 + MOVD 8(R0), R1 // arg 2 new + MOVD 16(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 how + BL libc_pthread_sigmask(SB) + CMP $0, R0 + BEQ 2(PC) BL notok<>(SB) RET -TEXT runtime·sigaction(SB),NOSPLIT,$0 - MOVW mode+0(FP), R0 - MOVD new+8(FP), R1 - MOVD old+16(FP), R2 - MOVW $SYS_sigaction, R16 - SVC $0x80 - BCC 2(PC) +TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0 + MOVD 8(R0), R1 // arg 2 new + MOVD 16(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 how + BL libc_sigaction(SB) + CMP $0, R0 + BEQ 2(PC) BL notok<>(SB) RET @@ -375,10 +382,12 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0 SVC $0x80 RET -// sigaltstack on some darwin/arm version is buggy and will always +// sigaltstack on iOS is not supported and will always // run the signal handler on the main stack, so our sigtramp has // to do the stack switch ourselves. -TEXT runtime·sigaltstack(SB),NOSPLIT,$0 +TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0 + MOVW $43, R0 + BL libc_exit(SB) RET // Thread related functions From dda7985a7b748e7149dc46c29611c2ec6e861340 Mon Sep 17 00:00:00 2001 From: Andrew Bonventre Date: Mon, 11 Jun 2018 13:36:05 -0400 Subject: [PATCH 034/203] doc/go1.11: first draft of release notes Updates golang/go#23122 Change-Id: I2d6769101cdd580901cb08a3027d787fa438d4bc Reviewed-on: https://go-review.googlesource.com/117975 Reviewed-by: Brad Fitzpatrick --- doc/go1.11.html | 337 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 doc/go1.11.html diff --git a/doc/go1.11.html b/doc/go1.11.html new file mode 100644 index 0000000000..4eb4c42abe --- /dev/null +++ b/doc/go1.11.html @@ -0,0 +1,337 @@ + + + + + + +

DRAFT RELEASE NOTES - Introduction to Go 1.11

+ +

+ + Go 1.11 is not yet released. These are work-in-progress + release notes. Go 1.11 is expected to be released in August 2018. + +

+ +

+ The latest Go release, version 1.11, arrives six months after Go 1.10. + Most of its changes are in the implementation of the toolchain, runtime, and libraries. + As always, the release maintains the Go 1 promise of compatibility. + We expect almost all Go programs to continue to compile and run as before. +

+ +

Changes to the language

+ +

+ There are no changes to the language specification. +

+ +

Ports

+ +

+ As announced in the Go 1.10 release notes, Go 1.11 now requires + OpenBSD 6.2 or later, macOS 10.10 Yosemite or later, or Windows 7 or later; + Support for previous versions of these operating systems has been removed. +

+ +

+ There are known issues with NetBSD on i386 hardware. +

+ +

+ TODO: PPC64LE race detector support +

+ +

WebAssembly

+

+ Go 1.11 adds an experimental port to WebAssembly (wasm/js). +

+ +

Core library

+ +

+ All of the changes to the standard library are minor. +

+ +

Minor changes to the library

+ +

+ As always, there are various minor changes and updates to the library, + made with the Go 1 promise of compatibility + in mind. +

+ + + + + + + + + +
all
+
+

+ TODO: https://golang.org/cl/93875: enable c-shared/c-archive support for freebsd/amd64 +

+ +

+ TODO: https://golang.org/cl/94255: drop support for Windows Vista or below (Windows XP) +

+ +

+ TODO: https://golang.org/cl/115038: remove support for macOS 10.9 and earlier +

+ +
+ +
crypto
+
+

+ TODO: https://golang.org/cl/64451: randomly read an extra byte of randomness in some places. +

+ +
+ +
crypto/cipher
+
+

+ TODO: https://golang.org/cl/48510: add NewGCMWithTagSize for custom tag sizes. +

+ +
+ +
crypto/rsa
+
+

+ TODO: https://golang.org/cl/103876: add PublicKey.Size accessor +

+ +
+ +
debug/elf
+
+

+ TODO: https://golang.org/cl/112115: add machine and OSABI constants +

+ +
+ +
encoding/asn1
+
+

+ TODO: https://golang.org/cl/110561: allow Marshaling and Unmarshaling private tag class +

+ +
+ +
encoding/base32
+
+

+ TODO: https://golang.org/cl/112516: handle surplus padding consistently +

+ +
+ +
encoding/csv
+
+

+ TODO: https://golang.org/cl/99696: disallow quote for use as Comma +

+ +
+ +
go/build, runtime/internal/sys
+
+

+ TODO: https://golang.org/cl/106256: reserve RISC-V arch names +

+ +
+ +
image/gif
+
+

+ TODO: https://golang.org/cl/93076: support non-looping animated gifs (LoopCount=-1) +

+ +
+ +
io/ioutil
+
+

+ TODO: https://golang.org/cl/105675: change TempFile prefix to a pattern +

+ +
+ +
math/big
+
+

+ TODO: https://golang.org/cl/74851: speed-up addMulVVW on amd64 +

+ +
+ +
net
+
+

+ TODO: https://golang.org/cl/72810: add ListenConfig, Dialer.Control to permit socket opts before listen/dial +

+ +

+ TODO: https://golang.org/cl/76391: implement (*syscall.RawConn).Read/Write on Windows +

+ +

+ TODO: https://golang.org/cl/107715: add support for splice(2) in (*TCPConn).ReadFrom on Linux +

+ +

+ TODO: https://golang.org/cl/108297: calling File leaves the socket in nonblocking mode +

+ +
+ +
net/http
+
+

+ TODO: https://golang.org/cl/89275: don't sniff Content-type in Server when X-Content-Type-Options:nosniff +

+ +

+ TODO: https://golang.org/cl/93296: add StatusMisdirectedRequest (421) +

+ +
+ +
os
+
+

+ TODO: https://golang.org/cl/78835: add UserCacheDir +

+ +

+ TODO: https://golang.org/cl/94856: add ModeIrregular flag +

+ +

+ TODO: https://golang.org/cl/99337: enable symlink creation on Windows 10 +

+ +

+ TODO: https://golang.org/cl/100077: use poller when NewFile is called with a blocking descriptor. +

+ +
+ +
os/signal
+
+

+ TODO: https://golang.org/cl/108376: add func Ignored(sig Signal) bool +

+ +
+ +
os/user
+
+

+ TODO: https://golang.org/cl/92456: add a way to enforce pure Go implementation +

+ +
+ +
runtime
+
+

+ TODO: https://golang.org/cl/85887: use sparse mappings for the heap +

+ +

+ TODO: https://golang.org/cl/94076: use native CAS and memory barrier on ARMv7 +

+ +

+ TODO: https://golang.org/cl/106156: use fixed TLS offsets on darwin/amd64 and darwin/386 +

+ +

+ TODO: https://golang.org/cl/109255: enable memory sanitizer on arm64 +

+ +
+ +
runtime,cmd/ld
+
+

+ TODO: https://golang.org/cl/108679: on darwin, create theads using libc +

+ +
+ +
runtime/pprof
+
+

+ TODO: https://golang.org/cl/102696: introduce "allocs" profile +

+ +
+ +
runtime/traceback
+
+

+ TODO: https://golang.org/cl/70993: support tracking goroutine ancestor tracebacks with GODEBUG="tracebackancestors=N" +

+ +
+ +
sync
+
+

+ TODO: https://golang.org/cl/87095: enable profiling of RWMutex +

+ +
+ +
syscall
+
+

+ TODO: https://golang.org/cl/106275: introduce Pointer type and use it instead of uintptr +

+ +
+ +
text/scanner
+
+

+ TODO: https://golang.org/cl/112037: return RawString token rather than String for raw string literals +

+ +
+ +
text/template
+
+

+ TODO: https://golang.org/cl/84480: add variable assignments +

+ +
+ +
time
+
+

+ TODO: https://golang.org/cl/98157: add support for parsing timezones denoted by sign and offset +

+ +
From 48987baa09856ea6f656abe8a90d264070db8fad Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 6 Jun 2018 10:21:15 -0700 Subject: [PATCH 035/203] cmd/compile: correct alias cycle detection The original fix (https://go-review.googlesource.com/c/go/+/35831) for this issue was incorrect as it reported cycles in cases where it shouldn't. Instead, use a different approach: A type cycle containing aliases is only a cycle if there are no type definitions. As soon as there is a type definition, alias expansion terminates and there is no cycle. Approach: Split sprint_depchain into two non-recursive and more easily understandable functions (cycleFor and cycleTrace), and use those instead for cycle reporting. Analyze the cycle returned by cycleFor before issueing an alias cycle error. Also: Removed original fix (main.go) which introduced a separate crash (#23823). Fixes #18640. Fixes #23823. Fixes #24939. Change-Id: Ic3707a9dec40a71dc928a3e49b4868c5fac3d3b7 Reviewed-on: https://go-review.googlesource.com/118078 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/main.go | 6 +-- src/cmd/compile/internal/gc/typecheck.go | 58 +++++++++++++++++------- test/fixedbugs/issue18640.go | 21 +++++++++ test/fixedbugs/issue23823.go | 15 ++++++ test/fixedbugs/issue24939.go | 21 +++++++++ 5 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 test/fixedbugs/issue23823.go create mode 100644 test/fixedbugs/issue24939.go diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index e8b33008b4..9f1ea2ab4b 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -481,15 +481,13 @@ func Main(archInit func(*Arch)) { // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. - // We also defer type alias declarations until phase 2 - // to avoid cycles like #18640. defercheckwidth() // Don't use range--typecheck can add closures to xtop. timings.Start("fe", "typecheck", "top1") for i := 0; i < len(xtop); i++ { n := xtop[i] - if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) { + if op := n.Op; op != ODCL && op != OAS && op != OAS2 { xtop[i] = typecheck(n, Etop) } } @@ -501,7 +499,7 @@ func Main(archInit func(*Arch)) { timings.Start("fe", "typecheck", "top2") for i := 0; i < len(xtop); i++ { n := xtop[i] - if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias { + if op := n.Op; op == ODCL || op == OAS || op == OAS2 { xtop[i] = typecheck(n, Etop) } } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 483be32d6e..fd134e9f12 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -110,19 +110,35 @@ func typekind(t *types.Type) string { return fmt.Sprintf("etype=%d", et) } -// sprint_depchain prints a dependency chain of nodes into trace. -// It is used by typecheck in the case of OLITERAL nodes -// to print constant definition loops. -func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) { - for i := len(stack) - 1; i >= 0; i-- { - if n := stack[i]; n.Op == cur.Op { - if n != first { - sprint_depchain(trace, stack[:i], n, first) - } - *trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur) - return +func cycleFor(start *Node) []*Node { + // Find the start node in typecheck_tcstack. + // We know that it must exist because each time we mark + // a node with n.SetTypecheck(2) we push it on the stack, + // and each time we mark a node with n.SetTypecheck(2) we + // pop it from the stack. We hit a cycle when we encounter + // a node marked 2 in which case is must be on the stack. + i := len(typecheck_tcstack) - 1 + for i > 0 && typecheck_tcstack[i] != start { + i-- + } + + // collect all nodes with same Op + var cycle []*Node + for _, n := range typecheck_tcstack[i:] { + if n.Op == start.Op { + cycle = append(cycle, n) } } + + return cycle +} + +func cycleTrace(cycle []*Node) string { + var s string + for i, n := range cycle { + s += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cycle[(i+1)%len(cycle)]) + } + return s } var typecheck_tcstack []*Node @@ -174,10 +190,20 @@ func typecheck(n *Node, top int) *Node { } case OTYPE: + // Only report a type cycle if we are expecting a type. + // Otherwise let other code report an error. if top&Etype == Etype { - var trace string - sprint_depchain(&trace, typecheck_tcstack, n, n) - yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace) + // A cycle containing only alias types is an error + // since it would expand indefinitely when aliases + // are substituted. + cycle := cycleFor(n) + for _, n := range cycle { + if n.Name != nil && !n.Name.Param.Alias { + lineno = lno + return n + } + } + yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, cycleTrace(cycle)) } case OLITERAL: @@ -185,9 +211,7 @@ func typecheck(n *Node, top int) *Node { yyerror("%v is not a type", n) break } - var trace string - sprint_depchain(&trace, typecheck_tcstack, n, n) - yyerrorl(n.Pos, "constant definition loop%s", trace) + yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n))) } if nsavederrors+nerrors == 0 { diff --git a/test/fixedbugs/issue18640.go b/test/fixedbugs/issue18640.go index c4f948b706..60abd31f76 100644 --- a/test/fixedbugs/issue18640.go +++ b/test/fixedbugs/issue18640.go @@ -11,12 +11,20 @@ type ( b struct { *a } +) +type ( c struct { *d } d = c +) +// The compiler reports an incorrect (non-alias related) +// type cycle here (via dowith()). Disabled for now. +// See issue #25838. +/* +type ( e = f f = g g = []h @@ -24,3 +32,16 @@ type ( i = j j = e ) +*/ + +type ( + a1 struct{ *b1 } + b1 = c1 + c1 struct{ *b1 } +) + +type ( + a2 struct{ b2 } + b2 = c2 + c2 struct{ *b2 } +) diff --git a/test/fixedbugs/issue23823.go b/test/fixedbugs/issue23823.go new file mode 100644 index 0000000000..2f802d0988 --- /dev/null +++ b/test/fixedbugs/issue23823.go @@ -0,0 +1,15 @@ +// errorcheck + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type I1 = interface { + I2 +} + +type I2 interface { // ERROR "invalid recursive type" + I1 +} diff --git a/test/fixedbugs/issue24939.go b/test/fixedbugs/issue24939.go new file mode 100644 index 0000000000..26530e95b2 --- /dev/null +++ b/test/fixedbugs/issue24939.go @@ -0,0 +1,21 @@ +// compile + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type T interface { + M(P) +} + +type M interface { + F() P +} + +type P = interface { + I() M +} + +func main() {} From 39ad208c13368bbd1a129c5e2ed85d6ebc22401a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 12 Jun 2018 16:16:38 +0000 Subject: [PATCH 036/203] test: add test to verify that string copies don't get optimized away Fixes #25834 Change-Id: I33e58dabfd04b84dfee1a9a3796796b5d19862e7 Reviewed-on: https://go-review.googlesource.com/118295 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- test/strcopy.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/strcopy.go diff --git a/test/strcopy.go b/test/strcopy.go new file mode 100644 index 0000000000..6d32baeec5 --- /dev/null +++ b/test/strcopy.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that string([]byte(string)) makes a copy and doesn't reduce to +// nothing. (Issue 25834) + +package main + +import ( + "reflect" + "unsafe" +) + +func main() { + var ( + buf = make([]byte, 2<<10) + large = string(buf) + sub = large[10:12] + subcopy = string([]byte(sub)) + subh = *(*reflect.StringHeader)(unsafe.Pointer(&sub)) + subcopyh = *(*reflect.StringHeader)(unsafe.Pointer(&subcopy)) + ) + if subh.Data == subcopyh.Data { + panic("sub and subcopy have the same underlying array") + } +} From 44b826bb28171c473cf906413c298f3095c86451 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 11 Jun 2018 13:41:23 -0400 Subject: [PATCH 037/203] cmd/compile: use a different register for updated value in AtomicAnd8/Or8 on ARM64 ARM64 manual says it is "constrained unpredictable" if the src and dst registers of STLXRB are same, although it doesn't seem to cause any problem on real hardwares so far. Fix by allocating a different register to hold the updated value for AtomicAnd8/Or8. We do this by making the ops returns like AtomicAdd, although val will not be used elsewhere. Fixes #25823. Change-Id: I735b9822f99877b3c7aee67a65e62b7278dc40df Reviewed-on: https://go-review.googlesource.com/117976 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall Reviewed-by: Wei Xiao --- src/cmd/compile/internal/arm64/ssa.go | 13 ++++---- src/cmd/compile/internal/ssa/gen/ARM64.rules | 5 +-- src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 12 ++++---- src/cmd/compile/internal/ssa/opGen.go | 28 +++++++++++------ src/cmd/compile/internal/ssa/rewriteARM64.go | 32 ++++++++++++++------ 5 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 4459596e24..501eafe03f 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -603,25 +603,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { gc.Patch(p2, p5) case ssa.OpARM64LoweredAtomicAnd8, ssa.OpARM64LoweredAtomicOr8: - // LDAXRB (Rarg0), Rtmp - // AND/OR Rarg1, Rtmp - // STLXRB Rtmp, (Rarg0), Rtmp + // LDAXRB (Rarg0), Rout + // AND/OR Rarg1, Rout + // STLXRB Rout, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) r0 := v.Args[0].Reg() r1 := v.Args[1].Reg() + out := v.Reg0() p := s.Prog(arm64.ALDAXRB) p.From.Type = obj.TYPE_MEM p.From.Reg = r0 p.To.Type = obj.TYPE_REG - p.To.Reg = arm64.REGTMP + p.To.Reg = out p1 := s.Prog(v.Op.Asm()) p1.From.Type = obj.TYPE_REG p1.From.Reg = r1 p1.To.Type = obj.TYPE_REG - p1.To.Reg = arm64.REGTMP + p1.To.Reg = out p2 := s.Prog(arm64.ASTLXRB) p2.From.Type = obj.TYPE_REG - p2.From.Reg = arm64.REGTMP + p2.From.Reg = out p2.To.Type = obj.TYPE_MEM p2.To.Reg = r0 p2.RegTo2 = arm64.REGTMP diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index b5eeb96468..a1a3cccf3c 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -540,8 +540,9 @@ (AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem) (AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem) -(AtomicAnd8 ptr val mem) -> (LoweredAtomicAnd8 ptr val mem) -(AtomicOr8 ptr val mem) -> (LoweredAtomicOr8 ptr val mem) +// Currently the updated value is not used, but we need a register to temporarily hold it. +(AtomicAnd8 ptr val mem) -> (Select1 (LoweredAtomicAnd8 ptr val mem)) +(AtomicOr8 ptr val mem) -> (Select1 (LoweredAtomicOr8 ptr val mem)) // Write barrier. (WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index b54de53f59..9e8b07ec4b 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -596,13 +596,13 @@ func init() { {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, // atomic and/or. - // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero. - // LDAXRB (Rarg0), Rtmp - // AND/OR Rarg1, Rtmp - // STLXRB Rtmp, (Rarg0), Rtmp + // *arg0 &= (|=) arg1. arg2=mem. returns . auxint must be zero. + // LDAXRB (Rarg0), Rout + // AND/OR Rarg1, Rout + // STLXRB Rout, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) - {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true}, // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier // It saves all GP registers if necessary, diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 4e12132aa5..eec5b02713 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -16759,29 +16759,37 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LoweredAtomicAnd8", - argLen: 3, - faultOnNilArg0: true, - hasSideEffects: true, - asm: arm64.AAND, + name: "LoweredAtomicAnd8", + argLen: 3, + resultNotInArgs: true, + faultOnNilArg0: true, + hasSideEffects: true, + asm: arm64.AAND, reg: regInfo{ inputs: []inputInfo{ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, }, }, { - name: "LoweredAtomicOr8", - argLen: 3, - faultOnNilArg0: true, - hasSideEffects: true, - asm: arm64.AORR, + name: "LoweredAtomicOr8", + argLen: 3, + resultNotInArgs: true, + faultOnNilArg0: true, + hasSideEffects: true, + asm: arm64.AORR, reg: regInfo{ inputs: []inputInfo{ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, }, }, { diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index f538011198..60121038e4 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -25925,18 +25925,24 @@ func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool { } } func rewriteValueARM64_OpAtomicAnd8_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ // match: (AtomicAnd8 ptr val mem) // cond: - // result: (LoweredAtomicAnd8 ptr val mem) + // result: (Select1 (LoweredAtomicAnd8 ptr val mem)) for { _ = v.Args[2] ptr := v.Args[0] val := v.Args[1] mem := v.Args[2] - v.reset(OpARM64LoweredAtomicAnd8) - v.AddArg(ptr) - v.AddArg(val) - v.AddArg(mem) + v.reset(OpSelect1) + v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicAnd8, types.NewTuple(typ.UInt8, types.TypeMem)) + v0.AddArg(ptr) + v0.AddArg(val) + v0.AddArg(mem) + v.AddArg(v0) return true } } @@ -26051,18 +26057,24 @@ func rewriteValueARM64_OpAtomicLoadPtr_0(v *Value) bool { } } func rewriteValueARM64_OpAtomicOr8_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ // match: (AtomicOr8 ptr val mem) // cond: - // result: (LoweredAtomicOr8 ptr val mem) + // result: (Select1 (LoweredAtomicOr8 ptr val mem)) for { _ = v.Args[2] ptr := v.Args[0] val := v.Args[1] mem := v.Args[2] - v.reset(OpARM64LoweredAtomicOr8) - v.AddArg(ptr) - v.AddArg(val) - v.AddArg(mem) + v.reset(OpSelect1) + v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicOr8, types.NewTuple(typ.UInt8, types.TypeMem)) + v0.AddArg(ptr) + v0.AddArg(val) + v0.AddArg(mem) + v.AddArg(v0) return true } } From f7142206e95f7b7bf880d8819341718b9adef7dd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Jun 2018 16:05:29 -0400 Subject: [PATCH 038/203] cmd/go: use build cache for tests when GOCACHE is unset Before this CL, if you had GOCACHE=/some/dir, then the cmd/go tests used it. But if you were relying on the implicit behavior that GOCACHE being empty meant an appropriate system-specific cache directory, then the cmd/go tests ran with no cache at all, which makes them about 4X slower. During all.bash GOCACHE is set to a fresh temporary directory and is therefore already getting proper caching; this CL mainly helps people running 'go test cmd/go' by hand. Change-Id: I7c322ca79b877c1d0a3b448b95d5354fbfcba7f8 Reviewed-on: https://go-review.googlesource.com/118320 Run-TryBot: Russ Cox Reviewed-by: Ian Lance Taylor --- src/cmd/go/go_test.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index abe23ff52d..21dc9607d5 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -99,6 +99,7 @@ func init() { var testGOROOT string var testCC string +var testGOCACHE string // The TestMain function creates a go command for testing purposes and // deletes it after the tests have been run. @@ -175,6 +176,13 @@ func TestMain(m *testing.M) { } } + out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out) + os.Exit(2) + } + testGOCACHE = strings.TrimSpace(string(out)) + // As of Sept 2017, MSan is only supported on linux/amd64. // https://github.com/google/sanitizers/wiki/MemorySanitizer#getting-memorysanitizer canMSan = canCgo && runtime.GOOS == "linux" && runtime.GOARCH == "amd64" @@ -198,7 +206,7 @@ func TestMain(m *testing.M) { } os.Setenv("HOME", "/test-go-home-does-not-exist") if os.Getenv("GOCACHE") == "" { - os.Setenv("GOCACHE", "off") // because $HOME is gone + os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone } r := m.Run() @@ -3261,9 +3269,9 @@ func TestGoTestCoverMultiPackage(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.run("test", "-cover", "./testdata/testcover/...") - tg.grepStdout(`\?.*testdata/testcover/pkg1.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") - tg.grepStdout(`ok.*testdata/testcover/pkg2.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") - tg.grepStdout(`ok.*testdata/testcover/pkg3.*\d\.\d\d\ds.*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") + tg.grepStdout(`\?.*testdata/testcover/pkg1.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") + tg.grepStdout(`ok.*testdata/testcover/pkg2.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") + tg.grepStdout(`ok.*testdata/testcover/pkg3.*(\d\.\d\d\ds|cached).*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") } // issue 24570 @@ -3272,9 +3280,9 @@ func TestGoTestCoverprofileMultiPackage(t *testing.T) { defer tg.cleanup() tg.creatingTemp("testdata/cover.out") tg.run("test", "-coverprofile=testdata/cover.out", "./testdata/testcover/...") - tg.grepStdout(`\?.*testdata/testcover/pkg1.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") - tg.grepStdout(`ok.*testdata/testcover/pkg2.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") - tg.grepStdout(`ok.*testdata/testcover/pkg3.*\d\.\d\d\ds.*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") + tg.grepStdout(`\?.*testdata/testcover/pkg1.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1") + tg.grepStdout(`ok.*testdata/testcover/pkg2.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2") + tg.grepStdout(`ok.*testdata/testcover/pkg3.*(\d\.\d\d\ds|cached).*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3") if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { t.Error(err) } else { From bd83774593bca66cc899d5180c77680bc907fab8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 4 May 2018 14:55:31 -0400 Subject: [PATCH 039/203] cmd/link: separate virtual address layout from file layout Currently these two forms of layout are done in a single pass. This makes it difficult to compress DWARF sections because that must be done after relocations are applied, which must happen after virtual address layout, but we can't layout the file until we've compressed the DWARF sections. Fix this by separating the two layout steps. In the process, we can also unify the copy-pasted code in Link.address to compute file offsets. Currently, each instance of this is slightly different, but there's no reason for it to be. For example, we don't perform PEFILEALIGN alignment on Segrodata or Selreltodata even when HeadType == Hwindows, but it turns out it doesn't matter whether you do or don't because these segments simply don't exist on Windows. Hence, in the unified code path, we do this alignment for all segments. Likewise, there are two ways of computing Fileoff: seg.Vaddr - prev.Vaddr + prev.Fileoff and prev.Fileoff + uint64(Rnd(int64(prev.Filelen), int64(*FlagRound))) At the moment, these always have the same value, but the latter will continue to work after we start compressing sections on disk. Tested by comparing test binaries for all packages in std before and after this change for GOOS={linux,windows,darwin,plan9}. All binaries are identical. For #11799. Change-Id: If09f28771bb4d78dd392fd58b8d7c9d5f22b0b9f Reviewed-on: https://go-review.googlesource.com/111682 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Heschi Kreinick Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/data.go | 68 +++++++++++++++++++------------- src/cmd/link/internal/ld/main.go | 3 +- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 3e4773102d..184e8158fd 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1903,12 +1903,15 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6 return sect, n, va } -// assign addresses -func (ctxt *Link) address() { +// address assigns virtual addresses to all segments and sections and +// returns all segments in file order. +func (ctxt *Link) address() []*sym.Segment { + var order []*sym.Segment // Layout order + va := uint64(*FlagTextAddr) + order = append(order, &Segtext) Segtext.Rwx = 05 Segtext.Vaddr = va - Segtext.Fileoff = uint64(HEADR) for _, s := range Segtext.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1916,7 +1919,6 @@ func (ctxt *Link) address() { } Segtext.Length = va - uint64(*FlagTextAddr) - Segtext.Filelen = Segtext.Length if ctxt.HeadType == objabi.Hnacl { va += 32 // room for the "halt sled" } @@ -1937,13 +1939,9 @@ func (ctxt *Link) address() { // writable even for this short period. va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segrodata) Segrodata.Rwx = 04 Segrodata.Vaddr = va - Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff - Segrodata.Filelen = 0 - if ctxt.HeadType == objabi.Hwindows { - Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN)) - } for _, s := range Segrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1951,17 +1949,15 @@ func (ctxt *Link) address() { } Segrodata.Length = va - Segrodata.Vaddr - Segrodata.Filelen = Segrodata.Length } if len(Segrelrodata.Sections) > 0 { // align to page boundary so as not to mix // rodata, rel-ro data, and executable text. va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segrelrodata) Segrelrodata.Rwx = 06 Segrelrodata.Vaddr = va - Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff - Segrelrodata.Filelen = 0 for _, s := range Segrelrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1969,20 +1965,12 @@ func (ctxt *Link) address() { } Segrelrodata.Length = va - Segrelrodata.Vaddr - Segrelrodata.Filelen = Segrelrodata.Length } va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segdata) Segdata.Rwx = 06 Segdata.Vaddr = va - Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff - Segdata.Filelen = 0 - if ctxt.HeadType == objabi.Hwindows { - Segdata.Fileoff = Segrodata.Fileoff + uint64(Rnd(int64(Segrodata.Length), PEFILEALIGN)) - } - if ctxt.HeadType == objabi.Hplan9 { - Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen - } var data *sym.Section var noptr *sym.Section var bss *sym.Section @@ -2012,16 +2000,14 @@ func (ctxt *Link) address() { } } + // Assign Segdata's Filelen omitting the BSS. We do this here + // simply because right now we know where the BSS starts. Segdata.Filelen = bss.Vaddr - Segdata.Vaddr va = uint64(Rnd(int64(va), int64(*FlagRound))) + order = append(order, &Segdwarf) Segdwarf.Rwx = 06 Segdwarf.Vaddr = va - Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound))) - Segdwarf.Filelen = 0 - if ctxt.HeadType == objabi.Hwindows { - Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), PEFILEALIGN)) - } for i, s := range Segdwarf.Sections { vlen := int64(s.Length) if i+1 < len(Segdwarf.Sections) { @@ -2035,8 +2021,6 @@ func (ctxt *Link) address() { Segdwarf.Length = va - Segdwarf.Vaddr } - Segdwarf.Filelen = va - Segdwarf.Vaddr - var ( text = Segtext.Sections[0] rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect @@ -2123,6 +2107,34 @@ func (ctxt *Link) address() { ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr)) ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length)) ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length)) + + return order +} + +// layout assigns file offsets and lengths to the segments in order. +func (ctxt *Link) layout(order []*sym.Segment) { + var prev *sym.Segment + for _, seg := range order { + if prev == nil { + seg.Fileoff = uint64(HEADR) + } else { + switch ctxt.HeadType { + default: + seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), int64(*FlagRound))) + case objabi.Hwindows: + seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN)) + case objabi.Hplan9: + seg.Fileoff = prev.Fileoff + prev.Filelen + } + } + if seg != &Segdata { + // Link.address already set Segdata.Filelen to + // account for BSS. + seg.Filelen = seg.Length + } + prev = seg + } + } // add a trampoline with symbol s (to be laid down after the current function) diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index bfa3f70a9e..23dfa277d0 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -224,8 +224,9 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.typelink() ctxt.symtab() ctxt.dodata() - ctxt.address() + order := ctxt.address() ctxt.reloc() + ctxt.layout(order) thearch.Asmb(ctxt) ctxt.undef() ctxt.hostlink() From be36bd996eb120741ed866396e607fcd5e0b702a Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Tue, 12 Jun 2018 23:22:03 +0200 Subject: [PATCH 040/203] runtime/internal/sys: rename Wasm to WASM This commit changes sys.Wasm to sys.WASM, as requested on https://groups.google.com/forum/#!topic/golang-dev/VquDxlhjPkg Change-Id: I30a208c34576a8bb49b9beb524203d71df8fdf1c Reviewed-on: https://go-review.googlesource.com/118395 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/runtime/internal/sys/arch.go | 2 +- src/runtime/internal/sys/arch_wasm.go | 2 +- src/runtime/stack.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/internal/sys/arch.go b/src/runtime/internal/sys/arch.go index d9debaeef7..75beb7872f 100644 --- a/src/runtime/internal/sys/arch.go +++ b/src/runtime/internal/sys/arch.go @@ -15,5 +15,5 @@ const ( MIPS64 PPC64 S390X - Wasm + WASM ) diff --git a/src/runtime/internal/sys/arch_wasm.go b/src/runtime/internal/sys/arch_wasm.go index 54fcd1e92e..5463f934d6 100644 --- a/src/runtime/internal/sys/arch_wasm.go +++ b/src/runtime/internal/sys/arch_wasm.go @@ -5,7 +5,7 @@ package sys const ( - ArchFamily = Wasm + ArchFamily = WASM BigEndian = false CacheLineSize = 64 DefaultPhysPageSize = 65536 diff --git a/src/runtime/stack.go b/src/runtime/stack.go index d83e9d6722..648603db35 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -940,7 +940,7 @@ func newstack() { throw("missing stack in newstack") } sp := gp.sched.sp - if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 || sys.ArchFamily == sys.Wasm { + if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 || sys.ArchFamily == sys.WASM { // The call to morestack cost a word. sp -= sys.PtrSize } From 2cf9732e8aae92edfa55a8d0e3cebea9154aced7 Mon Sep 17 00:00:00 2001 From: Ioannis Georgoulas Date: Sat, 15 Jul 2017 12:16:56 -0600 Subject: [PATCH 041/203] context: add docs to ExampleWithValue Change-Id: I3a83c63f4db2e46fd96f373378a429896e93f9d1 Reviewed-on: https://go-review.googlesource.com/48861 Reviewed-by: Brad Fitzpatrick --- src/context/example_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/context/example_test.go b/src/context/example_test.go index b2c2aa921d..2b28b57704 100644 --- a/src/context/example_test.go +++ b/src/context/example_test.go @@ -93,6 +93,8 @@ func ExampleWithTimeout() { // context deadline exceeded } +// This example demonstrates how a value can be passed to the context +// and also how to retrieve it if it exists. func ExampleWithValue() { type favContextKey string From 3885e864114f9e45ed7d4322e0d802b897124c37 Mon Sep 17 00:00:00 2001 From: Matthew Broberg Date: Sat, 15 Jul 2017 17:40:29 -0600 Subject: [PATCH 042/203] regexp: add QuoteMeta example Change-Id: I0bbb53cad9a7c464ab1cfca381128f33496813ff Reviewed-on: https://go-review.googlesource.com/49130 Reviewed-by: Brad Fitzpatrick --- src/regexp/example_test.go | 6 ++++++ src/regexp/regexp.go | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/regexp/example_test.go b/src/regexp/example_test.go index 0bf1f6bee7..eb8cd4ea94 100644 --- a/src/regexp/example_test.go +++ b/src/regexp/example_test.go @@ -38,6 +38,12 @@ func ExampleMatchString() { // false error parsing regexp: missing closing ): `a(b` } +func ExampleQuoteMeta() { + fmt.Println(regexp.QuoteMeta("Escaping symbols like: .+*?()|[]{}^$")) + // Output: + // Escaping symbols like: \.\+\*\?\(\)\|\[\]\{\}\^\$ +} + func ExampleRegexp_FindString() { re := regexp.MustCompile("foo.?") fmt.Printf("%q\n", re.FindString("seafood fool")) diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go index 09faced8f3..0d10aa1e22 100644 --- a/src/regexp/regexp.go +++ b/src/regexp/regexp.go @@ -616,9 +616,9 @@ func init() { } } -// QuoteMeta returns a string that quotes all regular expression metacharacters +// QuoteMeta returns a string that escapes all regular expression metacharacters // inside the argument text; the returned string is a regular expression matching -// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`. +// the literal text. func QuoteMeta(s string) string { // A byte loop is correct because all metacharacters are ASCII. var i int From b768d82d8e19493e287b9f6c3219cd253d3ccb42 Mon Sep 17 00:00:00 2001 From: Niek Sanders Date: Thu, 15 Jun 2017 09:38:57 -0700 Subject: [PATCH 043/203] encoding/base32: eliminate alphabet bounds check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old time/op new time/op delta EncodeToString-4 35.5µs ± 7% 33.3µs ± 6% -6.27% (p=0.008 n=10+9) DecodeString-4 120µs ± 7% 113µs ± 8% -5.88% (p=0.011 n=10+10) name old speed new speed delta EncodeToString-4 231MB/s ± 8% 247MB/s ± 5% +6.55% (p=0.008 n=10+9) DecodeString-4 109MB/s ± 7% 116MB/s ± 8% +6.27% (p=0.011 n=10+10) Change-Id: I60bf962464179e35b1711617adbc45a822eaece5 Reviewed-on: https://go-review.googlesource.com/45876 Reviewed-by: Brad Fitzpatrick --- src/encoding/base32/base32.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go index 60f25b04b2..3fb6caceab 100644 --- a/src/encoding/base32/base32.go +++ b/src/encoding/base32/base32.go @@ -21,7 +21,7 @@ import ( // introduced for SASL GSSAPI and standardized in RFC 4648. // The alternate "base32hex" encoding is used in DNSSEC. type Encoding struct { - encode string + encode [32]byte decodeMap [256]byte padChar rune } @@ -37,8 +37,12 @@ const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV" // NewEncoding returns a new Encoding defined by the given alphabet, // which must be a 32-byte string. func NewEncoding(encoder string) *Encoding { + if len(encoder) != 32 { + panic("encoding alphabet is not 32-bytes long") + } + e := new(Encoding) - e.encode = encoder + copy(e.encode[:], encoder) e.padChar = StdPadding for i := 0; i < len(e.decodeMap); i++ { @@ -129,17 +133,17 @@ func (enc *Encoding) Encode(dst, src []byte) { size := len(dst) if size >= 8 { // Common case, unrolled for extra performance - dst[0] = enc.encode[b[0]] - dst[1] = enc.encode[b[1]] - dst[2] = enc.encode[b[2]] - dst[3] = enc.encode[b[3]] - dst[4] = enc.encode[b[4]] - dst[5] = enc.encode[b[5]] - dst[6] = enc.encode[b[6]] - dst[7] = enc.encode[b[7]] + dst[0] = enc.encode[b[0]&31] + dst[1] = enc.encode[b[1]&31] + dst[2] = enc.encode[b[2]&31] + dst[3] = enc.encode[b[3]&31] + dst[4] = enc.encode[b[4]&31] + dst[5] = enc.encode[b[5]&31] + dst[6] = enc.encode[b[6]&31] + dst[7] = enc.encode[b[7]&31] } else { for i := 0; i < size; i++ { - dst[i] = enc.encode[b[i]] + dst[i] = enc.encode[b[i]&31] } } From 4f6b9ed5adffbfb38f10fd1843d5f6f731ece884 Mon Sep 17 00:00:00 2001 From: Nathan Cantelmo Date: Wed, 6 Sep 2017 11:19:25 -0400 Subject: [PATCH 044/203] doc: document the lack of support for symlinks under GOPATH In an effort to help others avoid the issues I've hit due to lack of symlink support under GOPATH, I've added a note of warning to the Workspaces section. I have not changed the contents of go help gopath, because on reflection it seems this change alone may be sufficient. Fixes #21320 Change-Id: Ib8969bf12cecad878e89ff66b5864bbf3caaf219 Reviewed-on: https://go-review.googlesource.com/61930 Reviewed-by: Ian Lance Taylor --- doc/code.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/code.html b/doc/code.html index f22e6b4919..92616a5a5a 100644 --- a/doc/code.html +++ b/doc/code.html @@ -110,6 +110,10 @@ packages and commands. Most Go programmers keep all their Go source code and dependencies in a single workspace.

+

+Note that symbolic links should not be used to link files or directories into your workspace. +

+

Commands and libraries are built from different kinds of source packages. We will discuss the distinction later. From 59be2261078ebf98907317d3a9a2507eba5d015c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 12 Jun 2018 17:32:50 -0700 Subject: [PATCH 045/203] go/importer: better error message when importer is out of date Separated out panic handling for bimporter and importer so that the handler can consider the current version and report a better error. Added new export data test for export data version 999 (created by changing the compiler temporarily) and verifying expected error message. Fixes #25856. Change-Id: Iaafec07b79499154ef7c007341783fa07c57f24d Reviewed-on: https://go-review.googlesource.com/118496 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/go/internal/gcimporter/bimport.go | 27 +++++++++--------- src/go/internal/gcimporter/gcimporter.go | 23 +++++++++++---- src/go/internal/gcimporter/gcimporter_test.go | 12 ++++++++ src/go/internal/gcimporter/iimport.go | 19 ++++++++++-- .../gcimporter/testdata/versions/test.go | 5 +++- .../testdata/versions/test_go1.11_0i.a | Bin 0 -> 2420 bytes .../testdata/versions/test_go1.11_6b.a | Bin 0 -> 2426 bytes .../testdata/versions/test_go1.11_999b.a | Bin 0 -> 2600 bytes .../testdata/versions/test_go1.11_999i.a | Bin 0 -> 2420 bytes 9 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a create mode 100644 src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a create mode 100644 src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a create mode 100644 src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go index 73ce465eab..503845e31c 100644 --- a/src/go/internal/gcimporter/bimport.go +++ b/src/go/internal/gcimporter/bimport.go @@ -50,24 +50,24 @@ type importer struct { // compromised, an error is returned. func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { // catch panics and return them as errors + const currentVersion = 6 + version := -1 // unknown version defer func() { if e := recover(); e != nil { - // The package (filename) causing the problem is added to this - // error by a wrapper in the caller (Import in gcimporter.go). // Return a (possibly nil or incomplete) package unchanged (see #16088). - err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e) + if version > currentVersion { + err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) + } else { + err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + } } }() - if len(data) > 0 && data[0] == 'i' { - return iImportData(fset, imports, data[1:], path) - } - p := importer{ imports: imports, data: data, importpath: path, - version: -1, // unknown version + version: version, strList: []string{""}, // empty string is mapped to 0 pathList: []string{""}, // empty string is mapped to 0 fake: fakeFileSet{ @@ -92,7 +92,7 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data [] p.posInfoFormat = p.int() != 0 versionstr = p.string() if versionstr == "v1" { - p.version = 0 + version = 0 } } else { // Go1.8 extensible encoding @@ -100,24 +100,25 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data [] versionstr = p.rawStringln(b) if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" { if v, err := strconv.Atoi(s[1]); err == nil && v > 0 { - p.version = v + version = v } } } + p.version = version // read version specific flags - extend as necessary switch p.version { - // case 7: + // case currentVersion: // ... // fallthrough - case 6, 5, 4, 3, 2, 1: + case currentVersion, 5, 4, 3, 2, 1: p.debugFormat = p.rawStringln(p.rawByte()) == "debug" p.trackAllTypes = p.int() != 0 p.posInfoFormat = p.int() != 0 case 0: // Go1.7 encoding format - nothing to do here default: - errorf("unknown export format version %d (%q)", p.version, versionstr) + errorf("unknown bexport format version %d (%q)", p.version, versionstr) } // --- generic export data --- diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index cf89fcd1b4..d117f6fe4d 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -144,16 +144,27 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func switch hdr { case "$$\n": err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path) + case "$$B\n": var data []byte data, err = ioutil.ReadAll(buf) - if err == nil { - // TODO(gri): allow clients of go/importer to provide a FileSet. - // Or, define a new standard go/types/gcexportdata package. - fset := token.NewFileSet() - _, pkg, err = BImportData(fset, packages, data, id) - return + if err != nil { + break } + + // TODO(gri): allow clients of go/importer to provide a FileSet. + // Or, define a new standard go/types/gcexportdata package. + fset := token.NewFileSet() + + // The indexed export format starts with an 'i'; the older + // binary export format starts with a 'c', 'd', or 'v' + // (from "version"). Select appropriate importer. + if len(data) > 0 && data[0] == 'i' { + _, pkg, err = iImportData(fset, packages, data[1:], id) + } else { + _, pkg, err = BImportData(fset, packages, data, id) + } + default: err = fmt.Errorf("unknown export data header: %q", hdr) } diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index 308f93e8bd..d496f2e57d 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -141,9 +141,21 @@ func TestVersionHandling(t *testing.T) { } pkgpath := "./" + name[:len(name)-2] + if testing.Verbose() { + t.Logf("importing %s", name) + } + // test that export data can be imported _, err := Import(make(map[string]*types.Package), pkgpath, dir, nil) if err != nil { + // ok to fail if it fails with a newer version error for select files + if strings.Contains(err.Error(), "newer version") { + switch name { + case "test_go1.11_999b.a", "test_go1.11_999i.a": + continue + } + // fall through + } t.Errorf("import %q failed: %v", pkgpath, err) continue } diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go index 1d13449ef6..a333f98f3a 100644 --- a/src/go/internal/gcimporter/iimport.go +++ b/src/go/internal/gcimporter/iimport.go @@ -10,6 +10,7 @@ package gcimporter import ( "bytes" "encoding/binary" + "fmt" "go/constant" "go/token" "go/types" @@ -60,13 +61,25 @@ const ( // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { + const currentVersion = 0 + version := -1 + defer func() { + if e := recover(); e != nil { + if version > currentVersion { + err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) + } else { + err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) + } + } + }() + r := &intReader{bytes.NewReader(data), path} - version := r.uint64() + version = int(r.uint64()) switch version { - case 0: + case currentVersion: default: - errorf("cannot import %q: unknown iexport format version %d", path, version) + errorf("unknown iexport format version %d", version) } sLen := int64(r.uint64()) diff --git a/src/go/internal/gcimporter/testdata/versions/test.go b/src/go/internal/gcimporter/testdata/versions/test.go index ac9c968c2d..227fc09251 100644 --- a/src/go/internal/gcimporter/testdata/versions/test.go +++ b/src/go/internal/gcimporter/testdata/versions/test.go @@ -11,7 +11,10 @@ // // go build -o test_go1.$X_$Y.a test.go // -// with $X = Go version and $Y = export format version. +// with $X = Go version and $Y = export format version +// (add 'b' or 'i' to distinguish between binary and +// indexed format starting with 1.11 as long as both +// formats are supported). // // Make sure this source is extended such that it exercises // whatever export format change has taken place. diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a new file mode 100644 index 0000000000000000000000000000000000000000..b00fefed0462172f5f5370f9769ed19342fc0c16 GIT binary patch literal 2420 zcmd5--)q}e6h69muBw_KLdZ-RK{Y0XwvlDomSrzBA-GAqvNg0Rgub}4e66UFB}bN1 zGRnHwvDZCpu!ju#KkT)%u;;z(|JYw}yK^PWah)GyZ@WnM+1DqefAUVHk@lW)sAU!R=Z-ziAz*d$3R7Pll9 zcIA!Y&f_PKAMce$p6nHiH}FUCis}R)bTZs2 zZF!b|xb0G}ckQ0=MuV0B_x9eXpn!016NLK`U_uExPS8<$Mh9x4pq?oLj0}OT#_rqmo&#X{*fU1qhfxSD`(3C5+jDF$ zuq|)&{&(G~RkWJbrCP0AH}tATjdIsCbd8o9mRYWS5?ra+J!)g4U219-z0oiCdtFNF z{hC>?+FfAy*!r%Am2Oz$C~&AxLo1@a7O=a?4(QRj`j3Du#?EdKc%S6!>snnm>iurN zVOUzZZc?*eGi`%bsAf~$1lDo_6}O@$7Vyes0pbClCe#!zDr7zrrnKiC z)Ep?mkht`l%9?7!(MVim;V9&%Z~u} z&`C3<^pF0^eSS?8e@W;6X4CzqHjQ6P2bWkLA7fG=w}b~Xfskcb1`VgV488`UoRM-$ zM#>1;tSDrq9NyWuK~`LlLFOp3h`=S1gWMT#SHf54q z+T#odoZ&U^e&Pgo*>!b7pd|!ECs+{S7h$A2oh&h85CxPB_vkWqRYuG#M&X~SNmgMM zZB`t@P{fp{!UpC9b61q0`2t5RMmF&rp{ityyoT3k+e8ErZ43Su@LJ@R8XUD5qxKP+ q<vTbv3ss< z^@i{M(5+HID_KpdmGWgnFKX1tH%&v=Xue{Z`O*i*g@WCpHa6O%rdH4^?R>k{q_o^F zndPG01cq;^-R)tdo7O0B9Xg=C70}ieu#M;h^z>T%r@$6NWz%(gANXtQT3I*B?Pj}T zSX#bpQnOq#ZG#r5W>eh+w&l1g9z~7FZ%WTLT670(_YRYd*kn3^%dz4ze>=G2TLXvQ zL099b;V|e2cNkUCXcGAKtZc@vZ%bPyHi)vu6LB@L>x^L{u7-8p#GItDJsQ~4Z>ku_ za+7j=R;%Ys!?ONp5On)gb?jz07^+$x*mguUz^cQqy1E`-@yTbc0#jlbQd+)my#}@t zqNcv`<=Ada4{R+Wj|z%s1>uzemYwq1cmhlg_waVW#XGT@%E*cRpK2@e{*Sel%zLaX z*b}o@WcUR8pSUf&CrQAbNCJctzKp1E`2Jw33BU0TVcx?bRLyrTXZ&so(JmxrgiG3M zFKUVtu9KeLMmnaSX1KD(2;}M4A&&L2{JofNgD4tTV7E*^Yvf)G@qdtW{BF*1b6EGe zi0giCQulLl-Ot5!AJ5Q;J;wCU|4w~!PZWQR*Z(Es^Tsl^UyCQVNNyiuVj!3Jy8&PV zA!$g1hRaj}KLb%tNGT;DC4^*B6p~U3pJdn|DbC9va}-%b;1WqeY648li6jCu9GJ!j zftgF-!z)1P)5x>9Ox_6aMo1N90;DFBG&vTlu-Fq#P<{|_%>ELN?EXrGm|aCF0h89o z4C~}vfO8?GA;Z$POj1jA&d}iuXMFgX6Kt^i>X<-_2#8KFAi_IgqO4 E0@X}F`Tzg` literal 0 HcmV?d00001 diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a new file mode 100644 index 0000000000000000000000000000000000000000..c35d22dce691e67127e04ea74ddd8c97a57e22ff GIT binary patch literal 2600 zcmd5-QE%c#5MFNy=W|eEYCj zofNe{t4~#>{-OSb&aBx$f#kU>+p|0K%{Q~N-rZLxPV5d&m2OwR`tYv({kfJlV9tK4GN1>%$9hg#UXWp1K*PW)>y)|`=NRW*-&W<%|Dk5#Om*JxNw>r9#U!*r~b zP0ci$Mx$A+X{J%OwbuqT?WWm}oe_(|V4Sd6=}m*7rv;u?yl%MV_s08v?Wf6Q6m@>S zx_JAs)U_|7*t!_KtKHs)x1H;^ei#;&H_#MC+23y|pIJN!!m-w9G!%tU=~==i2_YNG z@A|fKfBo+A$IHvk#w2#X^22Q&a_kIW_--(Y!Wa_RM!e@F&i0IHqM%0i!xycgGydf~ zU_+05O{vr+l#orjNhAW1m98Il^>AK5QK?63X_$73{$JMel|qOgmK#G)BLDpLr;&V# zn63|;$v`g_^@UP^kwyqP;Ej138~ZV%zGZv9{g znV&e*B=p&s#ZJP!Q?wnYb7FUEW^{*u9S-P);czK(-!$r`Rqyxu4a+ggb(`7sn(bPw z!VH(0Ho{N+P=|@>X^{1WI|EEG?uSo;jsdh=}V&d^_VEymMv z5{#JcyS*Tp=tdb=^(-YE!-<85gnq;ihxvBU5u^!MAa>%|`GU%Q?zyr%_5^ko2BC*( zkn~83oP=*VG!&Pjci*5^9g-`C$oe6cpk{Da~(`lDJVy;zog4 zbVW=-{{e#MzIi6gvuXw^X8{AKl@uyEI2~bJx6@$%1PEUGwmQYvIB5<$qk2Z$*50 zk75>_FIQD5p>37s>5beZJ44wf8d^aX7v%GO;k|hPJq4YWL!pz878ng++&xoiZnuMs z17y5kpgjiH=els+Gz1+rDI`qsK{i@_81CZGq8iaMXf;*%R8ePV0gI{7COseryqA?D z63LJRsHGFggVXp7#Hd+yYxGLd9RSj+|6dE7!@>Xn literal 0 HcmV?d00001 diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a new file mode 100644 index 0000000000000000000000000000000000000000..99401d7c37ca48fbca32f0448b71606b7f853ce4 GIT binary patch literal 2420 zcmd5-&uimG6n+|9N2{11LU7Geg4UQ2(nOZ!Uy7R;W4zgI15L=fG&ip-j}>(l%aP@5 z1EJe%>9vOzdPrgahhCRm=((5v4ZZd+nDmWgC0^&p(pv{<-psuBeecaDjr3^C^sS@1 z)aj`EyH8q=ca*4U6U$9Bj`~We6ngYZWEJJPWP6I&{f1hB(lh;+&OkAbd+6@bQ|c<8 zmWzf_EK|}RnwHiTHiO1>Ckfq0rjQs*l~M` z(^Im$U%veM#jyKq|CxPI9T!}uqv`px)3g4;aP;{oXzzd9(!9g7QZ*}WV3Q;%mupJS z-*fx&R_@8(!QNgwKk}`-?d3!2f$8RL%Q+r;J|@ZsbQJW=z|5agf8=dW>OKs7V9D=%9a!78T+cGy z(c9m3vs~25W|wN^LbaloG+HTijf$?(!lr2y%I^gii&l?X*l3p;T2bHZ7y7*}rPY4f zsFtiQFnnr#$Hhvw%yHn^bU=MGpuIY<^=Jq5^7VDCs#mK0Zhy04 zYK5vnjcVDjDzr#7i|Pijy6vgB6*VHiO`ZluID@`-Psn;4GArP6?6}gei7UQ2u<1Q? zEsh$Eg5%(xpc)2U7k*QftvK~vvSs3cNHs3RbYV9cLm{Tix*1|z%h(?etl1}3ifg&e zIoYe}+Ox2%KOO|mF;#7=>jWcJD*$UmR0I6p@T0G;@pC@)TC2d67>1Ol@0(}9av^Hw zEnkk~CiK8oBl742Gc<$n$NpzUBRcnI`(tQxc$`tI5;b)!vS0ntc=WXBNKY;)8AHY3y z;*2rW<9?>Dw_{AxV7!}9nL69c&=JeUcDq#+F&PE!ed4MaI1rIdt} z5RyqzNJ=TZlVO9TxFCbfQDhN;OC$xUYhYSVBoUb5z%1wjXNQEe%B)CVHu`4lRBryvAOf|9sD`=DA z5QZYAyb!i9Cm8#p1hwZlsx#8SbA+mrCOL<5v@Ifnh_(*@2zV{>N-G@I2vLU!O>$^+ nD3dor{X)Qn<{JT5T7U9>hmi$T8}%kKFB9# Date: Wed, 13 Jun 2018 03:43:12 +0000 Subject: [PATCH 046/203] doc/contribute.html: add whitespace after blocks, where missing Change-Id: Iea5c705dd58f9b83fbeb0500defcc08c34716169 GitHub-Last-Rev: 35702c784e2329fe3e44947430d246f8cdb04645 GitHub-Pull-Request: golang/go#25858 Reviewed-on: https://go-review.googlesource.com/118536 Reviewed-by: Brad Fitzpatrick --- doc/contribute.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/contribute.html b/doc/contribute.html index d802bd72a1..5f6af2c93c 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -418,7 +418,7 @@ $ ./all.bash # recompile and test

  • Step 4: Send the changes for review to Gerrit using git -codereview mail(which doesn't use e-mail, despite the name). +codereview mail (which doesn't use e-mail, despite the name).
     $ git codereview mail     # send changes to Gerrit
     
    @@ -984,8 +984,8 @@ followed by run.bash.
  • In this section, we'll call the directory into which you cloned the Go repository $GODIR. -The go tool built by $GODIR/make.bashwill be installed -in $GODIR/bin/goand you +The go tool built by $GODIR/make.bash will be installed +in $GODIR/bin/go and you can invoke it to test your code. For instance, if you have modified the compiler and you want to test how it affects the From f297d165c9b6518151f50eb59cec9bd95794986b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 12 Jun 2018 16:41:14 -0700 Subject: [PATCH 047/203] encoding/gob: correct issue number typo in comment Change-Id: I3ac25cf1770b5ac0d36690c37615b3badd27463d Reviewed-on: https://go-review.googlesource.com/118455 Reviewed-by: Rob Pike --- src/encoding/gob/encoder_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index a41fc9e889..dc9bbcf35d 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -1015,7 +1015,7 @@ type Bug4Secret struct { } // Test that a failed compilation doesn't leave around an executable encoder. -// Issue 3273. +// Issue 3723. func TestMutipleEncodingsOfBadType(t *testing.T) { x := Bug4Public{ Name: "name", From 1041ac8781be0fc6b7108b8270f583660e72ec77 Mon Sep 17 00:00:00 2001 From: Suriyaa Sundararuban Date: Wed, 13 Jun 2018 07:06:04 +0000 Subject: [PATCH 048/203] doc: use HTTPS for links Change-Id: I9d2d25df067ca573589db5ff18296a5ec33866be Reviewed-on: https://go-review.googlesource.com/118595 Reviewed-by: Ian Lance Taylor --- doc/code.html | 2 +- doc/contribute.html | 2 +- doc/debugging_with_gdb.html | 2 +- doc/docs.html | 2 +- doc/editors.html | 2 +- doc/gccgo_contribute.html | 6 +++--- doc/gccgo_install.html | 10 +++++----- doc/go1.2.html | 4 ++-- doc/go1.4.html | 10 +++++----- doc/go_faq.html | 10 +++++----- doc/go_spec.html | 10 +++++----- doc/install-source.html | 4 ++-- doc/install.html | 2 +- 13 files changed, 33 insertions(+), 33 deletions(-) diff --git a/doc/code.html b/doc/code.html index 92616a5a5a..c0efcde66f 100644 --- a/doc/code.html +++ b/doc/code.html @@ -673,7 +673,7 @@ articles about the Go language and its libraries and tools.

    For real-time help, ask the helpful gophers in #go-nuts on the -Freenode IRC server. +Freenode IRC server.

    diff --git a/doc/contribute.html b/doc/contribute.html index 5f6af2c93c..e7970537dd 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -639,7 +639,7 @@ The existing implementation has poor numerical properties for large arguments, so use the McGillicutty algorithm to improve accuracy above 1e10. -The algorithm is described at http://wikipedia.org/wiki/McGillicutty_Algorithm +The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm Fixes #159 diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html index 19d36f7d97..ca9d9a7c46 100644 --- a/doc/debugging_with_gdb.html +++ b/doc/debugging_with_gdb.html @@ -47,7 +47,7 @@ In short, the instructions below should be taken only as a guide to how to use GDB when it works, not as a guarantee of success. Besides this overview you might want to consult the -GDB manual. +GDB manual.

    diff --git a/doc/docs.html b/doc/docs.html index 21a9a63d51..955eb3044e 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -195,7 +195,7 @@ See the Articles page at the -

    A Video Tour of Go

    +

    A Video Tour of Go

    Three things that make Go fast, fun, and productive: interfaces, reflection, and concurrency. Builds a toy web crawler to diff --git a/doc/editors.html b/doc/editors.html index 617a100130..6f787864c6 100644 --- a/doc/editors.html +++ b/doc/editors.html @@ -9,7 +9,7 @@ This document lists commonly used editor plugins and IDEs from the Go ecosystem that make Go development more productive and seamless. A comprehensive list of editor support and IDEs for Go development is available at - the wiki. + the wiki.

    Options

    diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html index 1286fcc2be..6374cd0cbe 100644 --- a/doc/gccgo_contribute.html +++ b/doc/gccgo_contribute.html @@ -22,7 +22,7 @@ file HACKING in the gofrontend repository. You must follow the Go copyright rules for all changes to the gccgo frontend and the associated libgo library. Code that is part of GCC rather than gccgo must follow -the general GCC +the general GCC contribution rules.

    @@ -30,9 +30,9 @@ contribution rules.

    The master sources for the gccgo frontend may be found at -http://go.googlesource.com/gofrontend. +https://go.googlesource.com/gofrontend. They are mirrored -at http://github.com/golang/gofrontend. +at https://github.com/golang/gofrontend. The master sources are not buildable by themselves, but only in conjunction with GCC (in the future, other compilers may be supported). Changes made to the gccgo frontend are also applied to diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html index d4eac12f11..a974bb3680 100644 --- a/doc/gccgo_install.html +++ b/doc/gccgo_install.html @@ -9,7 +9,7 @@ the Go language. The gccgo compiler is a new frontend for GCC, the widely used GNU compiler. Although the frontend itself is under a BSD-style license, gccgo is normally used as part of GCC and is then covered by -the GNU General Public +the GNU General Public License (the license covers gccgo itself as part of GCC; it does not cover code generated by gccgo).

    @@ -25,7 +25,7 @@ compiler.

    The simplest way to install gccgo is to install a GCC binary release built to include Go support. GCC binary releases are available from -various +various websites and are typically included as part of GNU/Linux distributions. We expect that most people who build these binaries will include Go support. @@ -79,7 +79,7 @@ If you cannot use a release, or prefer to build gccgo for yourself, the gccgo source code is accessible via Subversion. The GCC web site -has instructions for getting the +has instructions for getting the GCC source code. The gccgo source code is included. As a convenience, a stable version of the Go support is available in a branch of the main GCC code @@ -101,7 +101,7 @@ gccgo.

    Building gccgo is just like building GCC with one or two additional options. See -the instructions on the gcc web +the instructions on the gcc web site. When you run configure, add the option --enable-languages=c,c++,go (along with other languages you may want to build). If you are targeting a 32-bit x86, @@ -156,7 +156,7 @@ option --with-ld=GOLD_BINARY.

    A number of prerequisites are required to build GCC, as described on -the gcc web +the gcc web site. It is important to install all the prerequisites before running the gcc configure script. The prerequisite libraries can be conveniently downloaded using the diff --git a/doc/go1.2.html b/doc/go1.2.html index 5370bbbbd6..1f6051418c 100644 --- a/doc/go1.2.html +++ b/doc/go1.2.html @@ -860,13 +860,13 @@ The new build tag netgo (off by default) allows the construction of The net package adds a new field DualStack to the Dialer struct for TCP connection setup using a dual IP stack as described in -RFC 6555. +RFC 6555.

  • The net/http package will no longer transmit cookies that are incorrect according to -RFC 6265. +RFC 6265. It just logs an error and sends nothing. Also, the net/http package's diff --git a/doc/go1.4.html b/doc/go1.4.html index ca44d56ceb..c8f7c9c525 100644 --- a/doc/go1.4.html +++ b/doc/go1.4.html @@ -420,7 +420,7 @@ to automate the running of tools to generate source code before compilation. For example, it can be used to run the yacc compiler-compiler on a .y file to produce the Go source file implementing the grammar, or to automate the generation of String methods for typed constants using the new -stringer +stringer tool in the golang.org/x/tools subrepository.

    @@ -619,9 +619,9 @@ has been created to serve as the location for new developments to support system calls on all kernels. It has a nicer structure, with three packages that each hold the implementation of system calls for one of -Unix, -Windows and -Plan 9. +Unix, +Windows and +Plan 9. These packages will be curated more generously, accepting all reasonable changes that reflect kernel interfaces in those operating systems. See the documentation and the article mentioned above for more information. @@ -670,7 +670,7 @@ The crypto package now has a
  • The crypto/tls package -now supports ALPN as defined in RFC 7301. +now supports ALPN as defined in RFC 7301.
  • diff --git a/doc/go_faq.html b/doc/go_faq.html index cc81e49a9b..e83408e6f1 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -97,14 +97,14 @@ What's the origin of the mascot?

    The mascot and logo were designed by -Renée French, who also designed +Renée French, who also designed Glenda, the Plan 9 bunny. The gopher -is derived from one she used for an WFMU +is derived from one she used for an WFMU T-shirt design some years ago. The logo and mascot are covered by the -Creative Commons Attribution 3.0 +Creative Commons Attribution 3.0 license.

    @@ -1929,7 +1929,7 @@ func main() {

    Nowadays, most Go programmers use a tool, -goimports, +goimports, which automatically rewrites a Go source file to have the correct imports, eliminating the unused imports issue in practice. This program is easily connected to most editors to run automatically when a Go source file is written. @@ -1968,7 +1968,7 @@ The slowest depend on libraries for which versions of comparable performance are not available in Go. For instance, pidigits.go depends on a multi-precision math package, and the C -versions, unlike Go's, use GMP (which is +versions, unlike Go's, use GMP (which is written in optimized assembler). Benchmarks that depend on regular expressions (regex-dna.go, diff --git a/doc/go_spec.html b/doc/go_spec.html index f1300c105a..f70ff7a02f 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -69,7 +69,7 @@ language.

    Source code is Unicode text encoded in -UTF-8. The text is not +UTF-8. The text is not canonicalized, so a single accented code point is distinct from the same character constructed from combining an accent and a letter; those are treated as two code points. For simplicity, this document @@ -104,7 +104,7 @@ unicode_digit = /* a Unicode code point classified as "Number, decimal digit" *

    -In The Unicode Standard 8.0, +In The Unicode Standard 8.0, Section 4.5 "General Category" defines a set of character categories. Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo as Unicode letters, and those in the Number category Nd as Unicode digits. @@ -793,7 +793,7 @@ rune alias for int32

    The value of an n-bit integer is n bits wide and represented using -two's complement arithmetic. +two's complement arithmetic.

    @@ -3543,7 +3543,7 @@ x = q*y + r and |r| < |y|

    with x / y truncated towards zero -("truncated division"). +("truncated division").

    @@ -6109,7 +6109,7 @@ package and may be relative to a repository of installed packages.
     

    Implementation restriction: A compiler may restrict ImportPaths to non-empty strings using only characters belonging to -Unicode's +Unicode's L, M, N, P, and S general categories (the Graphic characters without spaces) and may also exclude the characters !"#$%&'()*,:;<=>?[\]^`{|} diff --git a/doc/install-source.html b/doc/install-source.html index 1928b0ba9b..844fb002f7 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -197,7 +197,7 @@ have a git command before proceeding.)

    If you do not have a working Git installation, follow the instructions on the -Git downloads page. +Git downloads page.

    (Optional) Install a C compiler

    @@ -388,7 +388,7 @@ You can access the latter commands with

    The usual community resources such as -#go-nuts on the Freenode IRC server +#go-nuts on the Freenode IRC server and the Go Nuts mailing list have active developers that can help you with problems diff --git a/doc/install.html b/doc/install.html index f3b3f97fb8..cd51e7603a 100644 --- a/doc/install.html +++ b/doc/install.html @@ -57,7 +57,7 @@ If your OS or architecture is not on the list, you may be able to A C compiler is required only if you plan to use cgo.
    You only need to install the command line tools for -Xcode. If you have already +Xcode. If you have already installed Xcode 4.3+, you can install it from the Components tab of the Downloads preferences panel.

    From ee2e8ecb19d986c42941af96ad8647cb0bf81996 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 12 Jun 2018 16:40:52 -0400 Subject: [PATCH 049/203] cmd/go: fix go list usage line CL 108156 added -cgo and -export, but in the usage line it added -cgo and -list. CL 117015 correctly added -export to the usage line. All that remains is to remove -list. Change-Id: I8cc5cfc78bc6b52080ae1b861f92620a8f18b53f Reviewed-on: https://go-review.googlesource.com/118375 Run-TryBot: Russ Cox Reviewed-by: Bryan C. Mills TryBot-Result: Gobot Gobot --- src/cmd/go/alldocs.go | 2 +- src/cmd/go/internal/list/list.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 3494601e69..d37942b738 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -579,7 +579,7 @@ // // Usage: // -// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-list] [-test] [build flags] [packages] +// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages] // // List lists the packages named by the import paths, one per line. // diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index d519dcc5e0..218999c7e8 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -23,7 +23,7 @@ import ( ) var CmdList = &base.Command{ - UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-list] [-test] [build flags] [packages]", + UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages]", Short: "list packages", Long: ` List lists the packages named by the import paths, one per line. From 16caec5892c67ae322be192841d9f15cb2f1c0bc Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 13 Jun 2018 10:51:17 +0200 Subject: [PATCH 050/203] cmd/dist, go/types: add support for GOARCH=riscv64 This is needed in addition to CL 110066 in order to be able to generate Go type definitions for linux/riscv64 in the golang.org/x/sys/unix package. Change-Id: I4a27e6424aaea63283b55bd4f73b958b41f29d72 Reviewed-on: https://go-review.googlesource.com/118618 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/dist/build.go | 2 ++ src/cmd/vet/all/main.go | 5 +++++ src/go/types/sizes.go | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index effea903e9..616e76dfe7 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -67,6 +67,7 @@ var okgoarch = []string{ "mips64le", "ppc64", "ppc64le", + "riscv64", "s390x", "wasm", } @@ -1393,6 +1394,7 @@ var cgoEnabled = map[string]bool{ "linux/mipsle": true, "linux/mips64": true, "linux/mips64le": true, + "linux/riscv64": true, "linux/s390x": true, "android/386": true, "android/amd64": true, diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go index 6c56daff03..4b1df73b54 100644 --- a/src/cmd/vet/all/main.go +++ b/src/cmd/vet/all/main.go @@ -197,6 +197,11 @@ func (p platform) vet() { fmt.Println("skipping js/wasm") return } + if p.os == "linux" && p.arch == "riscv64" { + // TODO(tklauser): enable as soon as the riscv64 port has fully landed + fmt.Println("skipping linux/riscv64") + return + } var buf bytes.Buffer fmt.Fprintf(&buf, "go run main.go -p %s\n", p) diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go index fda0c95469..7b5410167f 100644 --- a/src/go/types/sizes.go +++ b/src/go/types/sizes.go @@ -167,6 +167,7 @@ var gcArchSizes = map[string]*StdSizes{ "mips64le": {8, 8}, "ppc64": {8, 8}, "ppc64le": {8, 8}, + "riscv64": {8, 8}, "s390x": {8, 8}, "wasm": {8, 8}, // When adding more architectures here, @@ -178,7 +179,7 @@ var gcArchSizes = map[string]*StdSizes{ // // Supported architectures for compiler "gc": // "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle", -// "mips64", "mips64le", "ppc64", "ppc64le", "s390x", "wasm". +// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm". func SizesFor(compiler, arch string) Sizes { if compiler != "gc" { return nil From 7b2f55d89f12a539df6cf57d60b2b6b605cbb34a Mon Sep 17 00:00:00 2001 From: Hana Kim Date: Tue, 12 Jun 2018 12:01:59 -0400 Subject: [PATCH 051/203] runtime/pprof: set HasFunctions of mapping entries The pprof tool utilizes attributes of mapping entries such as HasFunctions to determine whether the profile includes necessary symbol information. If none of the attributes is set, pprof tool tries to read the corresponding binary to use for local symbolization. If the binary doesn't exist, it prints out error messages. Go runtime generated profiles without any of the attributes set so the pprof tool always printed out the error messages. The error messages became more obvious with the new terminal support that uses red color for error messages. Go runtime can symbolize all Go symbols and generate self-contained profile for pure Go program. Thus, there is no reason for the pprof tool to look for the copy of the binary. So, this CL sets one of the attributes (HasFunctions) true if all PCs in samples look fully symbolized. For non-pure Go program, however, it's possible that symbolization of non-Go PCs is incomplete. In this case, we need to leave the attributes all false so pprof can attempt to symbolize using the local copy of the binary if available. It's hard to determine whether a mapping includes non-Go code. Instead, this CL checks PCs from collected samples. If unsuccessful symbolization is observed, it skips setting the HasFunctions attribute. Fixes #25743 Change-Id: I5108be45bbc37ab486d145fa03e7ce37d88fad50 Reviewed-on: https://go-review.googlesource.com/118275 Run-TryBot: Hyang-Ah Hana Kim TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/pprof/proto.go | 65 ++++++++--- src/runtime/pprof/proto_test.go | 69 ++++++++++++ .../pprof/testdata/mappingtest/main.go | 105 ++++++++++++++++++ 3 files changed, 226 insertions(+), 13 deletions(-) create mode 100644 src/runtime/pprof/testdata/mappingtest/main.go diff --git a/src/runtime/pprof/proto.go b/src/runtime/pprof/proto.go index d67c3a2865..1cf3a5154f 100644 --- a/src/runtime/pprof/proto.go +++ b/src/runtime/pprof/proto.go @@ -11,7 +11,6 @@ import ( "io" "io/ioutil" "runtime" - "sort" "strconv" "time" "unsafe" @@ -48,10 +47,26 @@ type profileBuilder struct { } type memMap struct { - start uintptr - end uintptr + // initialized as reading mapping + start uintptr + end uintptr + offset uint64 + file, buildID string + + funcs symbolizeFlag } +// symbolizeFlag keeps track of symbolization result. +// 0 : no symbol lookup was performed +// 1<<0 (lookupTried) : symbol lookup was performed +// 1<<1 (lookupFailed): symbol lookup was performed but failed +type symbolizeFlag uint8 + +const ( + lookupTried symbolizeFlag = 1 << iota + lookupFailed symbolizeFlag = 1 << iota +) + const ( // message Profile tagProfile_SampleType = 1 // repeated ValueType @@ -171,7 +186,7 @@ func (b *profileBuilder) pbLine(tag int, funcID uint64, line int64) { } // pbMapping encodes a Mapping message to b.pb. -func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file, buildID string) { +func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file, buildID string, hasFuncs bool) { start := b.pb.startMessage() b.pb.uint64Opt(tagMapping_ID, id) b.pb.uint64Opt(tagMapping_Start, base) @@ -179,8 +194,15 @@ func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file b.pb.uint64Opt(tagMapping_Offset, offset) b.pb.int64Opt(tagMapping_Filename, b.stringIndex(file)) b.pb.int64Opt(tagMapping_BuildID, b.stringIndex(buildID)) - // TODO: Set any of HasInlineFrames, HasFunctions, HasFilenames, HasLineNumbers? - // It seems like they should all be true, but they've never been set. + // TODO: we set HasFunctions if all symbols from samples were symbolized (hasFuncs). + // Decide what to do about HasInlineFrames and HasLineNumbers. + // Also, another approach to handle the mapping entry with + // incomplete symbolization results is to dupliace the mapping + // entry (but with different Has* fields values) and use + // different entries for symbolized locations and unsymbolized locations. + if hasFuncs { + b.pb.bool(tagMapping_HasFunctions, true) + } b.pb.endMessage(tag, start) } @@ -205,6 +227,11 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 { return 0 } + symbolizeResult := lookupTried + if frame.PC == 0 || frame.Function == "" || frame.File == "" || frame.Line == 0 { + symbolizeResult |= lookupFailed + } + if frame.PC == 0 { // If we failed to resolve the frame, at least make up // a reasonable call PC. This mostly happens in tests. @@ -239,12 +266,14 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 { } frame, more = frames.Next() } - if len(b.mem) > 0 { - i := sort.Search(len(b.mem), func(i int) bool { - return b.mem[i].end > addr - }) - if i < len(b.mem) && b.mem[i].start <= addr && addr < b.mem[i].end { + for i := range b.mem { + if b.mem[i].start <= addr && addr < b.mem[i].end { b.pb.uint64Opt(tagLocation_MappingID, uint64(i+1)) + + m := b.mem[i] + m.funcs |= symbolizeResult + b.mem[i] = m + break } } b.pb.endMessage(tagProfile_Location, start) @@ -392,6 +421,11 @@ func (b *profileBuilder) build() { b.pbSample(values, locs, labels) } + for i, m := range b.mem { + hasFunctions := m.funcs == lookupTried // lookupTried but not lookupFailed + b.pbMapping(tagProfile_Mapping, uint64(i+1), uint64(m.start), uint64(m.end), m.offset, m.file, m.buildID, hasFunctions) + } + // TODO: Anything for tagProfile_DropFrames? // TODO: Anything for tagProfile_KeepFrames? @@ -506,6 +540,11 @@ func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file, } func (b *profileBuilder) addMapping(lo, hi, offset uint64, file, buildID string) { - b.mem = append(b.mem, memMap{uintptr(lo), uintptr(hi)}) - b.pbMapping(tagProfile_Mapping, uint64(len(b.mem)), lo, hi, offset, file, buildID) + b.mem = append(b.mem, memMap{ + start: uintptr(lo), + end: uintptr(hi), + offset: offset, + file: file, + buildID: buildID, + }) } diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go index 78bb84412f..9efcaeafe0 100644 --- a/src/runtime/pprof/proto_test.go +++ b/src/runtime/pprof/proto_test.go @@ -8,7 +8,10 @@ import ( "bytes" "encoding/json" "fmt" + "internal/testenv" "io/ioutil" + "os" + "os/exec" "reflect" "runtime" "runtime/pprof/internal/profile" @@ -225,3 +228,69 @@ func TestProcSelfMaps(t *testing.T) { } } } + +// TestMapping checkes the mapping section of CPU profiles +// has the HasFunctions field set correctly. If all PCs included +// in the samples are successfully symbolized, the corresponding +// mapping entry (in this test case, only one entry) should have +// its HasFunctions field set true. +// The test generates a CPU profile that includes PCs from C side +// that the runtime can't symbolize. See ./testdata/mappingtest. +func TestMapping(t *testing.T) { + testenv.MustHaveGoRun(t) + + prog := "./testdata/mappingtest" + + // GoOnly includes only Go symbols that runtime will symbolize. + // Go+C includes C symbols that runtime will not symbolize. + for _, traceback := range []string{"GoOnly", "Go+C"} { + t.Run("traceback"+traceback, func(t *testing.T) { + cmd := exec.Command("go", "run", prog) + if traceback != "GoOnly" { + cmd.Env = append(os.Environ(), "SETCGOTRACEBACK=1") + } + cmd.Stderr = new(bytes.Buffer) + + out, err := cmd.Output() + if err != nil { + t.Fatalf("failed to run the test program %q: %v\n%v", prog, err, cmd.Stderr) + } + + prof, err := profile.Parse(bytes.NewReader(out)) + if err != nil { + t.Fatalf("failed to parse the generated profile data: %v", err) + } + + allResolved := !hasUnresolvedSymbol(prof) + if allResolved && traceback != "GoOnly" { + t.Log("No non-Go samples were sampled") + } + + for _, m := range prof.Mapping { + if !strings.Contains(m.File, "/exe/main") { + continue + } + if allResolved && !m.HasFunctions { + t.Errorf("HasFunctions=%t when all sampled PCs were symbolized\n%s", m.HasFunctions, prof) + } + if !allResolved && m.HasFunctions { + t.Errorf("HasFunctions=%t when some sampled PCs were not symbolized\n%s", m.HasFunctions, prof) + } + } + }) + } +} + +func hasUnresolvedSymbol(prof *profile.Profile) bool { + for _, loc := range prof.Location { + if len(loc.Line) == 0 { + return true + } + l := loc.Line[0] + f := l.Function + if l.Line == 0 || f == nil || f.Name == "" || f.Filename == "" { + return true + } + } + return false +} diff --git a/src/runtime/pprof/testdata/mappingtest/main.go b/src/runtime/pprof/testdata/mappingtest/main.go new file mode 100644 index 0000000000..7850faab0d --- /dev/null +++ b/src/runtime/pprof/testdata/mappingtest/main.go @@ -0,0 +1,105 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This program outputs a CPU profile that includes +// both Go and Cgo stacks. This is used by the mapping info +// tests in runtime/pprof. +// +// If SETCGOTRACEBACK=1 is set, the CPU profile will includes +// PCs from C side but they will not be symbolized. +package main + +/* +#include +#include + +int cpuHogCSalt1 = 0; +int cpuHogCSalt2 = 0; + +void CPUHogCFunction() { + int foo = cpuHogCSalt1; + int i; + for (i = 0; i < 100000; i++) { + if (foo > 0) { + foo *= foo; + } else { + foo *= foo + 1; + } + cpuHogCSalt2 = foo; + } +} + +struct CgoTracebackArg { + uintptr_t context; + uintptr_t sigContext; + uintptr_t *buf; + uintptr_t max; +}; + +void CollectCgoTraceback(void* parg) { + struct CgoTracebackArg* arg = (struct CgoTracebackArg*)(parg); + arg->buf[0] = (uintptr_t)(CPUHogCFunction); + arg->buf[1] = 0; +}; +*/ +import "C" + +import ( + "log" + "os" + "runtime" + "runtime/pprof" + "time" + "unsafe" +) + +func init() { + if v := os.Getenv("SETCGOTRACEBACK"); v == "1" { + // Collect some PCs from C-side, but don't symbolize. + runtime.SetCgoTraceback(0, unsafe.Pointer(C.CollectCgoTraceback), nil, nil) + } +} + +func main() { + go cpuHogGoFunction() + go cpuHogCFunction() + runtime.Gosched() + + if err := pprof.StartCPUProfile(os.Stdout); err != nil { + log.Fatal("can't start CPU profile: ", err) + } + time.Sleep(1 * time.Second) + pprof.StopCPUProfile() + + if err := os.Stdout.Close(); err != nil { + log.Fatal("can't write CPU profile: ", err) + } +} + +var salt1 int +var salt2 int + +func cpuHogGoFunction() { + // Generates CPU profile samples including a Go call path. + for { + foo := salt1 + for i := 0; i < 1e5; i++ { + if foo > 0 { + foo *= foo + } else { + foo *= foo + 1 + } + salt2 = foo + } + runtime.Gosched() + } +} + +func cpuHogCFunction() { + // Generates CPU profile samples including a Cgo call path. + for { + C.CPUHogCFunction() + runtime.Gosched() + } +} From 72ce047a6ceae5490bb5e7d7cfb635463cdc6ea2 Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Wed, 13 Jun 2018 10:36:01 +0200 Subject: [PATCH 052/203] misc/wasm: remove use of performance.timeOrigin This commit changes wasm_exec.js to not depend on the existence of performance.timeOrigin. The field is not yet supported on all browsers, e.g. it is unavailable on Safari. Change-Id: I6cd3834376c1c55424c29166fde1219f0d4d338f Reviewed-on: https://go-review.googlesource.com/118617 Reviewed-by: Brad Fitzpatrick --- misc/wasm/wasm_exec.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js index 151de2e2d1..de4cff7d2c 100755 --- a/misc/wasm/wasm_exec.js +++ b/misc/wasm/wasm_exec.js @@ -16,13 +16,11 @@ }, }; - const now = () => { - const [sec, nsec] = process.hrtime(); - return sec * 1000 + nsec / 1000000; - }; global.performance = { - timeOrigin: Date.now() - now(), - now: now, + now() { + const [sec, nsec] = process.hrtime(); + return sec * 1000 + nsec / 1000000; + }, }; const util = require("util"); @@ -116,6 +114,7 @@ return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); } + const timeOrigin = Date.now() - performance.now(); this.importObject = { go: { // func wasmExit(code int32) @@ -133,7 +132,7 @@ // func nanotime() int64 "runtime.nanotime": (sp) => { - setInt64(sp + 8, (performance.timeOrigin + performance.now()) * 1000000); + setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); }, // func walltime() (sec int64, nsec int32) From a2f72cc80d3c8cbda793959c3186c76e004532af Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 13 Jun 2018 15:40:50 +0200 Subject: [PATCH 053/203] syscall: support Linux syscalls without error return on mipsx/mips64x Like on other architectures, use rawSyscallNoError for Linux syscalls that don't return an error and convert all applicable occurences of RawSyscall to use it instead. This was missed in CL 84485 because mkall.sh doesn't support mipsx/mips64x, so add the corresponding entries as well. Updates #22924 Change-Id: I762cbee0827140b9890c4a10830e0b4cd33de92f Reviewed-on: https://go-review.googlesource.com/118655 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/syscall/mkall.sh | 30 ++++++++++++++++++++++++++ src/syscall/zsyscall_linux_mips.go | 16 +++++++------- src/syscall/zsyscall_linux_mips64.go | 16 +++++++------- src/syscall/zsyscall_linux_mips64le.go | 16 +++++++------- src/syscall/zsyscall_linux_mipsle.go | 16 +++++++------- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh index cd0783e876..b381b93161 100755 --- a/src/syscall/mkall.sh +++ b/src/syscall/mkall.sh @@ -189,6 +189,36 @@ linux_arm64) # API consistent between platforms. mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" ;; +linux_mips) + GOOSARCH_in=syscall_linux_mipsx.go + unistd_h=/usr/include/asm/unistd.h + mksyscall="./mksyscall.pl -b32 -arm" + mkerrors="$mkerrors" + mksysnum="./mksysnum_linux.pl $unistd_h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +linux_mipsle) + GOOSARCH_in=syscall_linux_mipsx.go + unistd_h=/usr/include/asm/unistd.h + mksyscall="./mksyscall.pl -l32 -arm" + mkerrors="$mkerrors" + mksysnum="./mksysnum_linux.pl $unistd_h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +linux_mips64) + GOOSARCH_in=syscall_linux_mips64x.go + unistd_h=/usr/include/asm/unistd.h + mkerrors="$mkerrors -m64" + mksysnum="./mksysnum_linux.pl $unistd_h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; +linux_mips64le) + GOOSARCH_in=syscall_linux_mips64x.go + unistd_h=/usr/include/asm/unistd.h + mkerrors="$mkerrors -m64" + mksysnum="./mksysnum_linux.pl $unistd_h" + mktypes="GOARCH=$GOARCH go tool cgo -godefs" + ;; linux_ppc64) GOOSARCH_in=syscall_linux_ppc64x.go unistd_h=/usr/include/asm/unistd.h diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go index d304dd784c..df65776170 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -492,7 +492,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1169,7 +1169,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1177,7 +1177,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1185,7 +1185,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1193,7 +1193,7 @@ func Getgid() (gid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 83ad1a028e..701f39a252 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -492,7 +492,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1179,7 +1179,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1187,7 +1187,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1195,7 +1195,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1213,7 +1213,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index 331e1c89d6..c7976c9207 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -492,7 +492,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1179,7 +1179,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1187,7 +1187,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1195,7 +1195,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1213,7 +1213,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go index 363e3a734f..c3e8d92035 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -492,7 +492,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1169,7 +1169,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1177,7 +1177,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1185,7 +1185,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1193,7 +1193,7 @@ func Getgid() (gid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } From 24d29e85cb98010216012e0524f41b4f092b01cc Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 13 Jun 2018 15:12:28 +0000 Subject: [PATCH 054/203] net/http: make Transport.RoundTrip check context.Done earlier Fixes #25852 Change-Id: I35c630367c8f1934dcffc0b0e08891d55a903518 Reviewed-on: https://go-review.googlesource.com/118560 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Andrew Bonventre --- src/net/http/transport.go | 7 +++++++ src/net/http/transport_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 9b5ea52c9b..a298e2ef03 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -370,6 +370,13 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { } for { + select { + case <-ctx.Done(): + req.closeBody() + return nil, ctx.Err() + default: + } + // treq gets modified by roundTrip, so we need to recreate for each retry. treq := &transportRequest{Request: req, trace: trace} cm, err := t.connectMethodForRequest(treq) diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 01a209c633..a02867a2d0 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -4544,3 +4544,28 @@ func TestNoBodyOnChunked304Response(t *testing.T) { type funcWriter func([]byte) (int, error) func (f funcWriter) Write(p []byte) (int, error) { return f(p) } + +type doneContext struct { + context.Context + err error +} + +func (doneContext) Done() <-chan struct{} { + c := make(chan struct{}) + close(c) + return c +} + +func (d doneContext) Err() error { return d.err } + +// Issue 25852: Transport should check whether Context is done early. +func TestTransportCheckContextDoneEarly(t *testing.T) { + tr := &Transport{} + req, _ := NewRequest("GET", "http://fake.example/", nil) + wantErr := errors.New("some error") + req = req.WithContext(doneContext{context.Background(), wantErr}) + _, err := tr.RoundTrip(req) + if err != wantErr { + t.Errorf("error = %v; want %v", err, wantErr) + } +} From a1b85ee754f84899b1bd7460c0a51630541dc3da Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 13 Jun 2018 17:42:22 +0000 Subject: [PATCH 055/203] Revert "cmd/link: separate virtual address layout from file layout" This reverts commit bd83774593bca66cc899d5180c77680bc907fab8. Reason for revert: This broke ELF layout on arm, arm64, mips*, mips64*, ppc64*, and s390x. Change-Id: I56a27b76e6f4b22ce39a99790af9116f8687eee9 Reviewed-on: https://go-review.googlesource.com/118675 Reviewed-by: Heschi Kreinick Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/data.go | 68 +++++++++++++------------------- src/cmd/link/internal/ld/main.go | 3 +- 2 files changed, 29 insertions(+), 42 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 184e8158fd..3e4773102d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1903,15 +1903,12 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6 return sect, n, va } -// address assigns virtual addresses to all segments and sections and -// returns all segments in file order. -func (ctxt *Link) address() []*sym.Segment { - var order []*sym.Segment // Layout order - +// assign addresses +func (ctxt *Link) address() { va := uint64(*FlagTextAddr) - order = append(order, &Segtext) Segtext.Rwx = 05 Segtext.Vaddr = va + Segtext.Fileoff = uint64(HEADR) for _, s := range Segtext.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1919,6 +1916,7 @@ func (ctxt *Link) address() []*sym.Segment { } Segtext.Length = va - uint64(*FlagTextAddr) + Segtext.Filelen = Segtext.Length if ctxt.HeadType == objabi.Hnacl { va += 32 // room for the "halt sled" } @@ -1939,9 +1937,13 @@ func (ctxt *Link) address() []*sym.Segment { // writable even for this short period. va = uint64(Rnd(int64(va), int64(*FlagRound))) - order = append(order, &Segrodata) Segrodata.Rwx = 04 Segrodata.Vaddr = va + Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff + Segrodata.Filelen = 0 + if ctxt.HeadType == objabi.Hwindows { + Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN)) + } for _, s := range Segrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1949,15 +1951,17 @@ func (ctxt *Link) address() []*sym.Segment { } Segrodata.Length = va - Segrodata.Vaddr + Segrodata.Filelen = Segrodata.Length } if len(Segrelrodata.Sections) > 0 { // align to page boundary so as not to mix // rodata, rel-ro data, and executable text. va = uint64(Rnd(int64(va), int64(*FlagRound))) - order = append(order, &Segrelrodata) Segrelrodata.Rwx = 06 Segrelrodata.Vaddr = va + Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff + Segrelrodata.Filelen = 0 for _, s := range Segrelrodata.Sections { va = uint64(Rnd(int64(va), int64(s.Align))) s.Vaddr = va @@ -1965,12 +1969,20 @@ func (ctxt *Link) address() []*sym.Segment { } Segrelrodata.Length = va - Segrelrodata.Vaddr + Segrelrodata.Filelen = Segrelrodata.Length } va = uint64(Rnd(int64(va), int64(*FlagRound))) - order = append(order, &Segdata) Segdata.Rwx = 06 Segdata.Vaddr = va + Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff + Segdata.Filelen = 0 + if ctxt.HeadType == objabi.Hwindows { + Segdata.Fileoff = Segrodata.Fileoff + uint64(Rnd(int64(Segrodata.Length), PEFILEALIGN)) + } + if ctxt.HeadType == objabi.Hplan9 { + Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen + } var data *sym.Section var noptr *sym.Section var bss *sym.Section @@ -2000,14 +2012,16 @@ func (ctxt *Link) address() []*sym.Segment { } } - // Assign Segdata's Filelen omitting the BSS. We do this here - // simply because right now we know where the BSS starts. Segdata.Filelen = bss.Vaddr - Segdata.Vaddr va = uint64(Rnd(int64(va), int64(*FlagRound))) - order = append(order, &Segdwarf) Segdwarf.Rwx = 06 Segdwarf.Vaddr = va + Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound))) + Segdwarf.Filelen = 0 + if ctxt.HeadType == objabi.Hwindows { + Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), PEFILEALIGN)) + } for i, s := range Segdwarf.Sections { vlen := int64(s.Length) if i+1 < len(Segdwarf.Sections) { @@ -2021,6 +2035,8 @@ func (ctxt *Link) address() []*sym.Segment { Segdwarf.Length = va - Segdwarf.Vaddr } + Segdwarf.Filelen = va - Segdwarf.Vaddr + var ( text = Segtext.Sections[0] rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect @@ -2107,34 +2123,6 @@ func (ctxt *Link) address() []*sym.Segment { ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr)) ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length)) ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length)) - - return order -} - -// layout assigns file offsets and lengths to the segments in order. -func (ctxt *Link) layout(order []*sym.Segment) { - var prev *sym.Segment - for _, seg := range order { - if prev == nil { - seg.Fileoff = uint64(HEADR) - } else { - switch ctxt.HeadType { - default: - seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), int64(*FlagRound))) - case objabi.Hwindows: - seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN)) - case objabi.Hplan9: - seg.Fileoff = prev.Fileoff + prev.Filelen - } - } - if seg != &Segdata { - // Link.address already set Segdata.Filelen to - // account for BSS. - seg.Filelen = seg.Length - } - prev = seg - } - } // add a trampoline with symbol s (to be laid down after the current function) diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 23dfa277d0..bfa3f70a9e 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -224,9 +224,8 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.typelink() ctxt.symtab() ctxt.dodata() - order := ctxt.address() + ctxt.address() ctxt.reloc() - ctxt.layout(order) thearch.Asmb(ctxt) ctxt.undef() ctxt.hostlink() From 537fb06c5dabfc5329bd8535c63d6a0f1ccbb1b4 Mon Sep 17 00:00:00 2001 From: Hana Kim Date: Wed, 13 Jun 2018 13:37:33 -0400 Subject: [PATCH 056/203] runtime/pprof: skip TestMapping if CGO is not available The test requires cgo Change-Id: I1bffee5f187afcf4b7e27516451c56ddfc263a26 Reviewed-on: https://go-review.googlesource.com/118638 Reviewed-by: Ian Lance Taylor Reviewed-by: Alberto Donizetti Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/runtime/pprof/proto_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go index 9efcaeafe0..baa23e9330 100644 --- a/src/runtime/pprof/proto_test.go +++ b/src/runtime/pprof/proto_test.go @@ -238,6 +238,7 @@ func TestProcSelfMaps(t *testing.T) { // that the runtime can't symbolize. See ./testdata/mappingtest. func TestMapping(t *testing.T) { testenv.MustHaveGoRun(t) + testenv.MustHaveCGO(t) prog := "./testdata/mappingtest" From 72c29fc8cde7a02c760915e7b3e63de5502496bb Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Wed, 13 Jun 2018 08:20:23 -0700 Subject: [PATCH 057/203] runtime: move darwin kevent calls to libc kqueue, kevent, closeonexec, setitimer, with sysctl and fcntl helpers. TODO:arm,arm64 Change-Id: I9386f377186d6ac7cb99064c524a67e0c8282eba Reviewed-on: https://go-review.googlesource.com/118561 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/runtime/defs_darwin.go | 4 ++ src/runtime/defs_darwin_386.go | 3 + src/runtime/defs_darwin_amd64.go | 3 + src/runtime/netpoll_kqueue.go | 6 -- src/runtime/os_darwin.go | 6 -- src/runtime/os_dragonfly.go | 6 ++ src/runtime/os_freebsd.go | 6 ++ src/runtime/os_netbsd.go | 6 ++ src/runtime/os_openbsd.go | 6 ++ src/runtime/sys_darwin.go | 46 ++++++++++++ src/runtime/sys_darwin_386.s | 118 +++++++++++++++++++++---------- src/runtime/sys_darwin_amd64.s | 100 +++++++++++++------------- 12 files changed, 210 insertions(+), 100 deletions(-) diff --git a/src/runtime/defs_darwin.go b/src/runtime/defs_darwin.go index 92f7822796..a52ec3db63 100644 --- a/src/runtime/defs_darwin.go +++ b/src/runtime/defs_darwin.go @@ -25,6 +25,7 @@ package runtime #include #include #include +#include */ import "C" @@ -146,6 +147,9 @@ const ( EVFILT_WRITE = C.EVFILT_WRITE PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED + + F_SETFD = C.F_SETFD + FD_CLOEXEC = C.FD_CLOEXEC ) type MachBody C.mach_msg_body_t diff --git a/src/runtime/defs_darwin_386.go b/src/runtime/defs_darwin_386.go index 7f8ae9c934..9a9aa26fb5 100644 --- a/src/runtime/defs_darwin_386.go +++ b/src/runtime/defs_darwin_386.go @@ -123,6 +123,9 @@ const ( _EVFILT_WRITE = -0x2 _PTHREAD_CREATE_DETACHED = 0x2 + + _F_SETFD = 0x2 + _FD_CLOEXEC = 0x1 ) type machbody struct { diff --git a/src/runtime/defs_darwin_amd64.go b/src/runtime/defs_darwin_amd64.go index f35b90a5fa..53fc927cd3 100644 --- a/src/runtime/defs_darwin_amd64.go +++ b/src/runtime/defs_darwin_amd64.go @@ -123,6 +123,9 @@ const ( _EVFILT_WRITE = -0x2 _PTHREAD_CREATE_DETACHED = 0x2 + + _F_SETFD = 0x2 + _FD_CLOEXEC = 0x1 ) type machbody struct { diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go index 4d5d1a4ea8..0f73bf385e 100644 --- a/src/runtime/netpoll_kqueue.go +++ b/src/runtime/netpoll_kqueue.go @@ -10,12 +10,6 @@ package runtime import "unsafe" -func kqueue() int32 - -//go:noescape -func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 -func closeonexec(fd int32) - var ( kq int32 = -1 ) diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index cf57cc9020..8024d443a2 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -18,9 +18,6 @@ func mach_reply_port() uint32 func mach_task_self() uint32 func mach_thread_self() uint32 -//go:noescape -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 - func unimplemented(name string) { println(name, "not implemented") *(*int)(unsafe.Pointer(uintptr(1231))) = 1231 @@ -498,9 +495,6 @@ const ( _SS_DISABLE = 4 ) -//go:noescape -func setitimer(mode int32, new, old *itimerval) - //extern SigTabTT runtime·sigtab[]; type sigset uint32 diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index 2c9a78ca7b..eb7e159d35 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -49,6 +49,12 @@ func sys_umtx_wakeup(addr *uint32, val int32) int32 func osyield() +func kqueue() int32 + +//go:noescape +func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 +func closeonexec(fd int32) + const stackSystem = 0 // From DragonFly's diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index b3fc6a34ac..631dc20ab4 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -34,6 +34,12 @@ func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_ func osyield() +func kqueue() int32 + +//go:noescape +func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 +func closeonexec(fd int32) + // From FreeBSD's const ( _CTL_HW = 6 diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 1a92619354..a9bf407a36 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -68,6 +68,12 @@ func lwp_self() int32 func osyield() +func kqueue() int32 + +//go:noescape +func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 +func closeonexec(fd int32) + const ( _ESRCH = 3 _ETIMEDOUT = 60 diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go index 432c468a8b..c359ceb280 100644 --- a/src/runtime/os_openbsd.go +++ b/src/runtime/os_openbsd.go @@ -55,6 +55,12 @@ func thrwakeup(ident uintptr, n int32) int32 func osyield() +func kqueue() int32 + +//go:noescape +func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 +func closeonexec(fd int32) + const ( _ESRCH = 3 _EAGAIN = 35 diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go index 7b4e927b36..475bbff0ce 100644 --- a/src/runtime/sys_darwin.go +++ b/src/runtime/sys_darwin.go @@ -214,10 +214,51 @@ func raiseproc(sig uint32) { } func raiseproc_trampoline() +//go:nosplit +//go:cgo_unsafe_args +func setitimer(mode int32, new, old *itimerval) { + asmcgocall(unsafe.Pointer(funcPC(setitimer_trampoline)), unsafe.Pointer(&mode)) +} +func setitimer_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 { + return asmcgocall(unsafe.Pointer(funcPC(sysctl_trampoline)), unsafe.Pointer(&mib)) +} +func sysctl_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func fcntl(fd, cmd, arg int32) int32 { + return asmcgocall(unsafe.Pointer(funcPC(fcntl_trampoline)), unsafe.Pointer(&fd)) +} +func fcntl_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func kqueue() int32 { + v := asmcgocall(unsafe.Pointer(funcPC(kqueue_trampoline)), nil) + return v +} +func kqueue_trampoline() + +//go:nosplit +//go:cgo_unsafe_args +func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 { + return asmcgocall(unsafe.Pointer(funcPC(kevent_trampoline)), unsafe.Pointer(&kq)) +} +func kevent_trampoline() + // Not used on Darwin, but must be defined. func exitThread(wait *uint32) { } +//go:nosplit +func closeonexec(fd int32) { + fcntl(fd, _F_SETFD, _FD_CLOEXEC) +} + // Tell the linker that the libc_* functions are to be found // in a system library, with the libc_ prefix missing. @@ -247,6 +288,11 @@ func exitThread(wait *uint32) { //go:cgo_import_dynamic libc_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_setitimer setitimer "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib" +//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib" // Magic incantation to get libSystem actually dynamically linked. // TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210 diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s index cb60d070b5..624cead0b5 100644 --- a/src/runtime/sys_darwin_386.s +++ b/src/runtime/sys_darwin_386.s @@ -150,9 +150,20 @@ TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0 POPL BP RET -TEXT runtime·setitimer(SB),NOSPLIT,$0 - MOVL $83, AX - INT $0x80 +TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $24, SP + MOVL 32(SP), CX + MOVL 0(CX), AX // arg 1 mode + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 new + MOVL AX, 4(SP) + MOVL 8(CX), AX // arg 3 old + MOVL AX, 8(SP) + CALL libc_setitimer(SB) + MOVL BP, SP + POPL BP RET TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 @@ -398,46 +409,79 @@ TEXT runtime·setldt(SB),NOSPLIT,$32 // Nothing to do on Darwin, pthread already set thread-local storage up. RET -TEXT runtime·sysctl(SB),NOSPLIT,$0 - MOVL $202, AX - INT $0x80 - JAE 4(PC) - NEGL AX - MOVL AX, ret+24(FP) - RET - MOVL $0, AX - MOVL AX, ret+24(FP) +TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $24, SP + MOVL 32(SP), CX + MOVL 0(CX), AX // arg 1 mib + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 miblen + MOVL AX, 4(SP) + MOVL 8(CX), AX // arg 3 out + MOVL AX, 8(SP) + MOVL 12(CX), AX // arg 4 size + MOVL AX, 12(SP) + MOVL 16(CX), AX // arg 5 dst + MOVL AX, 16(SP) + MOVL 20(CX), AX // arg 6 ndst + MOVL AX, 20(SP) + CALL libc_sysctl(SB) + MOVL BP, SP + POPL BP RET -// func kqueue() int32 -TEXT runtime·kqueue(SB),NOSPLIT,$0 - MOVL $362, AX - INT $0x80 - JAE 2(PC) - NEGL AX - MOVL AX, ret+0(FP) +TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $8, SP + CALL libc_kqueue(SB) + MOVL BP, SP + POPL BP RET -// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 -TEXT runtime·kevent(SB),NOSPLIT,$0 - MOVL $363, AX - INT $0x80 - JAE 2(PC) - NEGL AX - MOVL AX, ret+24(FP) +TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $24, SP + MOVL 32(SP), CX + MOVL 0(CX), AX // arg 1 kq + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 ch + MOVL AX, 4(SP) + MOVL 8(CX), AX // arg 3 nch + MOVL AX, 8(SP) + MOVL 12(CX), AX // arg 4 ev + MOVL AX, 12(SP) + MOVL 16(CX), AX // arg 5 nev + MOVL AX, 16(SP) + MOVL 20(CX), AX // arg 6 ts + MOVL AX, 20(SP) + CALL libc_kevent(SB) + CMPL AX, $-1 + JNE ok + CALL libc_error(SB) + MOVL (AX), AX // errno + NEGL AX // caller wants it as a negative error code +ok: + MOVL BP, SP + POPL BP RET -// func closeonexec(fd int32) -TEXT runtime·closeonexec(SB),NOSPLIT,$32 - MOVL $92, AX // fcntl - // 0(SP) is where the caller PC would be; kernel skips it - MOVL fd+0(FP), BX - MOVL BX, 4(SP) // fd - MOVL $2, 8(SP) // F_SETFD - MOVL $1, 12(SP) // FD_CLOEXEC - INT $0x80 - JAE 2(PC) - NEGL AX +TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 + PUSHL BP + MOVL SP, BP + SUBL $24, SP + MOVL 32(SP), CX + MOVL 0(CX), AX // arg 1 fd + MOVL AX, 0(SP) + MOVL 4(CX), AX // arg 2 cmd + MOVL AX, 4(SP) + MOVL 8(CX), AX // arg 3 arg + MOVL AX, 8(SP) + CALL libc_fcntl(SB) + MOVL BP, SP + POPL BP RET // mstart_stub is the first function executed on a new thread started by pthread_create. diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index b52e0b52cd..da08427701 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -63,12 +63,14 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0 POPQ BP RET -TEXT runtime·setitimer(SB), NOSPLIT, $0 - MOVL mode+0(FP), DI - MOVQ new+8(FP), SI - MOVQ old+16(FP), DX - MOVL $(0x2000000+83), AX // syscall entry - SYSCALL +TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVQ 8(DI), SI // arg 2 new + MOVQ 16(DI), DX // arg 3 old + MOVL 0(DI), DI // arg 1 which + CALL libc_setitimer(SB) + POPQ BP RET TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0 @@ -338,57 +340,53 @@ TEXT runtime·settls(SB),NOSPLIT,$32 // Nothing to do on Darwin, pthread already set thread-local storage up. RET -TEXT runtime·sysctl(SB),NOSPLIT,$0 - MOVQ mib+0(FP), DI - MOVL miblen+8(FP), SI - MOVQ out+16(FP), DX - MOVQ size+24(FP), R10 - MOVQ dst+32(FP), R8 - MOVQ ndst+40(FP), R9 - MOVL $(0x2000000+202), AX // syscall entry - SYSCALL - JCC 4(PC) - NEGQ AX - MOVL AX, ret+48(FP) - RET - MOVL $0, AX - MOVL AX, ret+48(FP) +TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVL 8(DI), SI // arg 2 miblen + MOVQ 16(DI), DX // arg 3 out + MOVQ 24(DI), CX // arg 4 size + MOVQ 32(DI), R8 // arg 5 dst + MOVQ 40(DI), R9 // arg 6 ndst + MOVQ 0(DI), DI // arg 1 mib + CALL libc_sysctl(SB) + POPQ BP RET -// func kqueue() int32 -TEXT runtime·kqueue(SB),NOSPLIT,$0 - MOVQ $0, DI - MOVQ $0, SI - MOVQ $0, DX - MOVL $(0x2000000+362), AX - SYSCALL - JCC 2(PC) - NEGQ AX - MOVL AX, ret+0(FP) +TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + CALL libc_kqueue(SB) + POPQ BP RET -// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 -TEXT runtime·kevent(SB),NOSPLIT,$0 - MOVL kq+0(FP), DI - MOVQ ch+8(FP), SI - MOVL nch+16(FP), DX - MOVQ ev+24(FP), R10 - MOVL nev+32(FP), R8 - MOVQ ts+40(FP), R9 - MOVL $(0x2000000+363), AX - SYSCALL - JCC 2(PC) - NEGQ AX - MOVL AX, ret+48(FP) +TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVQ 8(DI), SI // arg 2 keventt + MOVL 16(DI), DX // arg 3 nch + MOVQ 24(DI), CX // arg 4 ev + MOVL 32(DI), R8 // arg 5 nev + MOVQ 40(DI), R9 // arg 6 ts + MOVL 0(DI), DI // arg 1 kq + CALL libc_kevent(SB) + CMPQ AX, $-1 + JNE ok + CALL libc_error(SB) + MOVQ (AX), AX // errno + NEGQ AX // caller wants it as a negative error code +ok: + POPQ BP RET -// func closeonexec(fd int32) -TEXT runtime·closeonexec(SB),NOSPLIT,$0 - MOVL fd+0(FP), DI // fd - MOVQ $2, SI // F_SETFD - MOVQ $1, DX // FD_CLOEXEC - MOVL $(0x2000000+92), AX // fcntl - SYSCALL +TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 + PUSHQ BP + MOVQ SP, BP + MOVL 4(DI), SI // arg 2 cmd + MOVL 8(DI), DX // arg 3 arg + MOVL 0(DI), DI // arg 1 fd + CALL libc_fcntl(SB) + POPQ BP RET // mstart_stub is the first function executed on a new thread started by pthread_create. From c824f540d9bb937d4e78bba63b38f4c8ad427c8f Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 13 Jun 2018 18:21:23 +0200 Subject: [PATCH 058/203] runtime: move iOS kevent calls to libc Change-Id: Ie97c9c9163f5af7b4768c34faac726e21627aa79 Reviewed-on: https://go-review.googlesource.com/118660 Run-TryBot: Elias Naur TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/runtime/defs_darwin_arm.go | 3 + src/runtime/defs_darwin_arm64.go | 3 + src/runtime/sys_darwin_arm.s | 102 +++++++++++++------------------ src/runtime/sys_darwin_arm64.s | 97 +++++++++++------------------ 4 files changed, 84 insertions(+), 121 deletions(-) diff --git a/src/runtime/defs_darwin_arm.go b/src/runtime/defs_darwin_arm.go index 39a65bca01..2225556d52 100644 --- a/src/runtime/defs_darwin_arm.go +++ b/src/runtime/defs_darwin_arm.go @@ -125,6 +125,9 @@ const ( _EVFILT_WRITE = -0x2 _PTHREAD_CREATE_DETACHED = 0x2 + + _F_SETFD = 0x2 + _FD_CLOEXEC = 0x1 ) type machbody struct { diff --git a/src/runtime/defs_darwin_arm64.go b/src/runtime/defs_darwin_arm64.go index 607051ff88..7ba051c2b3 100644 --- a/src/runtime/defs_darwin_arm64.go +++ b/src/runtime/defs_darwin_arm64.go @@ -123,6 +123,9 @@ const ( _EVFILT_WRITE = -0x2 _PTHREAD_CREATE_DETACHED = 0x2 + + _F_SETFD = 0x2 + _FD_CLOEXEC = 0x1 ) type machbody struct { diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s index 5f6c903437..9b693e3121 100644 --- a/src/runtime/sys_darwin_arm.s +++ b/src/runtime/sys_darwin_arm.s @@ -10,19 +10,6 @@ #include "go_tls.h" #include "textflag.h" -// Copied from /usr/include/sys/syscall.h -#define SYS_gettimeofday 116 -#define SYS_kill 37 -#define SYS_getpid 20 -#define SYS_pthread_sigmask 329 -#define SYS_setitimer 83 -#define SYS___sysctl 202 -#define SYS_sigaction 46 -#define SYS_sigreturn 184 -#define SYS_kqueue 362 -#define SYS_kevent 363 -#define SYS_fcntl 92 - TEXT notok<>(SB),NOSPLIT,$0 MOVW $0, R8 MOVW R8, (R8) @@ -114,12 +101,11 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0 BL.EQ notok<>(SB) RET -TEXT runtime·setitimer(SB),NOSPLIT,$0 - MOVW mode+0(FP), R0 - MOVW new+4(FP), R1 - MOVW old+8(FP), R2 - MOVW $SYS_setitimer, R12 - SWI $0x80 +TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 new + MOVW 8(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 which + BL libc_setitimer(SB) RET TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 @@ -265,22 +251,18 @@ TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 B runtime·armPublicationBarrier(SB) -TEXT runtime·sysctl(SB),NOSPLIT,$0 - MOVW mib+0(FP), R0 - MOVW miblen+4(FP), R1 - MOVW out+8(FP), R2 - MOVW size+12(FP), R3 - MOVW dst+16(FP), R4 - MOVW ndst+20(FP), R5 - MOVW $SYS___sysctl, R12 // syscall entry - SWI $0x80 - BCC sysctl_ret - RSB $0, R0, R0 - MOVW R0, ret+24(FP) - RET -sysctl_ret: - MOVW $0, R0 - MOVW R0, ret+24(FP) +TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 miblen + MOVW 8(R0), R2 // arg 3 out + MOVW 12(R0), R3 // arg 4 size + MOVW 16(R0), R4 // arg 5 dst + MOVW 20(R0), R5 // arg 6 ndst + MOVW 0(R0), R0 // arg 1 mib + // Only R0-R3 are used for arguments, the rest + // go on the stack. + MOVM.DB.W [R4-R5], (R13) + BL libc_sysctl(SB) + ADD $(2*4), R13 RET // uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) @@ -352,35 +334,37 @@ TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 MOVW R0, ret+4(FP) RET -// int32 runtime·kqueue(void) -TEXT runtime·kqueue(SB),NOSPLIT,$0 - MOVW $SYS_kqueue, R12 - SWI $0x80 - RSB.CS $0, R0, R0 - MOVW R0, ret+0(FP) +TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 + BL libc_kqueue(SB) RET // int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout) -TEXT runtime·kevent(SB),NOSPLIT,$0 - MOVW $SYS_kevent, R12 - MOVW kq+0(FP), R0 - MOVW ch+4(FP), R1 - MOVW nch+8(FP), R2 - MOVW ev+12(FP), R3 - MOVW nev+16(FP), R4 - MOVW ts+20(FP), R5 - SWI $0x80 - RSB.CS $0, R0, R0 - MOVW R0, ret+24(FP) +TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 keventss + MOVW 8(R0), R2 // arg 3 nch + MOVW 12(R0), R3 // arg 4 ev + MOVW 16(R0), R4 // arg 5 nev + MOVW 20(R0), R5 // arg 6 ts + MOVW 0(R0), R0 // arg 1 kq + // Only R0-R3 are used for arguments, the rest + // go on the stack. + MOVM.DB.W [R4-R5], (R13) + BL libc_kevent(SB) + ADD $(2*4), R13 + MOVW $-1, R2 + CMP R0, R2 + BNE ok + BL libc_error(SB) + MOVW (R0), R0 // errno + RSB $0, R0, R0 // caller wants it as a negative error code +ok: RET -// int32 runtime·closeonexec(int32 fd) -TEXT runtime·closeonexec(SB),NOSPLIT,$0 - MOVW $SYS_fcntl, R12 - MOVW fd+0(FP), R0 - MOVW $2, R1 // F_SETFD - MOVW $1, R2 // FD_CLOEXEC - SWI $0x80 +TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 cmd + MOVW 8(R0), R2 // arg 3 arg + MOVW 0(R0), R0 // arg 1 fd + BL libc_fcntl(SB) RET // sigaltstack is not supported on iOS, so our sigtramp has diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s index c21a5566fa..73ffd12bff 100644 --- a/src/runtime/sys_darwin_arm64.s +++ b/src/runtime/sys_darwin_arm64.s @@ -10,19 +10,6 @@ #include "go_tls.h" #include "textflag.h" -// Copied from /usr/include/sys/syscall.h -#define SYS_gettimeofday 116 -#define SYS_kill 37 -#define SYS_getpid 20 -#define SYS_pthread_sigmask 329 -#define SYS_setitimer 83 -#define SYS___sysctl 202 -#define SYS_sigaction 46 -#define SYS_sigreturn 184 -#define SYS_kqueue 362 -#define SYS_kevent 363 -#define SYS_fcntl 92 - TEXT notok<>(SB),NOSPLIT,$0 MOVD $0, R8 MOVD R8, (R8) @@ -106,12 +93,11 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0 BL libc_madvise(SB) RET -TEXT runtime·setitimer(SB),NOSPLIT,$0 - MOVW mode+0(FP), R0 - MOVD new+8(FP), R1 - MOVD old+16(FP), R2 - MOVW $SYS_setitimer, R16 - SVC $0x80 +TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0 + MOVD 8(R0), R1 // arg 2 new + MOVD 16(R0), R2 // arg 3 old + MOVW 0(R0), R0 // arg 1 which + BL libc_setitimer(SB) RET TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0 @@ -262,22 +248,14 @@ TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0 BL libc_usleep(SB) RET -TEXT runtime·sysctl(SB),NOSPLIT,$0 - MOVD mib+0(FP), R0 - MOVW miblen+8(FP), R1 - MOVD out+16(FP), R2 - MOVD size+24(FP), R3 - MOVD dst+32(FP), R4 - MOVD ndst+40(FP), R5 - MOVW $SYS___sysctl, R16 - SVC $0x80 - BCC ok - NEG R0, R0 - MOVW R0, ret+48(FP) - RET -ok: - MOVW $0, R0 - MOVW R0, ret+48(FP) +TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0 + MOVW 8(R0), R1 // arg 2 miblen + MOVD 16(R0), R2 // arg 3 out + MOVD 24(R0), R3 // arg 4 size + MOVD 32(R0), R4 // arg 5 dst + MOVD 40(R0), R5 // arg 6 ndst + MOVD 0(R0), R0 // arg 1 mib + BL libc_sysctl(SB) RET // uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) @@ -349,37 +327,32 @@ TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 MOVW R0, ret+8(FP) RET -// int32 runtime·kqueue(void) -TEXT runtime·kqueue(SB),NOSPLIT,$0 - MOVW $SYS_kqueue, R16 - SVC $0x80 - BCC 2(PC) - NEG R0, R0 - MOVW R0, ret+0(FP) +TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0 + BL libc_kqueue(SB) RET -// int32 runtime·kevent(int kq, Kevent *ch, int nch, Kevent *ev, int nev, Timespec *ts) -TEXT runtime·kevent(SB),NOSPLIT,$0 - MOVW kq+0(FP), R0 - MOVD ch+8(FP), R1 - MOVW nch+16(FP), R2 - MOVD ev+24(FP), R3 - MOVW nev+32(FP), R4 - MOVD ts+40(FP), R5 - MOVW $SYS_kevent, R16 - SVC $0x80 - BCC 2(PC) - NEG R0, R0 - MOVW R0, ret+48(FP) +TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0 + MOVD 8(R0), R1 // arg 2 keventt + MOVW 16(R0), R2 // arg 3 nch + MOVD 24(R0), R3 // arg 4 ev + MOVW 32(R0), R4 // arg 5 nev + MOVD 40(R0), R5 // arg 6 ts + MOVW 0(R0), R0 // arg 1 kq + BL libc_kevent(SB) + MOVD $-1, R2 + CMP R0, R2 + BNE ok + BL libc_error(SB) + MOVD (R0), R0 // errno + NEG R0, R0 // caller wants it as a negative error code +ok: RET -// int32 runtime·closeonexec(int32 fd) -TEXT runtime·closeonexec(SB),NOSPLIT,$0 - MOVW fd+0(FP), R0 - MOVW $2, R1 // F_SETFD - MOVW $1, R2 // FD_CLOEXEC - MOVW $SYS_fcntl, R16 - SVC $0x80 +TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0 + MOVW 4(R0), R1 // arg 2 cmd + MOVW 8(R0), R2 // arg 3 arg + MOVW 0(R0), R0 // arg 1 fd + BL libc_fcntl(SB) RET // sigaltstack on iOS is not supported and will always From 4a778cdf3375d418062b3c3e9f6891cc9162e3d0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 13 Jun 2018 11:56:15 -0700 Subject: [PATCH 059/203] os: don't poll fifos on Darwin The Darwin kqueue implementation doesn't report any event when the last writer for a fifo is closed. Fixes #24164 Change-Id: Ic2c47018ef1284bf2e26379f8dd7646edaad4d05 Reviewed-on: https://go-review.googlesource.com/118566 Reviewed-by: Brad Fitzpatrick --- src/os/fifo_test.go | 109 ++++++++++++++++++++++++++++++++++++++++++++ src/os/file_unix.go | 15 +++++- src/os/pipe_test.go | 67 +++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 src/os/fifo_test.go diff --git a/src/os/fifo_test.go b/src/os/fifo_test.go new file mode 100644 index 0000000000..66bc2965ab --- /dev/null +++ b/src/os/fifo_test.go @@ -0,0 +1,109 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package os_test + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "sync" + "syscall" + "testing" + "time" +) + +// Issue 24164. +func TestFifoEOF(t *testing.T) { + if runtime.GOOS == "openbsd" { + // On OpenBSD 6.2 this test just hangs for some reason. + t.Skip("skipping on OpenBSD; issue 25877") + } + + dir, err := ioutil.TempDir("", "TestFifoEOF") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + fifoName := filepath.Join(dir, "fifo") + if err := syscall.Mkfifo(fifoName, 0600); err != nil { + t.Fatal(err) + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + w, err := os.OpenFile(fifoName, os.O_WRONLY, 0) + if err != nil { + t.Error(err) + return + } + + defer func() { + if err := w.Close(); err != nil { + t.Errorf("error closing writer: %v", err) + } + }() + + for i := 0; i < 3; i++ { + time.Sleep(10 * time.Millisecond) + _, err := fmt.Fprintf(w, "line %d\n", i) + if err != nil { + t.Errorf("error writing to fifo: %v", err) + return + } + } + time.Sleep(10 * time.Millisecond) + }() + + defer wg.Wait() + + r, err := os.Open(fifoName) + if err != nil { + t.Fatal(err) + } + + done := make(chan bool) + go func() { + defer close(done) + + defer func() { + if err := r.Close(); err != nil { + t.Errorf("error closing reader: %v", err) + } + }() + + rbuf := bufio.NewReader(r) + for { + b, err := rbuf.ReadBytes('\n') + if err == io.EOF { + break + } + if err != nil { + t.Error(err) + return + } + t.Logf("%s\n", bytes.TrimSpace(b)) + } + }() + + select { + case <-done: + // Test succeeded. + case <-time.After(time.Second): + t.Error("timed out waiting for read") + // Close the reader to force the read to complete. + r.Close() + } +} diff --git a/src/os/file_unix.go b/src/os/file_unix.go index 11fdb19808..e0b8119d96 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -114,6 +114,8 @@ func newFile(fd uintptr, name string, kind newFileKind) *File { stdoutOrErr: fdi == 1 || fdi == 2, }} + pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock + // Don't try to use kqueue with regular files on FreeBSD. // It crashes the system unpredictably while running all.bash. // Issue 19093. @@ -121,10 +123,19 @@ func newFile(fd uintptr, name string, kind newFileKind) *File { // we assume they know what they are doing so we allow it to be // used with kqueue. if runtime.GOOS == "freebsd" && kind == kindOpenFile { - kind = kindNewFile + pollable = false + } + + // On Darwin, kqueue does not work properly with fifos: + // closing the last writer does not cause a kqueue event + // for any readers. See issue #24164. + if runtime.GOOS == "darwin" && kind == kindOpenFile { + var st syscall.Stat_t + if err := syscall.Fstat(fdi, &st); err == nil && st.Mode&syscall.S_IFMT == syscall.S_IFIFO { + pollable = false + } } - pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock if err := f.pfd.Init("file", pollable); err != nil { // An error here indicates a failure to register // with the netpoll system. That can happen for diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go index 929e9bec53..1d81f57eab 100644 --- a/src/os/pipe_test.go +++ b/src/os/pipe_test.go @@ -8,6 +8,8 @@ package os_test import ( + "bufio" + "bytes" "fmt" "internal/testenv" "io" @@ -305,3 +307,68 @@ func testCloseWithBlockingRead(t *testing.T, r, w *os.File) { wg.Wait() } + +// Issue 24164, for pipes. +func TestPipeEOF(t *testing.T) { + r, w, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + defer func() { + if err := w.Close(); err != nil { + t.Errorf("error closing writer: %v", err) + } + }() + + for i := 0; i < 3; i++ { + time.Sleep(10 * time.Millisecond) + _, err := fmt.Fprintf(w, "line %d\n", i) + if err != nil { + t.Errorf("error writing to fifo: %v", err) + return + } + } + time.Sleep(10 * time.Millisecond) + }() + + defer wg.Wait() + + done := make(chan bool) + go func() { + defer close(done) + + defer func() { + if err := r.Close(); err != nil { + t.Errorf("error closing reader: %v", err) + } + }() + + rbuf := bufio.NewReader(r) + for { + b, err := rbuf.ReadBytes('\n') + if err == io.EOF { + break + } + if err != nil { + t.Error(err) + return + } + t.Logf("%s\n", bytes.TrimSpace(b)) + } + }() + + select { + case <-done: + // Test succeeded. + case <-time.After(time.Second): + t.Error("timed out waiting for read") + // Close the reader to force the read to complete. + r.Close() + } +} From fb4fb0430b8d77b5487f51fd780bba25476e816c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 13 Jun 2018 15:54:42 +0200 Subject: [PATCH 060/203] syscall: check Fchmodat flags parameter on Linux As mentioned in #25845, port CL 46474 from golang.org/x/sys/unix to the syscall package. Currently Linux' fchmodat(2) syscall implementation doesn't support the flags parameter (though it might in future versions [1]). Fchmodat in the syscall package takes the parameter and (wrongly) passes it on to the syscall which will ignore it. According to the POSIX.1-2008 manual page [2], AT_SYMLINK_NOFOLLOW is the only valid value for the flags parameter and EOPNOTSUPP should be returned in case changing the mode of a symbolic link is not supported by the underlying system. EINVAL should be returned for any other value of the flags parameter. [1] https://patchwork.kernel.org/patch/9596301/ [2] http://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html Updates #20130 Updates #25845 Change-Id: I1021dd0e6a4f4cb3557cb1c1b34dd618c378cda6 Reviewed-on: https://go-review.googlesource.com/118658 Reviewed-by: Ian Lance Taylor --- src/syscall/syscall_linux.go | 15 +++++- src/syscall/syscall_linux_test.go | 63 ++++++++++++++++++++++++++ src/syscall/zsyscall_linux_386.go | 30 ++++++------ src/syscall/zsyscall_linux_amd64.go | 30 ++++++------ src/syscall/zsyscall_linux_arm.go | 30 ++++++------ src/syscall/zsyscall_linux_arm64.go | 30 ++++++------ src/syscall/zsyscall_linux_mips.go | 30 ++++++------ src/syscall/zsyscall_linux_mips64.go | 30 ++++++------ src/syscall/zsyscall_linux_mips64le.go | 30 ++++++------ src/syscall/zsyscall_linux_mipsle.go | 30 ++++++------ src/syscall/zsyscall_linux_ppc64.go | 30 ++++++------ src/syscall/zsyscall_linux_ppc64le.go | 30 ++++++------ src/syscall/zsyscall_linux_s390x.go | 30 ++++++------ 13 files changed, 242 insertions(+), 166 deletions(-) diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 58216f1957..8d0532e216 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -35,6 +35,20 @@ func Creat(path string, mode uint32) (fd int, err error) { return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) } +//sys fchmodat(dirfd int, path string, mode uint32) (err error) + +func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { + // Linux fchmodat doesn't support the flags parameter. Mimick glibc's behavior + // and check the flags. Otherwise the mode would be applied to the symlink + // destination which is not what the user expects. + if flags&^_AT_SYMLINK_NOFOLLOW != 0 { + return EINVAL + } else if flags&_AT_SYMLINK_NOFOLLOW != 0 { + return EOPNOTSUPP + } + return fchmodat(dirfd, path, mode) +} + //sys linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) func Link(oldpath string, newpath string) (err error) { @@ -830,7 +844,6 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri //sys Fallocate(fd int, mode uint32, off int64, len int64) (err error) //sys Fchdir(fd int) (err error) //sys Fchmod(fd int, mode uint32) (err error) -//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys fcntl(fd int, cmd int, arg int) (val int, err error) //sys Fdatasync(fd int) (err error) diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go index 932ccee491..4490fc24ca 100644 --- a/src/syscall/syscall_linux_test.go +++ b/src/syscall/syscall_linux_test.go @@ -21,6 +21,69 @@ import ( "time" ) +// chtmpdir changes the working directory to a new temporary directory and +// provides a cleanup function. Used when PWD is read-only. +func chtmpdir(t *testing.T) func() { + oldwd, err := os.Getwd() + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + if err := os.Chdir(d); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + return func() { + if err := os.Chdir(oldwd); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + os.RemoveAll(d) + } +} + +func touch(t *testing.T, name string) { + f, err := os.Create(name) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } +} + +const ( + _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_FDCWD = -0x64 +) + +func TestFchmodat(t *testing.T) { + defer chtmpdir(t)() + + touch(t, "file1") + os.Symlink("file1", "symlink1") + + err := syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, 0) + if err != nil { + t.Fatalf("Fchmodat: unexpected error: %v", err) + } + + fi, err := os.Stat("file1") + if err != nil { + t.Fatal(err) + } + + if fi.Mode() != 0444 { + t.Errorf("Fchmodat: failed to change mode: expected %v, got %v", 0444, fi.Mode()) + } + + err = syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, _AT_SYMLINK_NOFOLLOW) + if err != syscall.EOPNOTSUPP { + t.Fatalf("Fchmodat: unexpected error: %v, expected EOPNOTSUPP", err) + } +} + func TestMain(m *testing.M) { if os.Getenv("GO_DEATHSIG_PARENT") == "1" { deathSignalParent() diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index 951bf9ad48..346c3cdbcf 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index 55e7edd9e8..606c9e8cb0 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index 40ee288827..ccddfae9f6 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go index 59d445cc1c..3ad94d0e7f 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go index df65776170..50bc319f27 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 701f39a252..26b22169e4 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index c7976c9207..18d0298ced 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go index c3e8d92035..0b2862d1cb 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go index 6f0e09e63a..071ef7e461 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go index 6202e79b36..e1267ecd87 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go index 1020c8ee60..07962f6188 100644 --- a/src/syscall/zsyscall_linux_s390x.go +++ b/src/syscall/zsyscall_linux_s390x.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) From 5eb98b3c3016c7dd10d71ee15bb6fc5d3128bec9 Mon Sep 17 00:00:00 2001 From: Yury Smolsky Date: Fri, 8 Jun 2018 00:25:12 +0300 Subject: [PATCH 061/203] cmd/compile: use expandable columns in ssa.html Display just a few columns in ssa.html, other columns can be expanded by clicking on collapsed column. Use sans serif font for the text, slightly smaller font size for non program text. Fixes #25286 Change-Id: I1094695135401602d90b97b69e42f6dda05871a2 Reviewed-on: https://go-review.googlesource.com/117275 Run-TryBot: Yury Smolsky TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 2 +- src/cmd/compile/internal/ssa/compile.go | 4 +- src/cmd/compile/internal/ssa/html.go | 95 +++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index a64d212233..3c15c8e555 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -4985,7 +4985,7 @@ func genssa(f *ssa.Func, pp *Progs) { } buf.WriteString("") buf.WriteString("
    ") - f.HTMLWriter.WriteColumn("genssa", "ssa-prog", buf.String()) + f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) // pp.Text.Ctxt.LineHist.PrintFilenameOnly = saved } } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 4bd9ade479..c7797d79e9 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -43,7 +43,7 @@ func Compile(f *Func) { // Run all the passes printFunc(f) - f.HTMLWriter.WriteFunc("start", f) + f.HTMLWriter.WriteFunc("start", "start", f) if BuildDump != "" && BuildDump == f.Name { f.dumpFile("build") } @@ -86,7 +86,7 @@ func Compile(f *Func) { f.Logf(" pass %s end %s\n", p.name, stats) printFunc(f) - f.HTMLWriter.WriteFunc(fmt.Sprintf("after %s %s", phaseName, stats), f) + f.HTMLWriter.WriteFunc(phaseName, fmt.Sprintf("%s %s", phaseName, stats), f) } if p.time || p.mem { // Surround timing information w/ enough context to allow comparisons. diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index 85d97ba497..d37e69977e 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -38,6 +38,11 @@ func (w *HTMLWriter) start(name string) { @@ -189,8 +197,13 @@ var highlights = [ "highlight-lightpink", "highlight-lightsteelblue", "highlight-palegreen", + "highlight-skyblue", "highlight-lightgray", - "highlight-yellow" + "highlight-yellow", + "highlight-lime", + "highlight-khaki", + "highlight-aqua", + "highlight-salmon" ]; // state: which value is highlighted this color? @@ -207,7 +220,11 @@ var outlines = [ "outline-darkolivegreen", "outline-fuchsia", "outline-sienna", - "outline-gold" + "outline-gold", + "outline-orangered", + "outline-teal", + "outline-maroon", + "outline-black" ]; // state: which value is outlined this color? From 05f8b44d5edc2960eff106e5e780cf83535d0533 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 7 Jun 2018 18:18:50 +0000 Subject: [PATCH 104/203] unicode: fix SpecialCase to follow its docs & respect explict no-op mappings If SpecialCase contains an explicit CaseRange with zero deltas, respect those and don't fall back to the default behavior. Fixes #25636 Change-Id: Ic554c6b3dd462b1b39c75194eec469b6ff4aa55b Reviewed-on: https://go-review.googlesource.com/117155 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Marcel van Lohuizen --- src/unicode/letter.go | 26 ++++++++++++++------------ src/unicode/letter_test.go | 12 ++++++++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/unicode/letter.go b/src/unicode/letter.go index 4d9fc67165..8be9a7b7c9 100644 --- a/src/unicode/letter.go +++ b/src/unicode/letter.go @@ -206,9 +206,10 @@ func IsTitle(r rune) bool { } // to maps the rune using the specified case mapping. -func to(_case int, r rune, caseRange []CaseRange) rune { +// It additionally reports whether caseRange contained a mapping for r. +func to(_case int, r rune, caseRange []CaseRange) (mappedRune rune, foundMapping bool) { if _case < 0 || MaxCase <= _case { - return ReplacementChar // as reasonable an error as any + return ReplacementChar, false // as reasonable an error as any } // binary search over ranges lo := 0 @@ -229,9 +230,9 @@ func to(_case int, r rune, caseRange []CaseRange) rune { // bit in the sequence offset. // The constants UpperCase and TitleCase are even while LowerCase // is odd so we take the low bit from _case. - return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1)) + return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1)), true } - return r + delta + return r + delta, true } if r < rune(cr.Lo) { hi = m @@ -239,12 +240,13 @@ func to(_case int, r rune, caseRange []CaseRange) rune { lo = m + 1 } } - return r + return r, false } // To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase. func To(_case int, r rune) rune { - return to(_case, r, CaseRanges) + r, _ = to(_case, r, CaseRanges) + return r } // ToUpper maps the rune to upper case. @@ -282,8 +284,8 @@ func ToTitle(r rune) rune { // ToUpper maps the rune to upper case giving priority to the special mapping. func (special SpecialCase) ToUpper(r rune) rune { - r1 := to(UpperCase, r, []CaseRange(special)) - if r1 == r { + r1, hadMapping := to(UpperCase, r, []CaseRange(special)) + if r1 == r && !hadMapping { r1 = ToUpper(r) } return r1 @@ -291,8 +293,8 @@ func (special SpecialCase) ToUpper(r rune) rune { // ToTitle maps the rune to title case giving priority to the special mapping. func (special SpecialCase) ToTitle(r rune) rune { - r1 := to(TitleCase, r, []CaseRange(special)) - if r1 == r { + r1, hadMapping := to(TitleCase, r, []CaseRange(special)) + if r1 == r && !hadMapping { r1 = ToTitle(r) } return r1 @@ -300,8 +302,8 @@ func (special SpecialCase) ToTitle(r rune) rune { // ToLower maps the rune to lower case giving priority to the special mapping. func (special SpecialCase) ToLower(r rune) rune { - r1 := to(LowerCase, r, []CaseRange(special)) - if r1 == r { + r1, hadMapping := to(LowerCase, r, []CaseRange(special)) + if r1 == r && !hadMapping { r1 = ToLower(r) } return r1 diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go index 3fe72ff13d..19ee535d57 100644 --- a/src/unicode/letter_test.go +++ b/src/unicode/letter_test.go @@ -9,6 +9,7 @@ import ( "fmt" "runtime" "sort" + "strings" "testing" . "unicode" ) @@ -551,3 +552,14 @@ func TestLatinOffset(t *testing.T) { } } } + +func TestSpecialCaseNoMapping(t *testing.T) { + // Issue 25636 + // no change for rune 'A', zero delta, under upper/lower/title case change. + var noChangeForCapitalA = CaseRange{'A', 'A', [MaxCase]rune{0, 0, 0}} + got := strings.ToLowerSpecial(SpecialCase([]CaseRange{noChangeForCapitalA}), "ABC") + want := "Abc" + if got != want { + t.Errorf("got %q; want %q", got, want) + } +} From 9a91713090f22eb7bc2b0b3af7576fe6e86bebfe Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 17 Jun 2018 20:30:27 +0000 Subject: [PATCH 105/203] cmd/dist: don't test Examples for js/wasm Fixes #25913 Change-Id: I4701ec94fa4b07211a8beed85c02ee5aa4fe3eb3 Reviewed-on: https://go-review.googlesource.com/119377 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Richard Musiol --- src/cmd/dist/test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index ac43701d88..e146c2a3b8 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -324,6 +324,8 @@ func (t *tester) registerStdTest(pkg string) { } if t.compileOnly { args = append(args, "-run=^$") + } else if goos == "js" && goarch == "wasm" { + args = append(args, "-run=^Test") // exclude examples; Issue 25913 } args = append(args, stdMatches...) cmd := exec.Command("go", args...) @@ -1335,6 +1337,9 @@ func (t *tester) runFlag(rx string) string { if t.compileOnly { return "-run=^$" } + if rx == "" && goos == "js" && goarch == "wasm" { + return "-run=^Test" // exclude examples; Issue 25913 + } return "-run=" + rx } From 187c3a65a6293e6b9821bf3da49430e5d7bf77f8 Mon Sep 17 00:00:00 2001 From: Mostyn Bramley-Moore Date: Sun, 17 Jun 2018 19:42:03 +0200 Subject: [PATCH 106/203] doc: update more stale pprof links Related to #25477. Change-Id: I11261c6055b446ceca1b3acc538ab00fec4b47ca Reviewed-on: https://go-review.googlesource.com/119321 Reviewed-by: Brad Fitzpatrick --- doc/diagnostics.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/diagnostics.html b/doc/diagnostics.html index 35aae156e8..0a7847744b 100644 --- a/doc/diagnostics.html +++ b/doc/diagnostics.html @@ -50,7 +50,7 @@ trace. Use tools in isolation to get more precise info. Profiling is useful for identifying expensive or frequently called sections of code. The Go runtime provides profiling data in the format expected by the -pprof visualization tool. +pprof visualization tool. The profiling data can be collected during testing via go test or endpoints made available from the net/http/pprof package. Users need to collect the profiling data and use pprof tools to filter @@ -127,7 +127,7 @@ so it is recommended to collect only a single profile at a time.

    The Go tools provide text, graph, and callgrind visualization of the profile data using -go tool pprof. +go tool pprof. Read Profiling Go programs to see them in action.

    From b7d9e6e149567bb94d6bb87a9ab09c60055ac4e8 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 18 Jun 2018 13:57:27 +1000 Subject: [PATCH 107/203] cmd/cover: fix off-by-one in test error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drive-by after previous CL. Change-Id: I87db65b65745a0d76500cce06ac276b0d7928404 Reviewed-on: https://go-review.googlesource.com/119395 Reviewed-by: Ralph Corderoy Reviewed-by: Daniel Martí Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot --- src/cmd/cover/cover_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index 23a609996b..c818819c39 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -325,7 +325,7 @@ func TestCoverHTML(t *testing.T) { } } if len(goldenLines) != len(outLines) { - t.Fatalf("output longer than golden; first extra output line %d: %q\n", len(goldenLines), outLines[len(goldenLines)]) + t.Fatalf("output longer than golden; first extra output line %d: %q\n", len(goldenLines)+1, outLines[len(goldenLines)]) } } From 741dad28cb50b7cdbd4b6fd46114541aa73b15be Mon Sep 17 00:00:00 2001 From: Hiroshi Ioka Date: Sat, 6 Jan 2018 18:10:30 +0900 Subject: [PATCH 108/203] cmd/cgo: avoid name confliction for C functions Use more cryptic names for local variables inside C function wrappers. Fixes #23356 Change-Id: Ia6a0218f27a13be14f589b1a0facc9683d22ff56 Reviewed-on: https://go-review.googlesource.com/86495 Run-TryBot: Tobias Klauser Reviewed-by: Tobias Klauser Reviewed-by: Ian Lance Taylor --- misc/cgo/test/cgo_test.go | 1 + misc/cgo/test/issue23356.go | 19 +++++++++++++++++++ src/cmd/cgo/out.go | 22 +++++++++++----------- 3 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 misc/cgo/test/issue23356.go diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 4462df0059..4c7f676e0b 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -89,6 +89,7 @@ func Test21897(t *testing.T) { test21897(t) } func Test22906(t *testing.T) { test22906(t) } func Test24206(t *testing.T) { test24206(t) } func Test25143(t *testing.T) { test25143(t) } +func Test23356(t *testing.T) { test23356(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkGoString(b *testing.B) { benchGoString(b) } diff --git a/misc/cgo/test/issue23356.go b/misc/cgo/test/issue23356.go new file mode 100644 index 0000000000..1c390120c8 --- /dev/null +++ b/misc/cgo/test/issue23356.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +// int a(void) { return 5; }; +// int r(void) { return 3; }; +import "C" +import "testing" + +func test23356(t *testing.T) { + if got, want := C.a(), C.int(5); got != want { + t.Errorf("C.a() == %v, expected %v", got, want) + } + if got, want := C.r(), C.int(3); got != want { + t.Errorf("C.r() == %v, expected %v", got, want) + } +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index e9b7986565..dbc17d2d56 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -609,14 +609,14 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { // We're trying to write a gcc struct that matches gc's layout. // Use packed attribute to force no padding in this struct in case // gcc has different packing requirements. - fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) + fmt.Fprintf(fgcc, "\t%s %v *_cgo_a = v;\n", ctype, p.packedAttribute()) if n.FuncType.Result != nil { // Save the stack top for use below. - fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n") + fmt.Fprintf(fgcc, "\tchar *_cgo_stktop = _cgo_topofstack();\n") } tr := n.FuncType.Result if tr != nil { - fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n") + fmt.Fprintf(fgcc, "\t__typeof__(_cgo_a->r) _cgo_r;\n") } fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n") if n.AddError { @@ -624,9 +624,9 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { } fmt.Fprintf(fgcc, "\t") if tr != nil { - fmt.Fprintf(fgcc, "r = ") + fmt.Fprintf(fgcc, "_cgo_r = ") if c := tr.C.String(); c[len(c)-1] == '*' { - fmt.Fprint(fgcc, "(__typeof__(a->r)) ") + fmt.Fprint(fgcc, "(__typeof__(_cgo_a->r)) ") } } if n.Kind == "macro" { @@ -637,7 +637,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { if i > 0 { fmt.Fprintf(fgcc, ", ") } - fmt.Fprintf(fgcc, "a->p%d", i) + fmt.Fprintf(fgcc, "_cgo_a->p%d", i) } fmt.Fprintf(fgcc, ");\n") } @@ -648,9 +648,9 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { if n.FuncType.Result != nil { // The cgo call may have caused a stack copy (via a callback). // Adjust the return value pointer appropriately. - fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n") + fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n") // Save the return value. - fmt.Fprintf(fgcc, "\ta->r = r;\n") + fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n") } if n.AddError { fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n") @@ -685,12 +685,12 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, ")\n") fmt.Fprintf(fgcc, "{\n") if t := n.FuncType.Result; t != nil { - fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String()) + fmt.Fprintf(fgcc, "\t%s _cgo_r;\n", t.C.String()) } fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n") fmt.Fprintf(fgcc, "\t") if t := n.FuncType.Result; t != nil { - fmt.Fprintf(fgcc, "r = ") + fmt.Fprintf(fgcc, "_cgo_r = ") // Cast to void* to avoid warnings due to omitted qualifiers. if c := t.C.String(); c[len(c)-1] == '*' { fmt.Fprintf(fgcc, "(void*)") @@ -716,7 +716,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { if c := t.C.String(); c[len(c)-1] == '*' { fmt.Fprintf(fgcc, "(void*)") } - fmt.Fprintf(fgcc, "r;\n") + fmt.Fprintf(fgcc, "_cgo_r;\n") } fmt.Fprintf(fgcc, "}\n") fmt.Fprintf(fgcc, "\n") From 88b442f5c08a2984e6800e83a483a6c7f4b24cd1 Mon Sep 17 00:00:00 2001 From: Hana Kim Date: Mon, 18 Jun 2018 12:03:53 -0400 Subject: [PATCH 109/203] runtime/pprof: fix incorrect assumption in TestMapping TestMapping assumed that there was only one mapping entry corresponding to /exe/main, but that is not always true. This CL changes the test logic to examine whether all referenced mappings are symbolized. Based on the result, the test determines whether the corresponding mapping entries' HasFunctions fields to be true or false. I initially attempted to create two mappings for referenced locations (one for symbolized and another for unsymbolized) as described in the TODO in proto.go as part of fixing this bug. But that change requires non-trivial modification in the upstream profile package so I decided to just fix the test for now. Fixes #25891 Change-Id: Id27a5b07bb5b59e133755a0f863bf56c0a4f7f2b Reviewed-on: https://go-review.googlesource.com/119455 Run-TryBot: Hyang-Ah Hana Kim TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/pprof/proto_test.go | 46 +++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go index 4a47111e57..36c345b6d9 100644 --- a/src/runtime/pprof/proto_test.go +++ b/src/runtime/pprof/proto_test.go @@ -261,37 +261,43 @@ func TestMapping(t *testing.T) { if err != nil { t.Fatalf("failed to parse the generated profile data: %v", err) } + t.Logf("Profile: %s", prof) - allResolved := !hasUnresolvedSymbol(prof) - if allResolved && traceback != "GoOnly" { - t.Log("No non-Go samples were sampled") + hit := make(map[*profile.Mapping]bool) + miss := make(map[*profile.Mapping]bool) + for _, loc := range prof.Location { + if symbolized(loc) { + hit[loc.Mapping] = true + } else { + miss[loc.Mapping] = true + } + } + if len(miss) == 0 { + t.Log("no location with missing symbol info was sampled") } for _, m := range prof.Mapping { - if !strings.Contains(m.File, "/exe/main") { + if miss[m] && m.HasFunctions { + t.Errorf("mapping %+v has HasFunctions=true, but contains locations with failed symbolization", m) continue } - if allResolved && !m.HasFunctions { - t.Errorf("HasFunctions=%t when all sampled PCs were symbolized\n%s", m.HasFunctions, prof) - } - if !allResolved && m.HasFunctions { - t.Errorf("HasFunctions=%t when some sampled PCs were not symbolized\n%s", m.HasFunctions, prof) + if !miss[m] && hit[m] && !m.HasFunctions { + t.Errorf("mapping %+v has HasFunctions=false, but all referenced locations from this lapping were symbolized successfully", m) + continue } } }) } } -func hasUnresolvedSymbol(prof *profile.Profile) bool { - for _, loc := range prof.Location { - if len(loc.Line) == 0 { - return true - } - l := loc.Line[0] - f := l.Function - if l.Line == 0 || f == nil || f.Name == "" || f.Filename == "" { - return true - } +func symbolized(loc *profile.Location) bool { + if len(loc.Line) == 0 { + return false } - return false + l := loc.Line[0] + f := l.Function + if l.Line == 0 || f == nil || f.Name == "" || f.Filename == "" { + return false + } + return true } From 17a4e0475da1237168c4c14dd18af4ebe0d4b3d1 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Mon, 18 Jun 2018 17:09:37 -0400 Subject: [PATCH 110/203] runtime: skip gdb tests on mips after DWARF compression DWARF compression appears to break GDB on mips for reasons unknown. Skip the GDB tests there. Fixes #25939. Change-Id: Id76860d3a2ff8055999ac12ea891c37565bb6685 Reviewed-on: https://go-review.googlesource.com/119539 Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements --- src/runtime/runtime-gdb_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 3f936b15b3..4733efba6d 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -33,6 +33,9 @@ func checkGdbEnvironment(t *testing.T) { if runtime.GOARCH == "ppc64" { t.Skip("skipping gdb tests on linux/ppc64; see golang.org/issue/17366") } + if runtime.GOARCH == "mips" { + t.Skip("skipping gdb tests on linux/mips; see https://golang.org/issue/25939") + } } if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { t.Skip("gdb test can fail with GOROOT_FINAL pending") From c99300229de4e69220790c71da14785dc52c3d68 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Mon, 18 Jun 2018 16:29:16 -0400 Subject: [PATCH 111/203] runtime: fix lldb test after DWARF compression Most (all?) released versions of lldb don't support compressed DWARF. For now, skip the test if lldb can't find where to put the breakpoint. This is the best I could think of -- there is no explicit error that I can find that indicates it couldn't load the DWARF. Fixes #25925. Change-Id: Ib8fa486a04940cee5959ba7aab7bdbbaa3b2974e Reviewed-on: https://go-review.googlesource.com/119535 Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements --- src/runtime/runtime-lldb_test.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go index 9a287052ea..a036fd8480 100644 --- a/src/runtime/runtime-lldb_test.go +++ b/src/runtime/runtime-lldb_test.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" "strings" "testing" @@ -82,8 +83,12 @@ target = debugger.CreateTargetWithFileAndArch("a.exe", None) if target: print "Created target" main_bp = target.BreakpointCreateByLocation("main.go", 10) - if main_bp: + if main_bp.GetNumLocations() != 0: print "Created breakpoint" + else: + # This happens if lldb can't read the program's DWARF. See https://golang.org/issue/25925. + print "SKIP: no matching locations for breakpoint" + exit(1) process = target.LaunchSimple(None, None, os.getcwd()) if process: print "Process launched" @@ -98,7 +103,7 @@ if target: if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]: continue else: - print "Timeout launching" + print "SKIP: Timeout launching" break if state == lldb.eStateStopped: for t in process.threads: @@ -172,8 +177,9 @@ func TestLldbPython(t *testing.T) { got, _ := cmd.CombinedOutput() if string(got) != expectedLldbOutput { - if strings.Contains(string(got), "Timeout launching") { - t.Skip("Timeout launching") + skipReason := regexp.MustCompile("SKIP: .*\n").Find(got) + if skipReason != nil { + t.Skip(string(skipReason)) } t.Fatalf("Unexpected lldb output:\n%s", got) } From f125052ad5327c986ad81da48015696b7f8bd632 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 18 Jun 2018 14:38:45 -0700 Subject: [PATCH 112/203] cmd/compile: fix exporting of 'for' loops The existing code for encoding 'for' loops in exported, inlineable functions incorrectly assumed that the 'Right' field points to an 'expression' node. Adjusted the code to be able to handle any kind of node. Made matching changes for the binary and indexed exporter. This only shows up together with other pending compiler changes that enable exporting of such functions which contain for loops. No tests yet because we can't test this w/o those pending compiler changes. Once those changes are in, this code will be tested implicitly. However, the changes were tested manually together with the patches described in the issue. Fixes #25222. Change-Id: I54babb87e5d665d2c1ef6116c1de1b8c50b1138e Reviewed-on: https://go-review.googlesource.com/119595 Reviewed-by: David Chase --- src/cmd/compile/internal/gc/bexport.go | 16 ++++++++++------ src/cmd/compile/internal/gc/bimport.go | 2 +- src/cmd/compile/internal/gc/iexport.go | 16 ++++++++++------ src/cmd/compile/internal/gc/iimport.go | 2 +- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index c2672cb319..0d4997ccfc 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -1128,16 +1128,20 @@ func (p *exporter) stmtList(list Nodes) { } // TODO inlining produces expressions with ninits. we can't export these yet. // (from fmt.go:1461ff) - if opprec[n.Op] < 0 { - p.stmt(n) - } else { - p.expr(n) - } + p.node(n) } p.op(OEND) } +func (p *exporter) node(n *Node) { + if opprec[n.Op] < 0 { + p.stmt(n) + } else { + p.expr(n) + } +} + func (p *exporter) exprList(list Nodes) { if p.trace { if list.Len() == 0 { @@ -1552,7 +1556,7 @@ func (p *exporter) exprsOrNil(a, b *Node) { p.expr(a) } if ab&2 != 0 { - p.expr(b) + p.node(b) } } diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index 8215e4652f..c19f548e18 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -1209,7 +1209,7 @@ func (p *importer) exprsOrNil() (a, b *Node) { a = p.expr() } if ab&2 != 0 { - b = p.expr() + b = p.node() } return } diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index f6e9b8b061..3abbd15e16 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -970,15 +970,19 @@ func (w *exportWriter) linkname(s *types.Sym) { func (w *exportWriter) stmtList(list Nodes) { for _, n := range list.Slice() { - if opprec[n.Op] < 0 { - w.stmt(n) - } else { - w.expr(n) - } + w.node(n) } w.op(OEND) } +func (w *exportWriter) node(n *Node) { + if opprec[n.Op] < 0 { + w.stmt(n) + } else { + w.expr(n) + } +} + // Caution: stmt will emit more than one node for statement nodes n that have a non-empty // n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.). func (w *exportWriter) stmt(n *Node) { @@ -1338,7 +1342,7 @@ func (w *exportWriter) exprsOrNil(a, b *Node) { w.expr(a) } if ab&2 != 0 { - w.expr(b) + w.node(b) } } diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go index 4d66b4b042..d158899aaa 100644 --- a/src/cmd/compile/internal/gc/iimport.go +++ b/src/cmd/compile/internal/gc/iimport.go @@ -1060,7 +1060,7 @@ func (r *importReader) exprsOrNil() (a, b *Node) { a = r.expr() } if ab&2 != 0 { - b = r.expr() + b = r.node() } return } From 1caa06299c9a29f5009c92ffd82bc888d5a50f36 Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Seo Date: Tue, 29 May 2018 16:00:38 -0300 Subject: [PATCH 113/203] runtime: implement procyield properly for ppc64x The procyield() function should yield the processor as in other architectures. On ppc64x, this is achieved by setting the Program Priority Register to 'low priority' prior to the spin loop, and setting it back to 'medium-low priority' afterwards. benchmark old ns/op new ns/op delta BenchmarkMakeChan/Byte-8 87.7 86.6 -1.25% BenchmarkMakeChan/Int-8 107 106 -0.93% BenchmarkMakeChan/Ptr-8 201 204 +1.49% BenchmarkMakeChan/Struct/0-8 78.2 79.7 +1.92% BenchmarkMakeChan/Struct/32-8 196 200 +2.04% BenchmarkMakeChan/Struct/40-8 236 230 -2.54% BenchmarkChanNonblocking-8 8.64 8.85 +2.43% BenchmarkChanUncontended-8 5577 5598 +0.38% BenchmarkChanContended-8 66106 51529 -22.05% BenchmarkChanSync-8 451 441 -2.22% BenchmarkChanSyncWork-8 9155 9170 +0.16% BenchmarkChanProdCons0-8 1585 1083 -31.67% BenchmarkChanProdCons10-8 1094 838 -23.40% BenchmarkChanProdCons100-8 831 657 -20.94% BenchmarkChanProdConsWork0-8 1471 941 -36.03% BenchmarkChanProdConsWork10-8 1033 721 -30.20% BenchmarkChanProdConsWork100-8 730 511 -30.00% BenchmarkChanCreation-8 135 128 -5.19% BenchmarkChanSem-8 602 463 -23.09% BenchmarkChanPopular-8 3017466 2188441 -27.47% Fixes #25625 Change-Id: Iacb1c888d3c066902152b8367500348fb631c5f9 Reviewed-on: https://go-review.googlesource.com/115376 Run-TryBot: Lynn Boger TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/vet/all/whitelist/linux_ppc64x.txt | 1 - src/runtime/asm_ppc64x.s | 14 +++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/cmd/vet/all/whitelist/linux_ppc64x.txt b/src/cmd/vet/all/whitelist/linux_ppc64x.txt index 21e87e37d8..0091d97110 100644 --- a/src/cmd/vet/all/whitelist/linux_ppc64x.txt +++ b/src/cmd/vet/all/whitelist/linux_ppc64x.txt @@ -2,4 +2,3 @@ runtime/sys_linux_ppc64x.s: [GOARCH] _sigtramp: function _sigtramp missing Go declaration runtime/sys_linux_ppc64x.s: [GOARCH] _cgoSigtramp: function _cgoSigtramp missing Go declaration -runtime/asm_ppc64x.s: [GOARCH] procyield: use of 24(R1) points beyond argument frame diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s index b6a797640d..0886de9f2b 100644 --- a/src/runtime/asm_ppc64x.s +++ b/src/runtime/asm_ppc64x.s @@ -457,7 +457,19 @@ CALLFN(·call268435456, 268435456) CALLFN(·call536870912, 536870912) CALLFN(·call1073741824, 1073741824) -TEXT runtime·procyield(SB),NOSPLIT,$0-0 +TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0-4 + MOVW cycles+0(FP), R7 + // POWER does not have a pause/yield instruction equivalent. + // Instead, we can lower the program priority by setting the + // Program Priority Register prior to the wait loop and set it + // back to default afterwards. On Linux, the default priority is + // medium-low. For details, see page 837 of the ISA 3.0. + OR R1, R1, R1 // Set PPR priority to low +again: + SUB $1, R7 + CMP $0, R7 + BNE again + OR R6, R6, R6 // Set PPR priority back to medium-low RET // void jmpdefer(fv, sp); From 707ca18d97ccc769d78f9d16bdf94b992858977d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 19 Jun 2018 10:20:35 -0700 Subject: [PATCH 114/203] cmd/compile: more accurate position for select case error message Fixes #25958. Change-Id: I1f4808a70c20334ecfc4eb1789f5389d94dcf00e Reviewed-on: https://go-review.googlesource.com/119755 Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/select.go | 10 +++++++++- test/fixedbugs/issue25958.go | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/fixedbugs/issue25958.go diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index eb37e32bf1..4445edbe92 100644 --- a/src/cmd/compile/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go @@ -33,7 +33,15 @@ func typecheckselect(sel *Node) { ncase.List.Set(nil) switch n.Op { default: - yyerrorl(n.Pos, "select case must be receive, send or assign recv") + pos := n.Pos + if n.Op == ONAME { + // We don't have the right position for ONAME nodes (see #15459 and + // others). Using ncase.Pos for now as it will provide the correct + // line number (assuming the expression follows the "case" keyword + // on the same line). This matches the approach before 1.10. + pos = ncase.Pos + } + yyerrorl(pos, "select case must be receive, send or assign recv") // convert x = <-c into OSELRECV(x, <-c). // remove implicit conversions; the eventual assignment diff --git a/test/fixedbugs/issue25958.go b/test/fixedbugs/issue25958.go new file mode 100644 index 0000000000..ba7ee82230 --- /dev/null +++ b/test/fixedbugs/issue25958.go @@ -0,0 +1,17 @@ +// errorcheck + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +// Verify that the "must be receive" error for "case done:" appears +// on the line of the case clause, not the line of the done declaration. + +func f(done chan struct{}) { + select { + case done: // ERROR "must be receive", "not used" + case (chan struct{})(done): // ERROR "must be receive" + } +} From c6e455bb11d6da5c7a6334e0a7ea174586a83379 Mon Sep 17 00:00:00 2001 From: David Chase Date: Fri, 15 Jun 2018 15:20:57 -0400 Subject: [PATCH 115/203] cmd/compile: conditional on -race, disable inline of go:norace Adds the appropriate check to inl.go. Includes tests of both -race+go:norace and plain go:norace. Fixes #24651. Change-Id: Id806342430c20baf4679a985d12eea3b677092e0 Reviewed-on: https://go-review.googlesource.com/119195 Run-TryBot: David Chase TryBot-Result: Gobot Gobot Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/gc/inl.go | 6 ++++++ test/fixedbugs/issue24651a.go | 24 ++++++++++++++++++++++++ test/fixedbugs/issue24651b.go | 24 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 test/fixedbugs/issue24651a.go create mode 100644 test/fixedbugs/issue24651b.go diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index 25452911eb..cb3ddaf2a5 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -132,6 +132,12 @@ func caninl(fn *Node) { return } + // If marked "go:norace" and -race compilation, don't inline. + if flag_race && fn.Func.Pragma&Norace != 0 { + reason = "marked go:norace with -race compilation" + return + } + // If marked "go:cgo_unsafe_args", don't inline, since the // function makes assumptions about its argument frame layout. if fn.Func.Pragma&CgoUnsafeArgs != 0 { diff --git a/test/fixedbugs/issue24651a.go b/test/fixedbugs/issue24651a.go new file mode 100644 index 0000000000..5f63635a2a --- /dev/null +++ b/test/fixedbugs/issue24651a.go @@ -0,0 +1,24 @@ +//errorcheck -0 -race -m -m + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +//go:norace +func Foo(x int) int { // ERROR "cannot inline Foo: marked go:norace with -race compilation$" + return x * (x + 1) * (x + 2) +} + +func Bar(x int) int { // ERROR "can inline Bar as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" + return x * (x + 1) * (x + 2) +} + +var x = 5 + +//go:noinline Provide a clean, constant reason for not inlining main +func main() { // ERROR "cannot inline main: marked go:noinline$" + println("Foo(", x, ")=", Foo(x)) + println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" +} diff --git a/test/fixedbugs/issue24651b.go b/test/fixedbugs/issue24651b.go new file mode 100644 index 0000000000..2420f61fa6 --- /dev/null +++ b/test/fixedbugs/issue24651b.go @@ -0,0 +1,24 @@ +//errorcheck -0 -m -m + +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +//go:norace +func Foo(x int) int { // ERROR "can inline Foo as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" + return x * (x + 1) * (x + 2) +} + +func Bar(x int) int { // ERROR "can inline Bar as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" + return x * (x + 1) * (x + 2) +} + +var x = 5 + +//go:noinline Provide a clean, constant reason for not inlining main +func main() { // ERROR "cannot inline main: marked go:noinline$" + println("Foo(", x, ")=", Foo(x)) // ERROR "inlining call to Foo func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" + println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$" +} From 75d15a2082b9a9fcf30344062a6bfb8f4f51d79e Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Thu, 26 Apr 2018 17:35:01 -0400 Subject: [PATCH 116/203] crypto: panic on illegal input and output overlap Normalized all panic checks and added inexact aliasing panics across Stream, Block, BlockMode and AEAD implementations. Also, tweaked the aliasing docs of cipher.AEAD, as they did not account for the append nature of the API. Fixes #21624 Change-Id: I075c4415f59b3c06e3099bd9f76de6d12af086bf Reviewed-on: https://go-review.googlesource.com/109697 Run-TryBot: Filippo Valsorda TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/crypto/aes/aes_gcm.go | 15 ++- src/crypto/aes/cbc_s390x.go | 4 + src/crypto/aes/cipher.go | 7 + src/crypto/aes/cipher_amd64.go | 7 + src/crypto/aes/cipher_arm64.go | 7 + src/crypto/aes/cipher_ppc64le.go | 7 + src/crypto/aes/cipher_s390x.go | 7 + src/crypto/aes/ctr_s390x.go | 9 +- src/crypto/aes/gcm_s390x.go | 29 +++-- src/crypto/cipher/cbc.go | 8 ++ src/crypto/cipher/cfb.go | 8 ++ src/crypto/cipher/ctr.go | 8 ++ src/crypto/cipher/gcm.go | 23 ++-- src/crypto/cipher/ofb.go | 8 ++ src/crypto/des/cipher.go | 47 ++++++- src/crypto/internal/subtle/aliasing.go | 34 +++++ .../internal/subtle/aliasing_appengine.go | 37 ++++++ src/crypto/internal/subtle/aliasing_test.go | 50 ++++++++ src/crypto/rc4/rc4.go | 8 +- src/crypto/rc4/rc4_asm.go | 10 +- src/go/build/deps_test.go | 120 +++++++++--------- 21 files changed, 366 insertions(+), 87 deletions(-) create mode 100644 src/crypto/internal/subtle/aliasing.go create mode 100644 src/crypto/internal/subtle/aliasing_appengine.go create mode 100644 src/crypto/internal/subtle/aliasing_test.go diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go index c1cacdb752..13ae2fcb82 100644 --- a/src/crypto/aes/aes_gcm.go +++ b/src/crypto/aes/aes_gcm.go @@ -8,6 +8,7 @@ package aes import ( "crypto/cipher" + subtleoverlap "crypto/internal/subtle" "crypto/subtle" "errors" ) @@ -99,10 +100,10 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) { // details. func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } var counter, tagMask [gcmBlockSize]byte @@ -123,6 +124,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { gcmAesData(&g.productTable, data, &tagOut) ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } if len(plaintext) > 0 { gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) } @@ -136,12 +140,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { // for details. func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } // Sanity check to prevent the authentication from always succeeding if an implementation // leaves tagSize uninitialized, for example. if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } if len(ciphertext) < g.tagSize { @@ -173,6 +177,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { gcmAesData(&g.productTable, data, &expectedTag) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if len(ciphertext) > 0 { gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) } diff --git a/src/crypto/aes/cbc_s390x.go b/src/crypto/aes/cbc_s390x.go index 739e1febc3..28a6b1d546 100644 --- a/src/crypto/aes/cbc_s390x.go +++ b/src/crypto/aes/cbc_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" ) // Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces. @@ -48,6 +49,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } if len(src) > 0 { cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src)) } diff --git a/src/crypto/aes/cipher.go b/src/crypto/aes/cipher.go index c5a8e91d00..bb93fbb36e 100644 --- a/src/crypto/aes/cipher.go +++ b/src/crypto/aes/cipher.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "strconv" ) @@ -57,6 +58,9 @@ func (c *aesCipher) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockGo(c.enc, dst, src) } @@ -67,5 +71,8 @@ func (c *aesCipher) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockGo(c.dec, dst, src) } diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_amd64.go index 4b3b877cd7..b12d9b46a2 100644 --- a/src/crypto/aes/cipher_amd64.go +++ b/src/crypto/aes/cipher_amd64.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "internal/cpu" ) @@ -52,6 +53,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) } @@ -62,6 +66,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) } diff --git a/src/crypto/aes/cipher_arm64.go b/src/crypto/aes/cipher_arm64.go index c8027eec8b..a03547841f 100644 --- a/src/crypto/aes/cipher_arm64.go +++ b/src/crypto/aes/cipher_arm64.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "internal/cpu" "math/bits" ) @@ -40,6 +41,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) } @@ -50,6 +54,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) } diff --git a/src/crypto/aes/cipher_ppc64le.go b/src/crypto/aes/cipher_ppc64le.go index 110f61f57c..b788ea7d47 100644 --- a/src/crypto/aes/cipher_ppc64le.go +++ b/src/crypto/aes/cipher_ppc64le.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" ) // defined in asm_ppc64le.s @@ -54,6 +55,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } encryptBlockAsm(&dst[0], &src[0], &c.enc[0]) } @@ -64,6 +68,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } decryptBlockAsm(&dst[0], &src[0], &c.dec[0]) } diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go index 82f6f8f335..65b6b2fc1b 100644 --- a/src/crypto/aes/cipher_s390x.go +++ b/src/crypto/aes/cipher_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "internal/cpu" ) @@ -67,6 +68,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize) } @@ -77,6 +81,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if len(dst) < BlockSize { panic("crypto/aes: output not full block") } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/aes: invalid buffer overlap") + } // The decrypt function code is equal to the function code + 128. cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize) } diff --git a/src/crypto/aes/ctr_s390x.go b/src/crypto/aes/ctr_s390x.go index 8078aa6802..8fa85a3ae8 100644 --- a/src/crypto/aes/ctr_s390x.go +++ b/src/crypto/aes/ctr_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + "crypto/internal/subtle" "unsafe" ) @@ -64,9 +65,11 @@ func (c *aesctr) refill() { } func (c *aesctr) XORKeyStream(dst, src []byte) { - if len(src) > 0 { - // Assert len(dst) >= len(src) - _ = dst[len(src)-1] + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") } for len(src) > 0 { if len(c.buffer) == 0 { diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go index ca06ae52ac..d154ddbaa0 100644 --- a/src/crypto/aes/gcm_s390x.go +++ b/src/crypto/aes/gcm_s390x.go @@ -6,6 +6,7 @@ package aes import ( "crypto/cipher" + subtleoverlap "crypto/internal/subtle" "crypto/subtle" "errors" "internal/cpu" @@ -220,13 +221,16 @@ func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSi // details. func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } counter := g.deriveCounter(nonce) @@ -246,12 +250,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { // for details. func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } // Sanity check to prevent the authentication from always succeeding if an implementation // leaves tagSize uninitialized, for example. if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } if len(ciphertext) < g.tagSize { return nil, errOpen @@ -273,6 +277,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { g.auth(expectedTag[:], ciphertext, data, &tagMask) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { // The AESNI code decrypts and authenticates concurrently, and @@ -314,13 +321,16 @@ func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount) // details. func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } counter := g.deriveCounter(nonce) fc := g.block.function | kmaLAAD | kmaLPC @@ -336,7 +346,7 @@ func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte { // for details. func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if len(ciphertext) < g.tagSize { return nil, errOpen @@ -348,9 +358,12 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { tag := ciphertext[len(ciphertext)-g.tagSize:] ciphertext = ciphertext[:len(ciphertext)-g.tagSize] ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } counter := g.deriveCounter(nonce) diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go index 0367d5971a..0d07192e29 100644 --- a/src/crypto/cipher/cbc.go +++ b/src/crypto/cipher/cbc.go @@ -11,6 +11,8 @@ package cipher +import "crypto/internal/subtle" + type cbc struct { b Block blockSize int @@ -59,6 +61,9 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } iv := x.iv @@ -116,6 +121,9 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { if len(dst) < len(src) { panic("crypto/cipher: output smaller than input") } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } if len(src) == 0 { return } diff --git a/src/crypto/cipher/cfb.go b/src/crypto/cipher/cfb.go index 9b4eebf5b4..80c9bc24ea 100644 --- a/src/crypto/cipher/cfb.go +++ b/src/crypto/cipher/cfb.go @@ -6,6 +6,8 @@ package cipher +import "crypto/internal/subtle" + type cfb struct { b Block next []byte @@ -16,6 +18,12 @@ type cfb struct { } func (x *cfb) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } for len(src) > 0 { if x.outUsed == len(x.out) { x.b.Encrypt(x.out, x.next) diff --git a/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go index 75f46cfe51..cba028d2a4 100644 --- a/src/crypto/cipher/ctr.go +++ b/src/crypto/cipher/ctr.go @@ -12,6 +12,8 @@ package cipher +import "crypto/internal/subtle" + type ctr struct { b Block ctr []byte @@ -71,6 +73,12 @@ func (x *ctr) refill() { } func (x *ctr) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } for len(src) > 0 { if x.outUsed >= len(x.out)-x.b.BlockSize() { x.refill() diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go index 28f8b2093e..6321e9e82d 100644 --- a/src/crypto/cipher/gcm.go +++ b/src/crypto/cipher/gcm.go @@ -5,6 +5,7 @@ package cipher import ( + subtleoverlap "crypto/internal/subtle" "crypto/subtle" "errors" ) @@ -26,8 +27,8 @@ type AEAD interface { // slice. The nonce must be NonceSize() bytes long and unique for all // time, for a given key. // - // The plaintext and dst must overlap exactly or not at all. To reuse - // plaintext's storage for the encrypted output, use plaintext[:0] as dst. + // To reuse plaintext's storage for the encrypted output, use plaintext[:0] + // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext. Seal(dst, nonce, plaintext, additionalData []byte) []byte // Open decrypts and authenticates ciphertext, authenticates the @@ -36,8 +37,8 @@ type AEAD interface { // bytes long and both it and the additional data must match the // value passed to Seal. // - // The ciphertext and dst must overlap exactly or not at all. To reuse - // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst. + // To reuse ciphertext's storage for the decrypted output, use ciphertext[:0] + // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext. // // Even if the function fails, the contents of dst, up to its capacity, // may be overwritten. @@ -159,13 +160,16 @@ func (g *gcm) Overhead() int { func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) { - panic("cipher: message too large for GCM") + panic("crypto/cipher: message too large for GCM") } ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) + if subtleoverlap.InexactOverlap(out, plaintext) { + panic("crypto/cipher: invalid buffer overlap") + } var counter, tagMask [gcmBlockSize]byte g.deriveCounter(&counter, nonce) @@ -186,12 +190,12 @@ var errOpen = errors.New("cipher: message authentication failed") func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { if len(nonce) != g.nonceSize { - panic("cipher: incorrect nonce length given to GCM") + panic("crypto/cipher: incorrect nonce length given to GCM") } // Sanity check to prevent the authentication from always succeeding if an implementation // leaves tagSize uninitialized, for example. if g.tagSize < gcmMinimumTagSize { - panic("cipher: incorrect GCM tag size") + panic("crypto/cipher: incorrect GCM tag size") } if len(ciphertext) < g.tagSize { @@ -214,6 +218,9 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { g.auth(expectedTag[:], ciphertext, data, &tagMask) ret, out := sliceForAppend(dst, len(ciphertext)) + if subtleoverlap.InexactOverlap(out, ciphertext) { + panic("crypto/cipher: invalid buffer overlap") + } if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { // The AESNI code decrypts and authenticates concurrently, and diff --git a/src/crypto/cipher/ofb.go b/src/crypto/cipher/ofb.go index 7b35f8995c..fc47724865 100644 --- a/src/crypto/cipher/ofb.go +++ b/src/crypto/cipher/ofb.go @@ -6,6 +6,8 @@ package cipher +import "crypto/internal/subtle" + type ofb struct { b Block cipher []byte @@ -54,6 +56,12 @@ func (x *ofb) refill() { } func (x *ofb) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } for len(src) > 0 { if x.outUsed >= len(x.out)-x.b.BlockSize() { x.refill() diff --git a/src/crypto/des/cipher.go b/src/crypto/des/cipher.go index 46af5b0f02..9e6779c216 100644 --- a/src/crypto/des/cipher.go +++ b/src/crypto/des/cipher.go @@ -6,6 +6,7 @@ package des import ( "crypto/cipher" + "crypto/internal/subtle" "encoding/binary" "strconv" ) @@ -37,9 +38,31 @@ func NewCipher(key []byte) (cipher.Block, error) { func (c *desCipher) BlockSize() int { return BlockSize } -func (c *desCipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) } +func (c *desCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + encryptBlock(c.subkeys[:], dst, src) +} -func (c *desCipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) } +func (c *desCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + decryptBlock(c.subkeys[:], dst, src) +} // A tripleDESCipher is an instance of TripleDES encryption. type tripleDESCipher struct { @@ -62,6 +85,16 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) { func (c *tripleDESCipher) BlockSize() int { return BlockSize } func (c *tripleDESCipher) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + b := binary.BigEndian.Uint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) @@ -87,6 +120,16 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) { } func (c *tripleDESCipher) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/des: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/des: output not full block") + } + if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { + panic("crypto/des: invalid buffer overlap") + } + b := binary.BigEndian.Uint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) diff --git a/src/crypto/internal/subtle/aliasing.go b/src/crypto/internal/subtle/aliasing.go new file mode 100644 index 0000000000..812ce3c655 --- /dev/null +++ b/src/crypto/internal/subtle/aliasing.go @@ -0,0 +1,34 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +// +// This is a mirror of golang.org/x/crypto/internal/subtle. +package subtle // import "crypto/internal/subtle" + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/src/crypto/internal/subtle/aliasing_appengine.go b/src/crypto/internal/subtle/aliasing_appengine.go new file mode 100644 index 0000000000..844f901d18 --- /dev/null +++ b/src/crypto/internal/subtle/aliasing_appengine.go @@ -0,0 +1,37 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +// +// This is a mirror of golang.org/x/crypto/internal/subtle. +package subtle // import "crypto/internal/subtle" + +// This is the Google App Engine standard variant based on reflect +// because the unsafe package and cgo are disallowed. + +import "reflect" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && + reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/src/crypto/internal/subtle/aliasing_test.go b/src/crypto/internal/subtle/aliasing_test.go new file mode 100644 index 0000000000..f1e7238481 --- /dev/null +++ b/src/crypto/internal/subtle/aliasing_test.go @@ -0,0 +1,50 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package subtle_test + +import ( + "testing" + + "crypto/internal/subtle" +) + +var a, b [100]byte + +var aliasingTests = []struct { + x, y []byte + anyOverlap, inexactOverlap bool +}{ + {a[:], b[:], false, false}, + {a[:], b[:0], false, false}, + {a[:], b[:50], false, false}, + {a[40:50], a[50:60], false, false}, + {a[40:50], a[60:70], false, false}, + {a[:51], a[50:], true, true}, + {a[:], a[:], true, false}, + {a[:50], a[:60], true, false}, + {a[:], nil, false, false}, + {nil, nil, false, false}, + {a[:], a[:0], false, false}, + {a[:10], a[:10:20], true, false}, + {a[:10], a[5:10:20], true, true}, +} + +func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) { + any := subtle.AnyOverlap(x, y) + if any != anyOverlap { + t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any) + } + inexact := subtle.InexactOverlap(x, y) + if inexact != inexactOverlap { + t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any) + } +} + +func TestAliasing(t *testing.T) { + for i, tt := range aliasingTests { + testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap) + testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap) + } +} diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go index cf08ba7f8c..c445bb078f 100644 --- a/src/crypto/rc4/rc4.go +++ b/src/crypto/rc4/rc4.go @@ -9,7 +9,10 @@ // applications. package rc4 -import "strconv" +import ( + "crypto/internal/subtle" + "strconv" +) // A Cipher is an instance of RC4 using a particular key. type Cipher struct { @@ -60,6 +63,9 @@ func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) { if len(src) == 0 { return } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/rc4: invalid buffer overlap") + } i, j := c.i, c.j _ = dst[len(src)-1] dst = dst[:len(src)] // eliminate bounds check from loop diff --git a/src/crypto/rc4/rc4_asm.go b/src/crypto/rc4/rc4_asm.go index 7e5f8b2fa4..fc79e7ffc7 100644 --- a/src/crypto/rc4/rc4_asm.go +++ b/src/crypto/rc4/rc4_asm.go @@ -6,6 +6,8 @@ package rc4 +import "crypto/internal/subtle" + func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8) // XORKeyStream sets dst to the result of XORing src with the key stream. @@ -14,7 +16,11 @@ func (c *Cipher) XORKeyStream(dst, src []byte) { if len(src) == 0 { return } - // Assert len(dst) >= len(src) - _ = dst[len(src)-1] + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("crypto/cipher: invalid buffer overlap") + } xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j) } diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 663d5246f8..508ed8ac30 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -99,27 +99,29 @@ var pkgDeps = map[string][]string{ // L3 adds reflection and some basic utility packages // and interface definitions, but nothing that makes // system calls. - "crypto": {"L2", "hash"}, // interfaces - "crypto/cipher": {"L2", "crypto/subtle"}, - "crypto/subtle": {}, - "encoding/base32": {"L2"}, - "encoding/base64": {"L2", "encoding/binary"}, - "encoding/binary": {"L2", "reflect"}, - "hash": {"L2"}, // interfaces - "hash/adler32": {"L2", "hash"}, - "hash/crc32": {"L2", "hash"}, - "hash/crc64": {"L2", "hash"}, - "hash/fnv": {"L2", "hash"}, - "image": {"L2", "image/color"}, // interfaces - "image/color": {"L2"}, // interfaces - "image/color/palette": {"L2", "image/color"}, - "reflect": {"L2"}, - "sort": {"reflect"}, + "crypto": {"L2", "hash"}, // interfaces + "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"}, + "crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag + "crypto/subtle": {}, + "encoding/base32": {"L2"}, + "encoding/base64": {"L2", "encoding/binary"}, + "encoding/binary": {"L2", "reflect"}, + "hash": {"L2"}, // interfaces + "hash/adler32": {"L2", "hash"}, + "hash/crc32": {"L2", "hash"}, + "hash/crc64": {"L2", "hash"}, + "hash/fnv": {"L2", "hash"}, + "image": {"L2", "image/color"}, // interfaces + "image/color": {"L2"}, // interfaces + "image/color/palette": {"L2", "image/color"}, + "reflect": {"L2"}, + "sort": {"reflect"}, "L3": { "L2", "crypto", "crypto/cipher", + "crypto/internal/subtle", "crypto/subtle", "encoding/base32", "encoding/base64", @@ -229,49 +231,49 @@ var pkgDeps = map[string][]string{ "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, // One of a kind. - "archive/tar": {"L4", "OS", "syscall", "os/user"}, - "archive/zip": {"L4", "OS", "compress/flate"}, - "container/heap": {"sort"}, - "compress/bzip2": {"L4"}, - "compress/flate": {"L4"}, - "compress/gzip": {"L4", "compress/flate"}, - "compress/lzw": {"L4"}, - "compress/zlib": {"L4", "compress/flate"}, - "context": {"errors", "fmt", "reflect", "sync", "time"}, - "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"}, - "database/sql/driver": {"L4", "context", "time", "database/sql/internal"}, - "debug/dwarf": {"L4"}, - "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, - "debug/gosym": {"L4"}, - "debug/macho": {"L4", "OS", "debug/dwarf"}, - "debug/pe": {"L4", "OS", "debug/dwarf"}, - "debug/plan9obj": {"L4", "OS"}, - "encoding": {"L4"}, - "encoding/ascii85": {"L4"}, - "encoding/asn1": {"L4", "math/big"}, - "encoding/csv": {"L4"}, - "encoding/gob": {"L4", "OS", "encoding"}, - "encoding/hex": {"L4"}, - "encoding/json": {"L4", "encoding"}, - "encoding/pem": {"L4"}, - "encoding/xml": {"L4", "encoding"}, - "flag": {"L4", "OS"}, - "go/build": {"L4", "OS", "GOPARSER"}, - "html": {"L4"}, - "image/draw": {"L4", "image/internal/imageutil"}, - "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, - "image/internal/imageutil": {"L4"}, - "image/jpeg": {"L4", "image/internal/imageutil"}, - "image/png": {"L4", "compress/zlib"}, - "index/suffixarray": {"L4", "regexp"}, - "internal/singleflight": {"sync"}, - "internal/trace": {"L4", "OS"}, - "math/big": {"L4"}, - "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, - "mime/quotedprintable": {"L4"}, - "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, - "net/url": {"L4"}, - "plugin": {"L0", "OS", "CGO"}, + "archive/tar": {"L4", "OS", "syscall", "os/user"}, + "archive/zip": {"L4", "OS", "compress/flate"}, + "container/heap": {"sort"}, + "compress/bzip2": {"L4"}, + "compress/flate": {"L4"}, + "compress/gzip": {"L4", "compress/flate"}, + "compress/lzw": {"L4"}, + "compress/zlib": {"L4", "compress/flate"}, + "context": {"errors", "fmt", "reflect", "sync", "time"}, + "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"}, + "database/sql/driver": {"L4", "context", "time", "database/sql/internal"}, + "debug/dwarf": {"L4"}, + "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, + "debug/gosym": {"L4"}, + "debug/macho": {"L4", "OS", "debug/dwarf"}, + "debug/pe": {"L4", "OS", "debug/dwarf"}, + "debug/plan9obj": {"L4", "OS"}, + "encoding": {"L4"}, + "encoding/ascii85": {"L4"}, + "encoding/asn1": {"L4", "math/big"}, + "encoding/csv": {"L4"}, + "encoding/gob": {"L4", "OS", "encoding"}, + "encoding/hex": {"L4"}, + "encoding/json": {"L4", "encoding"}, + "encoding/pem": {"L4"}, + "encoding/xml": {"L4", "encoding"}, + "flag": {"L4", "OS"}, + "go/build": {"L4", "OS", "GOPARSER"}, + "html": {"L4"}, + "image/draw": {"L4", "image/internal/imageutil"}, + "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, + "image/internal/imageutil": {"L4"}, + "image/jpeg": {"L4", "image/internal/imageutil"}, + "image/png": {"L4", "compress/zlib"}, + "index/suffixarray": {"L4", "regexp"}, + "internal/singleflight": {"sync"}, + "internal/trace": {"L4", "OS"}, + "math/big": {"L4"}, + "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, + "mime/quotedprintable": {"L4"}, + "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, + "net/url": {"L4"}, + "plugin": {"L0", "OS", "CGO"}, "runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"}, "testing/internal/testdeps": {"L4", "internal/testlog", "runtime/pprof", "regexp"}, "text/scanner": {"L4", "OS"}, From 500293d8dce663dafea7482f06a6c828faf4e88b Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Tue, 19 Jun 2018 16:14:00 -0400 Subject: [PATCH 117/203] doc: update "Mac OS X", "OS X" to macOS; bump up to 10.10 The name was "Mac OS X" during versions 10.0 to 10.7. It was renamed to "OS X" starting from 10.8 until 10.11. The current name is "macOS" starting with 10.12. [1] Previous changes (e.g., CL 47252) updated "Mac OS X" to macOS in some places, but not everywhere. This CL updates remaining instances for consistency. Only the pages that display current information were updated; historical pages such as release notes for older Go releases, past articles, blog posts, etc., were left in original form. Rename the "#osx" anchor to "#macos" on /doc/install page, along with the single reference to it on the same page. Add an empty div with id="osx" to not break old links. Update minimum macOS version from 10.8 to 10.10 per #23122. [1]: https://en.wikipedia.org/wiki/macOS#History Updates #23122. Change-Id: I69fe4b85e83265b9d99f447e3cc5230dde094869 Reviewed-on: https://go-review.googlesource.com/119855 Reviewed-by: Brad Fitzpatrick --- doc/debugging_with_gdb.html | 2 +- doc/go_faq.html | 2 +- doc/install-source.html | 4 ++-- doc/install.html | 12 ++++++------ doc/root.html | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html index ca9d9a7c46..f3b4e37a28 100644 --- a/doc/debugging_with_gdb.html +++ b/doc/debugging_with_gdb.html @@ -57,7 +57,7 @@ Besides this overview you might want to consult the

    When you compile and link your Go programs with the gc toolchain -on Linux, Mac OS X, FreeBSD or NetBSD, the resulting binaries contain DWARFv4 +on Linux, macOS, FreeBSD or NetBSD, the resulting binaries contain DWARFv4 debugging information that recent versions (≥7.5) of the GDB debugger can use to inspect a live process or a core dump.

    diff --git a/doc/go_faq.html b/doc/go_faq.html index e83408e6f1..e020ce12c1 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -1396,7 +1396,7 @@ reservation does not deprive other processes of memory.

    To find the amount of actual memory allocated to a Go process, use the Unix top command and consult the RES (Linux) or -RSIZE (Mac OS X) columns. +RSIZE (macOS) columns.

    diff --git a/doc/install-source.html b/doc/install-source.html index 844fb002f7..f6d9473d9b 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -98,7 +98,7 @@ goroutines, such as stacks that grow and shrink on demand.

    The compilers can target the DragonFly BSD, FreeBSD, Linux, NetBSD, OpenBSD, -OS X (Darwin), Plan 9, Solaris and Windows operating systems. +macOS (Darwin), Plan 9, Solaris and Windows operating systems. The full set of supported combinations is listed in the discussion of environment variables below.

    @@ -468,7 +468,7 @@ These default to the values of $GOHOSTOS and

    Choices for $GOOS are -darwin (Mac OS X 10.8 and above and iOS), dragonfly, freebsd, +darwin (macOS 10.10 and above and iOS), dragonfly, freebsd, linux, netbsd, openbsd, plan9, solaris and windows. Choices for $GOARCH are diff --git a/doc/install.html b/doc/install.html index cd51e7603a..3bb4a15b25 100644 --- a/doc/install.html +++ b/doc/install.html @@ -17,7 +17,7 @@

    Official binary distributions are available for the FreeBSD (release 10-STABLE and above), -Linux, Mac OS X (10.8 and above), and Windows operating systems and +Linux, macOS (10.10 and above), and Windows operating systems and the 32-bit (386) and 64-bit (amd64) x86 processor architectures.

    @@ -49,7 +49,7 @@ If your OS or architecture is not on the list, you may be able to
    FreeBSD 10.3 or later amd64, 386 Debian GNU/kFreeBSD not supported Linux 2.6.23 or later with glibc amd64, 386, arm, arm64,
    s390x, ppc64le CentOS/RHEL 5.x not supported.
    Install from source for other libc. -macOS 10.8 or later amd64 use the clang or gcc that comes with Xcode for cgo support +macOS 10.10 or later amd64 use the clang or gcc that comes with Xcode for cgo support Windows XP SP2 or later amd64, 386 use MinGW gcc. No need for cygwin or msys. @@ -74,7 +74,7 @@ first remove the existing version.
    -

    Linux, Mac OS X, and FreeBSD tarballs

    +

    Linux, macOS, and FreeBSD tarballs

    Download the archive @@ -118,7 +118,7 @@ or execute them from the profile using a command such as

    -

    Mac OS X package installer

    +

    macOS package installer

    Download the package file, @@ -276,7 +276,7 @@ which describes some essential concepts about using the Go tools.

    To remove an existing Go installation from your system delete the go directory. This is usually /usr/local/go -under Linux, Mac OS X, and FreeBSD or c:\Go +under Linux, macOS, and FreeBSD or c:\Go under Windows.

    @@ -285,7 +285,7 @@ You should also remove the Go bin directory from your PATH environment variable. Under Linux and FreeBSD you should edit /etc/profile or $HOME/.profile. -If you installed Go with the Mac OS X package then you +If you installed Go with the macOS package then you should remove the /etc/paths.d/go file. Windows users should read the section about setting environment variables under Windows. diff --git a/doc/root.html b/doc/root.html index 545b28d2d5..b7422f2128 100644 --- a/doc/root.html +++ b/doc/root.html @@ -62,7 +62,7 @@ simple, reliable, and efficient software. Download Go Binary distributions available for
    -Linux, Mac OS X, Windows, and more. +Linux, macOS, Windows, and more.
    From 83515df3f31cc70eab2ea4af77e675cabe1eefd5 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Tue, 19 Jun 2018 15:39:17 -0400 Subject: [PATCH 118/203] cmd/link: enable DWARF compression on Windows Simple follow-on to CL 118276. Everything worked except that the compressed sections need to be aligned at PEFILEALIGN. Fixes #25927 Updates #11799 Change-Id: Iec871defe30e3e66055d64a5ae77d5a7aca355f5 Reviewed-on: https://go-review.googlesource.com/119816 Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick Reviewed-by: Austin Clements --- src/cmd/link/internal/ld/dwarf.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 3824dc3c2a..1dd45969c7 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1951,7 +1951,7 @@ func dwarfaddelfsectionsyms(ctxt *Link) { // relocations are applied. After this, dwarfp will contain a // different (new) set of symbols, and sections may have been replaced. func dwarfcompress(ctxt *Link) { - if !ctxt.IsELF || ctxt.LinkMode == LinkExternal { + if !(ctxt.IsELF || ctxt.HeadType == objabi.Hwindows) || ctxt.LinkMode == LinkExternal { return } @@ -1998,6 +1998,10 @@ func dwarfcompress(ctxt *Link) { log.Fatalf("%s: unexpected sub-symbols", s) } pos += uint64(s.Size) + if ctxt.HeadType == objabi.Hwindows { + pos = uint64(Rnd(int64(pos), PEFILEALIGN)) + } + } Segdwarf.Length = pos - Segdwarf.Vaddr } From 2036f16247c6702a95d6c5e876a35c8ef484dbf8 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Tue, 19 Jun 2018 15:41:45 -0400 Subject: [PATCH 119/203] debug/elf,macho,pe: support compressed DWARF Since we're going to start compressing DWARF on Windows and maybe Darwin, copy the ELF support for .zdebug sections to macho and pe. The code is almost completely the same across the three. While I was here I added support for compressed .debug_type sections, which I presume were overlooked before. Tests will come in a later CL once we can actually generate compressed PE/Mach-O binaries, since there's no other good way to get test data. Updates #25927, #11799 Change-Id: Ie920b6a16e9270bc3df214ce601a263837810376 Reviewed-on: https://go-review.googlesource.com/119815 Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick Reviewed-by: Austin Clements --- src/debug/elf/file.go | 41 +++++++++++------- src/debug/macho/file.go | 86 ++++++++++++++++++++++++++++++------ src/debug/pe/file.go | 91 +++++++++++++++++++++++++++++++++------ src/go/build/deps_test.go | 4 +- 4 files changed, 178 insertions(+), 44 deletions(-) diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go index 25b72642d8..b2adc2834f 100644 --- a/src/debug/elf/file.go +++ b/src/debug/elf/file.go @@ -1112,6 +1112,17 @@ func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { } func (f *File) DWARF() (*dwarf.Data, error) { + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, ".debug_"): + return s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + return s.Name[8:] + default: + return "" + } + + } // sectionData gets the data for s, checks its size, and // applies any applicable relations. sectionData := func(i int, s *Section) ([]byte, error) { @@ -1160,13 +1171,8 @@ func (f *File) DWARF() (*dwarf.Data, error) { // Don't bother loading others. var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} for i, s := range f.Sections { - suffix := "" - switch { - case strings.HasPrefix(s.Name, ".debug_"): - suffix = s.Name[7:] - case strings.HasPrefix(s.Name, ".zdebug_"): - suffix = s.Name[8:] - default: + suffix := dwarfSuffix(s) + if suffix == "" { continue } if _, ok := dat[suffix]; !ok { @@ -1186,16 +1192,19 @@ func (f *File) DWARF() (*dwarf.Data, error) { // Look for DWARF4 .debug_types sections. for i, s := range f.Sections { - if s.Name == ".debug_types" { - b, err := sectionData(i, s) - if err != nil { - return nil, err - } + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } - err = d.AddTypes(fmt.Sprintf("types-%d", i), b) - if err != nil { - return nil, err - } + b, err := sectionData(i, s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err } } diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go index da5d9cad4c..16708e5247 100644 --- a/src/debug/macho/file.go +++ b/src/debug/macho/file.go @@ -9,11 +9,13 @@ package macho import ( "bytes" + "compress/zlib" "debug/dwarf" "encoding/binary" "fmt" "io" "os" + "strings" ) // A File represents an open Mach-O file. @@ -575,26 +577,84 @@ func (f *File) Section(name string) *Section { // DWARF returns the DWARF debug information for the Mach-O file. func (f *File) DWARF() (*dwarf.Data, error) { - // There are many other DWARF sections, but these - // are the ones the debug/dwarf package uses. - // Don't bother loading others. - var names = [...]string{"abbrev", "info", "line", "ranges", "str"} - var dat [len(names)][]byte - for i, name := range names { - name = "__debug_" + name - s := f.Section(name) - if s == nil { - continue + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, "__debug_"): + return s.Name[8:] + case strings.HasPrefix(s.Name, "__zdebug_"): + return s.Name[9:] + default: + return "" } + + } + sectionData := func(s *Section) ([]byte, error) { b, err := s.Data() if err != nil && uint64(len(b)) < s.Size { return nil, err } - dat[i] = b + + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + return b, nil } - abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] - return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for _, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; !ok { + continue + } + b, err := sectionData(s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err + } + } + + return d, nil } // ImportedSymbols returns the names of all symbols diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go index 6fc1f3a60f..2f5efae4e6 100644 --- a/src/debug/pe/file.go +++ b/src/debug/pe/file.go @@ -6,11 +6,14 @@ package pe import ( + "bytes" + "compress/zlib" "debug/dwarf" "encoding/binary" "fmt" "io" "os" + "strings" ) // Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap. @@ -217,29 +220,91 @@ func (f *File) Section(name string) *Section { } func (f *File) DWARF() (*dwarf.Data, error) { - // There are many other DWARF sections, but these - // are the ones the debug/dwarf package uses. - // Don't bother loading others. - var names = [...]string{"abbrev", "info", "line", "ranges", "str"} - var dat [len(names)][]byte - for i, name := range names { - name = ".debug_" + name - s := f.Section(name) - if s == nil { - continue + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, ".debug_"): + return s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + return s.Name[8:] + default: + return "" } + + } + + // sectionData gets the data for s and checks its size. + sectionData := func(s *Section) ([]byte, error) { b, err := s.Data() if err != nil && uint32(len(b)) < s.Size { return nil, err } + if 0 < s.VirtualSize && s.VirtualSize < s.Size { b = b[:s.VirtualSize] } - dat[i] = b + + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + return b, nil } - abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] - return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for _, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; !ok { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } + + b, err := sectionData(s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err + } + } + + return d, nil } // TODO(brainman): document ImportDirectory once we decide what to do with it. diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 508ed8ac30..29dbe47d29 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -245,8 +245,8 @@ var pkgDeps = map[string][]string{ "debug/dwarf": {"L4"}, "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, "debug/gosym": {"L4"}, - "debug/macho": {"L4", "OS", "debug/dwarf"}, - "debug/pe": {"L4", "OS", "debug/dwarf"}, + "debug/macho": {"L4", "OS", "debug/dwarf", "compress/zlib"}, + "debug/pe": {"L4", "OS", "debug/dwarf", "compress/zlib"}, "debug/plan9obj": {"L4", "OS"}, "encoding": {"L4"}, "encoding/ascii85": {"L4"}, From 65d55a13a92a3bbc2a3750fd3318d63bd3e664c9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 17 Jun 2018 17:27:13 +0000 Subject: [PATCH 120/203] runtime: fix FreeBSDNumCPU test num cpu unit test fixes for FreeBSD. cpuset -g can possibly output more data than expected. Fixes #25924 Change-Id: Iec45a919df68648759331da7cd1fa3b9f3ca4241 GitHub-Last-Rev: 4cc275b519cda13189ec48b581ab9ce00cacd7f6 GitHub-Pull-Request: golang/go#25931 Reviewed-on: https://go-review.googlesource.com/119376 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/runtime/testdata/testprog/numcpu_freebsd.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/runtime/testdata/testprog/numcpu_freebsd.go b/src/runtime/testdata/testprog/numcpu_freebsd.go index 035c53470b..42ee154883 100644 --- a/src/runtime/testdata/testprog/numcpu_freebsd.go +++ b/src/runtime/testdata/testprog/numcpu_freebsd.go @@ -9,12 +9,17 @@ import ( "fmt" "os" "os/exec" + "regexp" "runtime" "strconv" "strings" "syscall" ) +var ( + cpuSetRE = regexp.MustCompile(`(\d,?)+`) +) + func init() { register("FreeBSDNumCPU", FreeBSDNumCPU) register("FreeBSDNumCPUHelper", FreeBSDNumCPUHelper) @@ -105,8 +110,12 @@ func checkNCPU(list []string) error { return fmt.Errorf("could not check against an empty CPU list") } + cListString := cpuSetRE.FindString(listString) + if len(cListString) == 0 { + return fmt.Errorf("invalid cpuset output '%s'", listString) + } // Launch FreeBSDNumCPUHelper() with specified CPUs list. - cmd := exec.Command("cpuset", "-l", listString, os.Args[0], "FreeBSDNumCPUHelper") + cmd := exec.Command("cpuset", "-l", cListString, os.Args[0], "FreeBSDNumCPUHelper") cmdline := strings.Join(cmd.Args, " ") output, err := cmd.CombinedOutput() if err != nil { @@ -120,7 +129,7 @@ func checkNCPU(list []string) error { return fmt.Errorf("fail to parse output from child '%s', error: %s, output: %s", cmdline, err, output) } if n != len(list) { - return fmt.Errorf("runtime.NumCPU() expected to %d, got %d when run with CPU list %s", len(list), n, listString) + return fmt.Errorf("runtime.NumCPU() expected to %d, got %d when run with CPU list %s", len(list), n, cListString) } return nil } From 29673a4be6770422774968a287e87bf7c8330497 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 19 Jun 2018 16:55:19 -0700 Subject: [PATCH 121/203] misc/cgo/test: avoid duplicate definition with gccgo Current versions of gccgo issue a duplicate definition error when both a definition and an empty declaration occur. Use build tags to avoid that case for the issue9400 subdirectory. Change-Id: I18517af87bab05e9ca43f2f295459cf34347c317 Reviewed-on: https://go-review.googlesource.com/119896 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- misc/cgo/test/issue9400/gccgo.go | 2 ++ misc/cgo/test/issue9400/stubs.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/misc/cgo/test/issue9400/gccgo.go b/misc/cgo/test/issue9400/gccgo.go index 0ef3a8cacf..a9b62b07a0 100644 --- a/misc/cgo/test/issue9400/gccgo.go +++ b/misc/cgo/test/issue9400/gccgo.go @@ -16,6 +16,8 @@ import ( // without writing more assembly code, which we haven't bothered to // do. So this is not much of a test. +var Baton int32 + func RewindAndSetgid() { atomic.StoreInt32(&Baton, 1) for atomic.LoadInt32(&Baton) != 0 { diff --git a/misc/cgo/test/issue9400/stubs.go b/misc/cgo/test/issue9400/stubs.go index 60193dc411..e431c5a28a 100644 --- a/misc/cgo/test/issue9400/stubs.go +++ b/misc/cgo/test/issue9400/stubs.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build gc + package issue9400 var Baton int32 From 0c9be48a90bfafac68cde05c4d7db8eee17492f6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 19 Jun 2018 16:53:18 -0700 Subject: [PATCH 122/203] go/internal/gccgoimporter: read export data from archives When used with the go tool, gccgo will normally generate archive files. This change teaches the gccgoimporter package how to read the export data from an archive. This is needed by, for example, cmd/vet, when typechecking packages. Change-Id: I21267949a7808cd81c0042af425c774a4ff7d82f Reviewed-on: https://go-review.googlesource.com/119895 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/go/internal/gccgoimporter/ar.go | 148 ++++++++++++++++++ src/go/internal/gccgoimporter/importer.go | 52 +++--- .../internal/gccgoimporter/importer_test.go | 1 + .../gccgoimporter/testdata/libimportsar.a | Bin 0 -> 9302 bytes 4 files changed, 179 insertions(+), 22 deletions(-) create mode 100644 src/go/internal/gccgoimporter/ar.go create mode 100644 src/go/internal/gccgoimporter/testdata/libimportsar.a diff --git a/src/go/internal/gccgoimporter/ar.go b/src/go/internal/gccgoimporter/ar.go new file mode 100644 index 0000000000..ebd08b8f35 --- /dev/null +++ b/src/go/internal/gccgoimporter/ar.go @@ -0,0 +1,148 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gccgoimporter + +import ( + "bytes" + "debug/elf" + "errors" + "fmt" + "io" + "strconv" + "strings" +) + +// Magic strings for different archive file formats. +const ( + armag = "!\n" + armagt = "!\n" + armagb = "\n" +) + +// Offsets and sizes for fields in a standard archive header. +const ( + arNameOff = 0 + arNameSize = 16 + arDateOff = arNameOff + arNameSize + arDateSize = 12 + arUIDOff = arDateOff + arDateSize + arUIDSize = 6 + arGIDOff = arUIDOff + arUIDSize + arGIDSize = 6 + arModeOff = arGIDOff + arGIDSize + arModeSize = 8 + arSizeOff = arModeOff + arModeSize + arSizeSize = 10 + arFmagOff = arSizeOff + arSizeSize + arFmagSize = 2 + + arHdrSize = arFmagOff + arFmagSize +) + +// The contents of the fmag field of a standard archive header. +const arfmag = "`\n" + +// arExportData takes an archive file and returns a ReadSeeker for the +// export data in that file. This assumes that there is only one +// object in the archive containing export data, which is not quite +// what gccgo does; gccgo concatenates together all the export data +// for all the objects in the file. In practice that case does not arise. +func arExportData(archive io.ReadSeeker) (io.ReadSeeker, error) { + if _, err := archive.Seek(0, io.SeekStart); err != nil { + return nil, err + } + + var buf [len(armag)]byte + if _, err := archive.Read(buf[:]); err != nil { + return nil, err + } + + switch string(buf[:]) { + case armag: + return standardArExportData(archive) + case armagt: + return nil, errors.New("unsupported thin archive") + case armagb: + return nil, errors.New("unsupported AIX big archive") + default: + return nil, fmt.Errorf("unrecognized archive file format %q", buf[:]) + } +} + +// standardArExportData returns export data form a standard archive. +func standardArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) { + off := int64(len(armag)) + for { + var hdrBuf [arHdrSize]byte + if _, err := archive.Read(hdrBuf[:]); err != nil { + return nil, err + } + off += arHdrSize + + if bytes.Compare(hdrBuf[arFmagOff:arFmagOff+arFmagSize], []byte(arfmag)) != 0 { + return nil, fmt.Errorf("archive header format header (%q)", hdrBuf[:]) + } + + size, err := strconv.ParseInt(strings.TrimSpace(string(hdrBuf[arSizeOff:arSizeOff+arSizeSize])), 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing size in archive header (%q): %v", hdrBuf[:], err) + } + + fn := hdrBuf[arNameOff : arNameOff+arNameSize] + if fn[0] == '/' && (fn[1] == ' ' || fn[1] == '/' || bytes.Compare(fn[:8], []byte("/SYM64/ ")) == 0) { + // Archive symbol table or extended name table, + // which we don't care about. + } else { + archiveAt := readerAtFromSeeker(archive) + ret, err := elfFromAr(io.NewSectionReader(archiveAt, off, size)) + if ret != nil || err != nil { + return ret, err + } + } + + if size&1 != 0 { + size++ + } + off += size + if _, err := archive.Seek(off, io.SeekStart); err != nil { + return nil, err + } + } +} + +// elfFromAr tries to get export data from an archive member as an ELF file. +// If there is no export data, this returns nil, nil. +func elfFromAr(member *io.SectionReader) (io.ReadSeeker, error) { + ef, err := elf.NewFile(member) + if err != nil { + return nil, err + } + sec := ef.Section(".go_export") + if sec == nil { + return nil, nil + } + return sec.Open(), nil +} + +// readerAtFromSeeker turns an io.ReadSeeker into an io.ReaderAt. +// This is only safe because there won't be any concurrent seeks +// while this code is executing. +func readerAtFromSeeker(rs io.ReadSeeker) io.ReaderAt { + if ret, ok := rs.(io.ReaderAt); ok { + return ret + } + return seekerReadAt{rs} +} + +type seekerReadAt struct { + seeker io.ReadSeeker +} + +func (sra seekerReadAt) ReadAt(p []byte, off int64) (int, error) { + if _, err := sra.seeker.Seek(off, io.SeekStart); err != nil { + return 0, err + } + return sra.seeker.Read(p) +} diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go index d4998cf2a2..159cc50719 100644 --- a/src/go/internal/gccgoimporter/importer.go +++ b/src/go/internal/gccgoimporter/importer.go @@ -6,13 +6,11 @@ package gccgoimporter // import "go/internal/gccgoimporter" import ( - "bytes" "debug/elf" "fmt" "go/types" "io" "os" - "os/exec" "path/filepath" "strings" ) @@ -98,18 +96,8 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e return case archiveMagic: - // TODO(pcc): Read the archive directly instead of using "ar". - f.Close() - closer = nil - - cmd := exec.Command("ar", "p", fpath) - var out []byte - out, err = cmd.Output() - if err != nil { - return - } - - elfreader = bytes.NewReader(out) + reader, err = arExportData(f) + return default: elfreader = f @@ -189,17 +177,24 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo reader = r } - var magic [4]byte - _, err = reader.Read(magic[:]) - if err != nil { - return - } - _, err = reader.Seek(0, io.SeekStart) + var magics string + magics, err = readMagic(reader) if err != nil { return } - switch string(magic[:]) { + if magics == archiveMagic { + reader, err = arExportData(reader) + if err != nil { + return + } + magics, err = readMagic(reader) + if err != nil { + return + } + } + + switch magics { case gccgov1Magic, gccgov2Magic: var p parser p.init(fpath, reader, imports) @@ -230,9 +225,22 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo // } default: - err = fmt.Errorf("unrecognized magic string: %q", string(magic[:])) + err = fmt.Errorf("unrecognized magic string: %q", magics) } return } } + +// readMagic reads the four bytes at the start of a ReadSeeker and +// returns them as a string. +func readMagic(reader io.ReadSeeker) (string, error) { + var magic [4]byte + if _, err := reader.Read(magic[:]); err != nil { + return "", err + } + if _, err := reader.Seek(0, io.SeekStart); err != nil { + return "", err + } + return string(magic[:]), nil +} diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go index 01ab47a445..5a699687bd 100644 --- a/src/go/internal/gccgoimporter/importer_test.go +++ b/src/go/internal/gccgoimporter/importer_test.go @@ -101,6 +101,7 @@ var importerTests = [...]importerTest{ {pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"}, {pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"}, {pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}}, + {pkgpath: "importsar", name: "Hello", want: "var Hello string"}, {pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"}, {pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"}, } diff --git a/src/go/internal/gccgoimporter/testdata/libimportsar.a b/src/go/internal/gccgoimporter/testdata/libimportsar.a new file mode 100644 index 0000000000000000000000000000000000000000..6f30758151dbc3ebbf037c54b55f4e84fb055277 GIT binary patch literal 9302 zcmb_iU5p!76~6ZDCeCiN%}*%_r7#HzB%wQN?|OIbZj^d=o5U4q8Aoy96D~k)& zpyfCVWf813UB_`Ut-!A~Dk2n)vm~nZrsqSc=+1Aq4WOlCP4S z{h4fkegnj@&g;iI|2Wq9^Rdofi=DTNomb%~b*=sCwf5C(?JLF3E5**QWT@hWU)sga z;pdB;Q!iYkZ4ggfX=kF|*5XCXT|D(dv11iGCsS`8C|)Avmx`U&x_P~MQyf~np-5y<86@??z|$%uuya4OoYzqc)j! zqjA%#)$D2`aQ#NPR-#cf6}YXS=2g103WyY{o?Z2#k=L?4oIjP5?=IKe#lTjwi?cO$}*gNHsG7t8p;NEO-(;1)c`y zz&E`20FKariBoSw?f3?)=yI-sO< zdYk=-=hv3#p3-Q8)~BvHHm2Y6aHFzF8S?wp?_HWoG5Vg}_84q2{C{)#k5BISKl4z0E2Giaq{Qd9|7eGlCflt4+bfOaq;S8qd# z3^wAH2L34FDOoq=WMXh|6woFMjU;*mh=leW!H_daJR=fY6MILt4_hO*jBHJ8+qeZ! zhUCq{8o7OVX85k{$ZmULcsPO1z~%_e4I}0rF+6+-b~r#cqD#6PVVGjWR95NdF?Yw# z}_$?qNqh5%Ur5rik@TH=S zoz4j~Q(1BJo>TTw&(1q(2c;~X$)%^#llDG$wdwjO!;PR^+ppeEA}{QX(-BAK=Wn<7 z!PWkEa3q(9UoR4mo)C%EEs0xh*qFMERosKw4@(VopdK38@|EQL<_&jUvYr~aFqnJ^ zifTSi(0&bwx39&`S?W$Q=d3=}$`V|4)>~M{apGA^$lHR4k+cN84EB;GaO4f5*PMig zb6p@cOKdi@g}@C0{Vu*<|HdBu4@v!AoD?mgTZg8*q<$CQ7s9fQddc4JhG2S(`zdcyx;L%G5|->sFMz+DZ5Bj4Mdg;q=8jk|;wX#9*P9N#0{(W<|KFh#aJ zA3jHVv2j5z;StZ7i5Qz~3^utQGk$7Z7X#OUpC9RW#}E#arC@2{G`zrd@K!(CYSya3 zX!x8^dhSBIf**mFJzTi#mlqa%_Z+(kA-~+HxL6N)rJ-7_+Hlzf!G*Kv)#)=sk0zf- zp^>{%TK3Czm{feP&3BgCsP`$Jz{c~vsk(&zHxxAsQAbA;ON`N_(vGa z_=bH-CAzBg>H6vY+>HNQU~%#7!O*Z6im0`tUf6jBA};=U75}o*r}*^ifEoWyU=-gx zKj&5aH0E@&^#S^?gX7kJi+U)qJ;kRzH{<^c7{xc~c@^KpP2KGPOpI*U{wIb5Q+EVF zT>b@>|I^BV@~2vF=KoR5n?5PzvU;F=l?ED_y5oK9-%|Fxe(b`u9|aJX|L@gLN^DR0 z)2}gR{zv-6zjb36@ktJ>q#1v{ zu#f#`RiFd!V85*F4K;Cr6E!9{F2j#0d*k*OPb&KYD=KNaJqP=^{j+1%Z!dhXJ+CX} zW5%XXSC!&6cdX-UlR#^soW#F)r8`%6Gpw`<%-EDZ{`RiW2?Wzf@h~ zzr(-N-{3Rp%#S5?6G+$OP9uisU=r?%!DFBgv;nY;h~yT?zAojyEw zdTrv)puOs6?{ymw=e$!*X>m>B6+*}#ydZV~e)Mkeppo^0bzC7<)>$Qg*%h{`ZYBCa|8 cYQ_$gl$o13rbnx}_T+!3QhbO88kzS01LaMjO#lD@ literal 0 HcmV?d00001 From e4a50ce97af2d9bb41d5f5af8561a17486274e1e Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Wed, 20 Jun 2018 11:35:20 +0530 Subject: [PATCH 123/203] cmd/go: remove inadvertent comment for vgo This change was introduced while adding the dark copy of golang.org/x/vgo in CL 118095. While the comment made sense in a separate vgo repo, when it is merged with the main repo, this should not remain. Found while running mkalldocs.sh in CL 119695. Change-Id: I112a4629c415032bd29e165ac1c27a0f3cabeede Reviewed-on: https://go-review.googlesource.com/119938 Reviewed-by: Brad Fitzpatrick --- src/cmd/go/internal/help/help.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go index 68b2c940d1..c79bf8bebb 100644 --- a/src/cmd/go/internal/help/help.go +++ b/src/cmd/go/internal/help/help.go @@ -64,10 +64,6 @@ func Help(args []string) { var usageTemplate = `Go is a tool for managing Go source code. -This is vgo, an experimental go command with support for package versioning. -Even though you are invoking it as vgo, most of the messages printed will -still say "go", not "vgo". Sorry. - Usage: go command [arguments] From f549af6f0a79479dddc70593291c31401b1f495a Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 19 Jun 2018 21:55:01 +0000 Subject: [PATCH 124/203] crypto/rand: make documentation consistent between package comment and Reader Updates #25959 Change-Id: I9ae64b216ab5807718db0db98b32de1dc5fa4bec Reviewed-on: https://go-review.googlesource.com/119875 Reviewed-by: Rob Pike Reviewed-by: Filippo Valsorda --- src/crypto/rand/rand.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go index e80ad368a2..b8df8a3711 100644 --- a/src/crypto/rand/rand.go +++ b/src/crypto/rand/rand.go @@ -3,13 +3,13 @@ // license that can be found in the LICENSE file. // Package rand implements a cryptographically secure -// pseudorandom number generator. +// random number generator. package rand import "io" // Reader is a global, shared instance of a cryptographically -// strong pseudo-random generator. +// secure random number generator. // // On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise. // On OpenBSD, Reader uses getentropy(2). From 578e0668627229ad0b9a3c88b61b3489cedb9074 Mon Sep 17 00:00:00 2001 From: LE Manh Cuong Date: Wed, 20 Jun 2018 11:22:37 +0700 Subject: [PATCH 125/203] make.bash: don't pass GOOS and GOARCH to cmd/go when finding GOROOT_BOOTSTRAP Fixes #25962 Change-Id: I10d41713f6aef100d7b2c8c976f22d1c8ac376d5 Reviewed-on: https://go-review.googlesource.com/119937 Reviewed-by: Brad Fitzpatrick --- src/make.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/make.bash b/src/make.bash index 4ea5a9a8b5..a28b82a058 100755 --- a/src/make.bash +++ b/src/make.bash @@ -141,7 +141,7 @@ export GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4} export GOROOT="$(cd .. && pwd)" IFS=$'\n'; for go_exe in $(type -ap go); do if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then - goroot=$(GOROOT='' "$go_exe" env GOROOT) + goroot=$(GOROOT='' GOOS='' GOARCH='' "$go_exe" env GOROOT) if [ "$goroot" != "$GOROOT" ]; then GOROOT_BOOTSTRAP=$goroot fi From 3ca5b7c5b21574da0b29ea1d2d53ffce8711d225 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 19 Jun 2018 20:43:24 -0700 Subject: [PATCH 126/203] internal/poll: better panic message for lock overflow Instead of "inconsistent poll.fdMutex", panic with "too many concurrent operations on a single file or socket (max 1048575)". Fixes #25558 Change-Id: I5cad3633aa539fb6f48cca236c6656c86acfb663 Reviewed-on: https://go-review.googlesource.com/119956 Run-TryBot: Ian Lance Taylor Run-TryBot: Dmitry Vyukov TryBot-Result: Gobot Gobot Reviewed-by: Dmitry Vyukov --- src/internal/poll/fd_mutex.go | 10 ++++++---- src/internal/poll/fd_mutex_test.go | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/internal/poll/fd_mutex.go b/src/internal/poll/fd_mutex.go index 2ba7de7da3..0a8ee6f0d4 100644 --- a/src/internal/poll/fd_mutex.go +++ b/src/internal/poll/fd_mutex.go @@ -34,6 +34,8 @@ const ( mutexWMask = (1<<20 - 1) << 43 ) +const overflowMsg = "too many concurrent operations on a single file or socket (max 1048575)" + // Read operations must do rwlock(true)/rwunlock(true). // // Write operations must do rwlock(false)/rwunlock(false). @@ -56,7 +58,7 @@ func (mu *fdMutex) incref() bool { } new := old + mutexRef if new&mutexRefMask == 0 { - panic("inconsistent poll.fdMutex") + panic(overflowMsg) } if atomic.CompareAndSwapUint64(&mu.state, old, new) { return true @@ -75,7 +77,7 @@ func (mu *fdMutex) increfAndClose() bool { // Mark as closed and acquire a reference. new := (old | mutexClosed) + mutexRef if new&mutexRefMask == 0 { - panic("inconsistent poll.fdMutex") + panic(overflowMsg) } // Remove all read and write waiters. new &^= mutexRMask | mutexWMask @@ -136,13 +138,13 @@ func (mu *fdMutex) rwlock(read bool) bool { // Lock is free, acquire it. new = (old | mutexBit) + mutexRef if new&mutexRefMask == 0 { - panic("inconsistent poll.fdMutex") + panic(overflowMsg) } } else { // Wait for lock. new = old + mutexWait if new&mutexMask == 0 { - panic("inconsistent poll.fdMutex") + panic(overflowMsg) } } if atomic.CompareAndSwapUint64(&mu.state, old, new) { diff --git a/src/internal/poll/fd_mutex_test.go b/src/internal/poll/fd_mutex_test.go index bab81c6dfe..2c53c4561f 100644 --- a/src/internal/poll/fd_mutex_test.go +++ b/src/internal/poll/fd_mutex_test.go @@ -8,6 +8,7 @@ import ( . "internal/poll" "math/rand" "runtime" + "strings" "testing" "time" ) @@ -121,6 +122,27 @@ func TestMutexPanic(t *testing.T) { mu.RWUnlock(false) } +func TestMutexOverflowPanic(t *testing.T) { + defer func() { + r := recover() + if r == nil { + t.Fatal("did not panic") + } + msg, ok := r.(string) + if !ok { + t.Fatalf("unexpected panic type %T", r) + } + if !strings.Contains(msg, "too many") || strings.Contains(msg, "inconsistent") { + t.Fatalf("wrong panic message %q", msg) + } + }() + + var mu1 FDMutex + for i := 0; i < 1<<21; i++ { + mu1.Incref() + } +} + func TestMutexStress(t *testing.T) { P := 8 N := int(1e6) From c89d75f981a64a3c87abb13d62cb44a0b55389e0 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 22 Nov 2017 18:25:20 +0000 Subject: [PATCH 127/203] crypto/tls: consolidate signatures handling in SKE and CV ServerKeyExchange and CertificateVerify can share the same logic for picking a signature algorithm (based on the certificate public key and advertised algorithms), selecting a hash algorithm (depending on TLS version) and signature verification. Refactor the code to achieve code reuse, have common error checking (especially for intersecting supported signature algorithms) and to prepare for addition of new signature algorithms. Code should be easier to read since version-dependent logic is concentrated at one place. Change-Id: I978dec3815d28e33c3cfbc85f0c704b1894c25a3 Reviewed-on: https://go-review.googlesource.com/79735 Reviewed-by: Filippo Valsorda Run-TryBot: Filippo Valsorda TryBot-Result: Gobot Gobot --- src/crypto/tls/auth.go | 99 +++++++++++++++++++++ src/crypto/tls/auth_test.go | 96 ++++++++++++++++++++ src/crypto/tls/handshake_client.go | 20 ++--- src/crypto/tls/handshake_server.go | 59 ++---------- src/crypto/tls/key_agreement.go | 138 +++++++---------------------- src/crypto/tls/prf.go | 31 ++----- 6 files changed, 245 insertions(+), 198 deletions(-) create mode 100644 src/crypto/tls/auth.go create mode 100644 src/crypto/tls/auth_test.go diff --git a/src/crypto/tls/auth.go b/src/crypto/tls/auth.go new file mode 100644 index 0000000000..57efe085a1 --- /dev/null +++ b/src/crypto/tls/auth.go @@ -0,0 +1,99 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "encoding/asn1" + "errors" + "fmt" +) + +// pickSignatureAlgorithm selects a signature algorithm that is compatible with +// the given public key and the list of algorithms from the peer and this side. +// The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored +// for tlsVersion < VersionTLS12. +// +// The returned SignatureScheme codepoint is only meaningful for TLS 1.2, +// previous TLS versions have a fixed hash function. +func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (sigAlg SignatureScheme, sigType uint8, hashFunc crypto.Hash, err error) { + if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 { + // For TLS 1.1 and before, the signature algorithm could not be + // negotiated and the hash is fixed based on the signature type. + // For TLS 1.2, if the client didn't send signature_algorithms + // extension then we can assume that it supports SHA1. See + // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + switch pubkey.(type) { + case *rsa.PublicKey: + if tlsVersion < VersionTLS12 { + return 0, signatureRSA, crypto.MD5SHA1, nil + } else { + return PKCS1WithSHA1, signatureRSA, crypto.SHA1, nil + } + case *ecdsa.PublicKey: + return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil + default: + return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey) + } + } + for _, sigAlg := range peerSigAlgs { + if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) { + continue + } + hashAlg, err := lookupTLSHash(sigAlg) + if err != nil { + panic("tls: supported signature algorithm has an unknown hash function") + } + sigType := signatureFromSignatureScheme(sigAlg) + switch pubkey.(type) { + case *rsa.PublicKey: + if sigType == signatureRSA { + return sigAlg, sigType, hashAlg, nil + } + case *ecdsa.PublicKey: + if sigType == signatureECDSA { + return sigAlg, sigType, hashAlg, nil + } + default: + return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey) + } + } + return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms") +} + +// verifyHandshakeSignature verifies a signature against pre-hashed handshake +// contents. +func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error { + switch sigType { + case signatureECDSA: + pubKey, ok := pubkey.(*ecdsa.PublicKey) + if !ok { + return errors.New("tls: ECDSA signing requires a ECDSA public key") + } + ecdsaSig := new(ecdsaSignature) + if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { + return err + } + if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { + return errors.New("tls: ECDSA signature contained zero or negative values") + } + if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { + return errors.New("tls: ECDSA verification failure") + } + case signatureRSA: + pubKey, ok := pubkey.(*rsa.PublicKey) + if !ok { + return errors.New("tls: RSA signing requires a RSA public key") + } + if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { + return err + } + default: + return errors.New("tls: unknown signature algorithm") + } + return nil +} diff --git a/src/crypto/tls/auth_test.go b/src/crypto/tls/auth_test.go new file mode 100644 index 0000000000..4258a822d6 --- /dev/null +++ b/src/crypto/tls/auth_test.go @@ -0,0 +1,96 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "crypto" + "testing" +) + +func TestSignatureSelection(t *testing.T) { + rsaCert := &testRSAPrivateKey.PublicKey + ecdsaCert := &testECDSAPrivateKey.PublicKey + sigsPKCS1WithSHA := []SignatureScheme{PKCS1WithSHA256, PKCS1WithSHA1} + sigsECDSAWithSHA := []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1} + + tests := []struct { + pubkey crypto.PublicKey + peerSigAlgs []SignatureScheme + ourSigAlgs []SignatureScheme + tlsVersion uint16 + + expectedSigAlg SignatureScheme // or 0 if ignored + expectedSigType uint8 + expectedHash crypto.Hash + }{ + // Hash is fixed for RSA in TLS 1.1 and before. + // https://tools.ietf.org/html/rfc4346#page-44 + {rsaCert, nil, nil, VersionTLS11, 0, signatureRSA, crypto.MD5SHA1}, + {rsaCert, nil, nil, VersionTLS10, 0, signatureRSA, crypto.MD5SHA1}, + {rsaCert, nil, nil, VersionSSL30, 0, signatureRSA, crypto.MD5SHA1}, + + // Before TLS 1.2, there is no signature_algorithms extension + // nor field in CertificateRequest and digitally-signed and thus + // it should be ignored. + {rsaCert, sigsPKCS1WithSHA, nil, VersionTLS11, 0, signatureRSA, crypto.MD5SHA1}, + {rsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS11, 0, signatureRSA, crypto.MD5SHA1}, + // Use SHA-1 for TLS 1.0 and 1.1 with ECDSA, see https://tools.ietf.org/html/rfc4492#page-20 + {ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS11, 0, signatureECDSA, crypto.SHA1}, + {ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS10, 0, signatureECDSA, crypto.SHA1}, + + // TLS 1.2 without signature_algorithms extension + // https://tools.ietf.org/html/rfc5246#page-47 + {rsaCert, nil, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA1, signatureRSA, crypto.SHA1}, + {ecdsaCert, nil, sigsPKCS1WithSHA, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1}, + + {rsaCert, []SignatureScheme{PKCS1WithSHA1}, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA1, signatureRSA, crypto.SHA1}, + {rsaCert, []SignatureScheme{PKCS1WithSHA256}, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA256, signatureRSA, crypto.SHA256}, + // "sha_hash" may denote hashes other than SHA-1 + // https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis-17#page-17 + {ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, sigsECDSAWithSHA, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1}, + {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, sigsECDSAWithSHA, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256}, + } + + for testNo, test := range tests { + sigAlg, sigType, hashFunc, err := pickSignatureAlgorithm(test.pubkey, test.peerSigAlgs, test.ourSigAlgs, test.tlsVersion) + if err != nil { + t.Errorf("test[%d]: unexpected error: %v", testNo, err) + } + if test.expectedSigAlg != 0 && test.expectedSigAlg != sigAlg { + t.Errorf("test[%d]: expected signature scheme %#x, got %#x", testNo, test.expectedSigAlg, sigAlg) + } + if test.expectedSigType != sigType { + t.Errorf("test[%d]: expected signature algorithm %#x, got %#x", testNo, test.expectedSigType, sigType) + } + if test.expectedHash != hashFunc { + t.Errorf("test[%d]: expected hash function %#x, got %#x", testNo, test.expectedHash, hashFunc) + } + } + + badTests := []struct { + pubkey crypto.PublicKey + peerSigAlgs []SignatureScheme + ourSigAlgs []SignatureScheme + tlsVersion uint16 + }{ + {rsaCert, sigsECDSAWithSHA, sigsPKCS1WithSHA, VersionTLS12}, + {ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS12}, + {ecdsaCert, sigsECDSAWithSHA, sigsPKCS1WithSHA, VersionTLS12}, + {rsaCert, []SignatureScheme{0}, sigsPKCS1WithSHA, VersionTLS12}, + + // ECDSA is unspecified for SSL 3.0 in RFC 4492. + // TODO a SSL 3.0 client cannot advertise signature_algorithms, + // but if an application feeds an ECDSA certificate anyway, it + // will be accepted rather than trigger a handshake failure. Ok? + //{ecdsaCert, nil, nil, VersionSSL30}, + } + + for testNo, test := range badTests { + sigAlg, sigType, hashFunc, err := pickSignatureAlgorithm(test.pubkey, test.peerSigAlgs, test.ourSigAlgs, test.tlsVersion) + if err == nil { + t.Errorf("test[%d]: unexpected success, got %#x %#x %#x", testNo, sigAlg, sigType, hashFunc) + } + } +} diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index fd6df4251c..634f967cd0 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -479,26 +479,16 @@ func (hs *clientHandshakeState) doFullHandshake() error { return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) } - var signatureType uint8 - switch key.Public().(type) { - case *ecdsa.PublicKey: - signatureType = signatureECDSA - case *rsa.PublicKey: - signatureType = signatureRSA - default: + signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers) + if err != nil { c.sendAlert(alertInternalError) - return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key) + return err } - // SignatureAndHashAlgorithm was introduced in TLS 1.2. if certVerify.hasSignatureAndHash { - certVerify.signatureAlgorithm, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.supportedSignatureAlgorithms, signatureType) - if err != nil { - c.sendAlert(alertInternalError) - return err - } + certVerify.signatureAlgorithm = signatureAlgorithm } - digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(signatureType, certVerify.signatureAlgorithm, hs.masterSecret) + digest, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret) if err != nil { c.sendAlert(alertInternalError) return err diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index f8dd630a04..0d685927b3 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -10,7 +10,6 @@ import ( "crypto/rsa" "crypto/subtle" "crypto/x509" - "encoding/asn1" "errors" "fmt" "io" @@ -520,59 +519,15 @@ func (hs *serverHandshakeState) doFullHandshake() error { } // Determine the signature type. - var signatureAlgorithm SignatureScheme - var sigType uint8 - if certVerify.hasSignatureAndHash { - signatureAlgorithm = certVerify.signatureAlgorithm - if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms) { - return errors.New("tls: unsupported hash function for client certificate") - } - sigType = signatureFromSignatureScheme(signatureAlgorithm) - } else { - // Before TLS 1.2 the signature algorithm was implicit - // from the key type, and only one hash per signature - // algorithm was possible. Leave signatureAlgorithm - // unset. - switch pub.(type) { - case *ecdsa.PublicKey: - sigType = signatureECDSA - case *rsa.PublicKey: - sigType = signatureRSA - } + _, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, supportedSignatureAlgorithms, c.vers) + if err != nil { + c.sendAlert(alertIllegalParameter) + return err } - switch key := pub.(type) { - case *ecdsa.PublicKey: - if sigType != signatureECDSA { - err = errors.New("tls: bad signature type for client's ECDSA certificate") - break - } - ecdsaSig := new(ecdsaSignature) - if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil { - break - } - if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { - err = errors.New("tls: ECDSA signature contained zero or negative values") - break - } - var digest []byte - if digest, _, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil { - break - } - if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) { - err = errors.New("tls: ECDSA verification failure") - } - case *rsa.PublicKey: - if sigType != signatureRSA { - err = errors.New("tls: bad signature type for client's RSA certificate") - break - } - var digest []byte - var hashFunc crypto.Hash - if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil { - break - } - err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature) + var digest []byte + if digest, err = hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret); err == nil { + err = verifyHandshakeSignature(sigType, pub, hashFunc, digest, certVerify.signature) } if err != nil { c.sendAlert(alertBadCertificate) diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go index 6685b47584..7dc54d5faa 100644 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@ -6,13 +6,11 @@ package tls import ( "crypto" - "crypto/ecdsa" "crypto/elliptic" "crypto/md5" "crypto/rsa" "crypto/sha1" "crypto/x509" - "encoding/asn1" "errors" "io" "math/big" @@ -110,58 +108,21 @@ func md5SHA1Hash(slices [][]byte) []byte { } // hashForServerKeyExchange hashes the given slices and returns their digest -// and the identifier of the hash function used. The signatureAlgorithm argument -// is only used for >= TLS 1.2 and identifies the hash function to use. -func hashForServerKeyExchange(sigType uint8, signatureAlgorithm SignatureScheme, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { +// using the given hash function (for >= TLS 1.2) or using a default based on +// the sigType (for earlier TLS versions). +func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) ([]byte, error) { if version >= VersionTLS12 { - if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms) { - return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer") - } - hashFunc, err := lookupTLSHash(signatureAlgorithm) - if err != nil { - return nil, crypto.Hash(0), err - } h := hashFunc.New() for _, slice := range slices { h.Write(slice) } digest := h.Sum(nil) - return digest, hashFunc, nil + return digest, nil } if sigType == signatureECDSA { - return sha1Hash(slices), crypto.SHA1, nil + return sha1Hash(slices), nil } - return md5SHA1Hash(slices), crypto.MD5SHA1, nil -} - -// pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a -// ServerKeyExchange given the signature type being used and the client's -// advertised list of supported signature and hash combinations. -func pickTLS12HashForSignature(sigType uint8, clientList []SignatureScheme) (SignatureScheme, error) { - if len(clientList) == 0 { - // If the client didn't specify any signature_algorithms - // extension then we can assume that it supports SHA1. See - // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 - switch sigType { - case signatureRSA: - return PKCS1WithSHA1, nil - case signatureECDSA: - return ECDSAWithSHA1, nil - default: - return 0, errors.New("tls: unknown signature algorithm") - } - } - - for _, sigAlg := range clientList { - if signatureFromSignatureScheme(sigAlg) != sigType { - continue - } - if isSupportedSignatureAlgorithm(sigAlg, supportedSignatureAlgorithms) { - return sigAlg, nil - } - } - - return 0, errors.New("tls: client doesn't support any common hash functions") + return md5SHA1Hash(slices), nil } func curveForCurveID(id CurveID) (elliptic.Curve, bool) { @@ -247,41 +208,25 @@ NextCandidate: serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) - var signatureAlgorithm SignatureScheme - - if ka.version >= VersionTLS12 { - var err error - signatureAlgorithm, err = pickTLS12HashForSignature(ka.sigType, clientHello.supportedSignatureAlgorithms) - if err != nil { - return nil, err - } - } - - digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, hello.random, serverECDHParams) - if err != nil { - return nil, err - } - priv, ok := cert.PrivateKey.(crypto.Signer) if !ok { return nil, errors.New("tls: certificate private key does not implement crypto.Signer") } - var sig []byte - switch ka.sigType { - case signatureECDSA: - _, ok := priv.Public().(*ecdsa.PublicKey) - if !ok { - return nil, errors.New("tls: ECDHE ECDSA requires an ECDSA server key") - } - case signatureRSA: - _, ok := priv.Public().(*rsa.PublicKey) - if !ok { - return nil, errors.New("tls: ECDHE RSA requires a RSA server key") - } - default: - return nil, errors.New("tls: unknown ECDHE signature algorithm") + + signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithms, ka.version) + if err != nil { + return nil, err } - sig, err = priv.Sign(config.rand(), digest, hashFunc) + if sigType != ka.sigType { + return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") + } + + digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, hello.random, serverECDHParams) + if err != nil { + return nil, err + } + + sig, err := priv.Sign(config.rand(), digest, hashFunc) if err != nil { return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) } @@ -380,53 +325,30 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell if ka.version >= VersionTLS12 { // handle SignatureAndHashAlgorithm signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) - if signatureFromSignatureScheme(signatureAlgorithm) != ka.sigType { - return errServerKeyExchange - } sig = sig[2:] if len(sig) < 2 { return errServerKeyExchange } } + _, sigType, hashFunc, err := pickSignatureAlgorithm(cert.PublicKey, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version) + if err != nil { + return err + } + if sigType != ka.sigType { + return errServerKeyExchange + } + sigLen := int(sig[0])<<8 | int(sig[1]) if sigLen+2 != len(sig) { return errServerKeyExchange } sig = sig[2:] - digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, serverHello.random, serverECDHParams) + digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, serverHello.random, serverECDHParams) if err != nil { return err } - switch ka.sigType { - case signatureECDSA: - pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) - if !ok { - return errors.New("tls: ECDHE ECDSA requires a ECDSA server public key") - } - ecdsaSig := new(ecdsaSignature) - if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil { - return err - } - if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { - return errors.New("tls: ECDSA signature contained zero or negative values") - } - if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { - return errors.New("tls: ECDSA verification failure") - } - case signatureRSA: - pubKey, ok := cert.PublicKey.(*rsa.PublicKey) - if !ok { - return errors.New("tls: ECDHE RSA requires a RSA server public key") - } - if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { - return err - } - default: - return errors.New("tls: unknown ECDHE signature algorithm") - } - - return nil + return verifyHandshakeSignature(sigType, cert.PublicKey, hashFunc, digest, sig) } func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go index 367e0842b0..1d883260de 100644 --- a/src/crypto/tls/prf.go +++ b/src/crypto/tls/prf.go @@ -309,50 +309,35 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { return out } -// selectClientCertSignatureAlgorithm returns a SignatureScheme to sign a -// client's CertificateVerify with, or an error if none can be found. -func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []SignatureScheme, sigType uint8) (SignatureScheme, error) { - for _, v := range serverList { - if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms) { - return v, nil - } - } - return 0, errors.New("tls: no supported signature algorithm found for signing client certificate") -} - -// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash -// id suitable for signing by a TLS client certificate. -func (h finishedHash) hashForClientCertificate(sigType uint8, signatureAlgorithm SignatureScheme, masterSecret []byte) ([]byte, crypto.Hash, error) { +// hashForClientCertificate returns a digest over the handshake messages so far, +// suitable for signing by a TLS client certificate. +func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) { if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil { panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer") } if h.version == VersionSSL30 { if sigType != signatureRSA { - return nil, 0, errors.New("tls: unsupported signature type for client certificate") + return nil, errors.New("tls: unsupported signature type for client certificate") } md5Hash := md5.New() md5Hash.Write(h.buffer) sha1Hash := sha1.New() sha1Hash.Write(h.buffer) - return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil + return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), nil } if h.version >= VersionTLS12 { - hashAlg, err := lookupTLSHash(signatureAlgorithm) - if err != nil { - return nil, 0, err - } hash := hashAlg.New() hash.Write(h.buffer) - return hash.Sum(nil), hashAlg, nil + return hash.Sum(nil), nil } if sigType == signatureECDSA { - return h.server.Sum(nil), crypto.SHA1, nil + return h.server.Sum(nil), nil } - return h.Sum(), crypto.MD5SHA1, nil + return h.Sum(), nil } // discardHandshakeBuffer is called when there is no more need to From dd0e7a95344a3ef959d9373235d250876c9a4475 Mon Sep 17 00:00:00 2001 From: Wayne Ashley Berry Date: Thu, 7 Jun 2018 20:54:08 +0100 Subject: [PATCH 128/203] doc: change git clone url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The git clone url should be a Gerrit host and not Github, otherwise the codereview command will fail. git-codereview: failed to load Gerrit origin: git origin must be a Gerrit host, not GitHub: https://github.com/golang/go Change-Id: I62f62c86ee6dce0720a844fc56340135dfae8405 Reviewed-on: https://go-review.googlesource.com/117178 Reviewed-by: Daniel Martí Reviewed-by: Brad Fitzpatrick --- doc/contribute.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/contribute.html b/doc/contribute.html index e7970537dd..7ed5e3779a 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -384,10 +384,10 @@ This is an overview of the overall process:
    • -Step 1: Clone the Go source code from GitHub or go.googlesource.com +Step 1: Clone the Go source code from go.googlesource.com and make sure it's stable by compiling and testing it once:
      -$ git clone https://github.com/golang/go    # or https://go.googlesource.com/go
      +$ git clone https://go.googlesource.com/go
       $ cd go/src
       $ ./all.bash                                # compile and test
       
      From ee9c9392b81023e29564d3fe308a15aca7d416ef Mon Sep 17 00:00:00 2001 From: Stephen Lewis Date: Wed, 20 Jun 2018 19:38:19 +0100 Subject: [PATCH 129/203] doc: fix spelling of G Suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'G Suite' seems to be the preferred spelling according to https://gsuite.google.com/ Change-Id: Ica60938cf942594157bba84ef205e1cdcb8c1b08 Reviewed-on: https://go-review.googlesource.com/120132 Reviewed-by: Daniel Martí --- doc/contribute.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/contribute.html b/doc/contribute.html index 7ed5e3779a..c5339613a8 100644 --- a/doc/contribute.html +++ b/doc/contribute.html @@ -92,10 +92,10 @@ account to use.

      -Google accounts can either be Gmail e-mail accounts, G-Suite organization accounts, or +Google accounts can either be Gmail e-mail accounts, G Suite organization accounts, or accounts associated with an external e-mail address. For instance, if you need to use -an existing corporate e-mail that is not managed through G-Suite, you can create +an existing corporate e-mail that is not managed through G Suite, you can create an account associated with your existing e-mail address. From f3f7bd5558d6c4aa2a7f62bb3c9e6d364fc43be9 Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Tue, 19 Jun 2018 20:27:08 +0530 Subject: [PATCH 130/203] cmd/go/internal: add a note about GOCACHE=off Fixes #25928 Change-Id: I1401ecc54af26eeeee648bb8eeb5d2d3566fa60c Reviewed-on: https://go-review.googlesource.com/119695 Reviewed-by: Ian Lance Taylor --- src/cmd/go/alldocs.go | 1 + src/cmd/go/internal/help/helpdoc.go | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index e7fbca2541..fd281460b1 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1012,6 +1012,7 @@ // in the standard user cache directory for the current operating system. // Setting the GOCACHE environment variable overrides this default, // and running 'go env GOCACHE' prints the current cache directory. +// You can set the variable to 'off' to disable the cache. // // The go command periodically deletes cached data that has not been // used recently. Running 'go clean -cache' deletes all cached data. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index a90d19e976..ce19796558 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -658,6 +658,7 @@ The default location for cache data is a subdirectory named go-build in the standard user cache directory for the current operating system. Setting the GOCACHE environment variable overrides this default, and running 'go env GOCACHE' prints the current cache directory. +You can set the variable to 'off' to disable the cache. The go command periodically deletes cached data that has not been used recently. Running 'go clean -cache' deletes all cached data. From feeff23556bc82778aab0ed80b576b953f064024 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 20 Jun 2018 18:25:54 +0000 Subject: [PATCH 131/203] mime: change *.js mime type to application/javascript, not x-javascript We delayed doing this for 4 years for fear that it might break something, but it was standardized (RFC 4329) 12 years ago, and the default in Debian and other places is correct: $ cat /etc/mime.types | grep js$ application/javascript js Time for us to change too. I doubt there will be problems, but we'll see during the Go 1.11 beta. Fixes #7498 Change-Id: Iba0bf8a6e707a64dd63317e1c0d6dd9a18634527 Reviewed-on: https://go-review.googlesource.com/120058 Reviewed-by: Andrew Bonventre Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/mime/type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mime/type.go b/src/mime/type.go index 53bf41e2e4..64e26ffb7c 100644 --- a/src/mime/type.go +++ b/src/mime/type.go @@ -62,7 +62,7 @@ var builtinTypesLower = map[string]string{ ".htm": "text/html; charset=utf-8", ".html": "text/html; charset=utf-8", ".jpg": "image/jpeg", - ".js": "application/x-javascript", + ".js": "application/javascript", ".wasm": "application/wasm", ".pdf": "application/pdf", ".png": "image/png", From 85e38cccb4d113862f4fd2c3c4d97927cd84420c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 20 Jun 2018 15:41:37 +0200 Subject: [PATCH 132/203] syscall: check faccessat flags parameter on Linux Port CL 119495 from golang.org/x/sys/unix to the syscall package. Currently Linux faccessat(2) syscall implementation doesn't support the flags parameter. As per the discussion in #25845, permit the same flags as glibc [1]. [1] https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;h=ea42b2303ff4b2d2d6548ea04376fb265f773436;hb=HEAD Updates #25845 Change-Id: I132b33275a9cc72b3a97acea5482806c7f47d7f7 Reviewed-on: https://go-review.googlesource.com/120015 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/syscall/syscall_linux.go | 12 +++++++++- src/syscall/syscall_linux_test.go | 31 ++++++++++++++++++++++++++ src/syscall/types_linux.go | 1 + src/syscall/zsyscall_linux_386.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_amd64.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_arm.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_arm64.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_mips.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_mips64.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_mips64le.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_mipsle.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_ppc64.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_ppc64le.go | 30 ++++++++++++------------- src/syscall/zsyscall_linux_s390x.go | 30 ++++++++++++------------- src/syscall/ztypes_linux_386.go | 1 + src/syscall/ztypes_linux_amd64.go | 1 + src/syscall/ztypes_linux_arm.go | 1 + src/syscall/ztypes_linux_arm64.go | 1 + src/syscall/ztypes_linux_mips.go | 1 + src/syscall/ztypes_linux_mips64.go | 1 + src/syscall/ztypes_linux_mips64le.go | 1 + src/syscall/ztypes_linux_mipsle.go | 1 + src/syscall/ztypes_linux_ppc64.go | 1 + src/syscall/ztypes_linux_ppc64le.go | 1 + src/syscall/ztypes_linux_s390x.go | 1 + 25 files changed, 219 insertions(+), 166 deletions(-) diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 8d0532e216..1a304c4966 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -35,6 +35,17 @@ func Creat(path string, mode uint32) (fd int, err error) { return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) } +//sys faccessat(dirfd int, path string, mode uint32) (err error) + +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + if flags & ^(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 { + return EINVAL + } else if flags&(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 { + return EOPNOTSUPP + } + return faccessat(dirfd, path, mode) +} + //sys fchmodat(dirfd int, path string, mode uint32) (err error) func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { @@ -840,7 +851,6 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri //sysnb EpollCreate(size int) (fd int, err error) //sysnb EpollCreate1(flag int) (fd int, err error) //sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) -//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fallocate(fd int, mode uint32, off int64, len int64) (err error) //sys Fchdir(fd int) (err error) //sys Fchmod(fd int, mode uint32) (err error) diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go index 4490fc24ca..24158bb8b8 100644 --- a/src/syscall/syscall_linux_test.go +++ b/src/syscall/syscall_linux_test.go @@ -56,8 +56,39 @@ func touch(t *testing.T, name string) { const ( _AT_SYMLINK_NOFOLLOW = 0x100 _AT_FDCWD = -0x64 + _AT_EACCESS = 0x200 ) +func TestFaccessat(t *testing.T) { + defer chtmpdir(t)() + touch(t, "file1") + + err := syscall.Faccessat(_AT_FDCWD, "file1", syscall.O_RDONLY, 0) + if err != nil { + t.Errorf("Faccessat: unexpected error: %v", err) + } + + err = syscall.Faccessat(_AT_FDCWD, "file1", syscall.O_RDONLY, 2) + if err != syscall.EINVAL { + t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err) + } + + err = syscall.Faccessat(_AT_FDCWD, "file1", syscall.O_RDONLY, _AT_EACCESS) + if err != syscall.EOPNOTSUPP { + t.Errorf("Faccessat: unexpected error: %v, want EOPNOTSUPP", err) + } + + err = os.Symlink("file1", "symlink1") + if err != nil { + t.Fatal(err) + } + + err = syscall.Faccessat(_AT_FDCWD, "symlink1", syscall.O_RDONLY, _AT_SYMLINK_NOFOLLOW) + if err != syscall.EOPNOTSUPP { + t.Errorf("Faccessat: unexpected error: %v, want EOPNOTSUPP", err) + } +} + func TestFchmodat(t *testing.T) { defer chtmpdir(t)() diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go index 125f69d60e..3c4c2f2cfd 100644 --- a/src/syscall/types_linux.go +++ b/src/syscall/types_linux.go @@ -405,6 +405,7 @@ const ( _AT_FDCWD = C.AT_FDCWD _AT_REMOVEDIR = C.AT_REMOVEDIR _AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW + _AT_EACCESS = C.AT_EACCESS ) // Terminal handling diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go index 2877be60e7..ef79b3e3e2 100644 --- a/src/syscall/zsyscall_linux_386.go +++ b/src/syscall/zsyscall_linux_386.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go index 59d376a45c..b6638269be 100644 --- a/src/syscall/zsyscall_linux_amd64.go +++ b/src/syscall/zsyscall_linux_amd64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go index 4baf713e61..216924ff20 100644 --- a/src/syscall/zsyscall_linux_arm.go +++ b/src/syscall/zsyscall_linux_arm.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go index 4c79cffa9f..f2dffa4bac 100644 --- a/src/syscall/zsyscall_linux_arm64.go +++ b/src/syscall/zsyscall_linux_arm64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go index 787b5d7b7e..72eabac8ec 100644 --- a/src/syscall/zsyscall_linux_mips.go +++ b/src/syscall/zsyscall_linux_mips.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len)) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go index 63cae60d47..4180ed1908 100644 --- a/src/syscall/zsyscall_linux_mips64.go +++ b/src/syscall/zsyscall_linux_mips64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go index e2cf9b8910..3b4b5da539 100644 --- a/src/syscall/zsyscall_linux_mips64le.go +++ b/src/syscall/zsyscall_linux_mips64le.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go index be5294cd1c..7114093a11 100644 --- a/src/syscall/zsyscall_linux_mipsle.go +++ b/src/syscall/zsyscall_linux_mipsle.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go index 2f6db68c47..b76944e96c 100644 --- a/src/syscall/zsyscall_linux_ppc64.go +++ b/src/syscall/zsyscall_linux_ppc64.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go index 44d5c5c87a..613793b0bf 100644 --- a/src/syscall/zsyscall_linux_ppc64le.go +++ b/src/syscall/zsyscall_linux_ppc64le.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go index ebad9f3080..7c63c3db58 100644 --- a/src/syscall/zsyscall_linux_s390x.go +++ b/src/syscall/zsyscall_linux_s390x.go @@ -9,6 +9,21 @@ import "unsafe" // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func fchmodat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -354,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go index a73c91770f..c92dfad114 100644 --- a/src/syscall/ztypes_linux_386.go +++ b/src/syscall/ztypes_linux_386.go @@ -576,6 +576,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go index 4cbd5d899d..623585a639 100644 --- a/src/syscall/ztypes_linux_amd64.go +++ b/src/syscall/ztypes_linux_amd64.go @@ -594,6 +594,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go index 16aa014ada..0c0a94a52f 100644 --- a/src/syscall/ztypes_linux_arm.go +++ b/src/syscall/ztypes_linux_arm.go @@ -565,6 +565,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go index e5d669cdba..ea682c4efa 100644 --- a/src/syscall/ztypes_linux_arm64.go +++ b/src/syscall/ztypes_linux_arm64.go @@ -572,6 +572,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_mips.go b/src/syscall/ztypes_linux_mips.go index 7a8d34dfc2..6d42e48d60 100644 --- a/src/syscall/ztypes_linux_mips.go +++ b/src/syscall/ztypes_linux_mips.go @@ -571,6 +571,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_mips64.go b/src/syscall/ztypes_linux_mips64.go index 8c5a0d1d76..397ded1f4d 100644 --- a/src/syscall/ztypes_linux_mips64.go +++ b/src/syscall/ztypes_linux_mips64.go @@ -577,6 +577,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_mips64le.go b/src/syscall/ztypes_linux_mips64le.go index 8c5a0d1d76..397ded1f4d 100644 --- a/src/syscall/ztypes_linux_mips64le.go +++ b/src/syscall/ztypes_linux_mips64le.go @@ -577,6 +577,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_mipsle.go b/src/syscall/ztypes_linux_mipsle.go index 7a8d34dfc2..6d42e48d60 100644 --- a/src/syscall/ztypes_linux_mipsle.go +++ b/src/syscall/ztypes_linux_mipsle.go @@ -571,6 +571,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go index 087a70d443..3d295390f6 100644 --- a/src/syscall/ztypes_linux_ppc64.go +++ b/src/syscall/ztypes_linux_ppc64.go @@ -583,6 +583,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go index 8412bddbfa..220083d9c5 100644 --- a/src/syscall/ztypes_linux_ppc64le.go +++ b/src/syscall/ztypes_linux_ppc64le.go @@ -583,6 +583,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go index 63c4a83b19..2805966774 100644 --- a/src/syscall/ztypes_linux_s390x.go +++ b/src/syscall/ztypes_linux_s390x.go @@ -597,6 +597,7 @@ const ( _AT_FDCWD = -0x64 _AT_REMOVEDIR = 0x200 _AT_SYMLINK_NOFOLLOW = 0x100 + _AT_EACCESS = 0x200 ) type Termios struct { From 1988b3ed0ed72995f566630558e5bb0531aeac60 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Mon, 21 May 2018 12:57:53 -0700 Subject: [PATCH 133/203] net/http: avoid deferred unlock in ServeMux.shouldRedirect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CL 96575 introduced concurrency protection for ServeMux.shouldRedirect with a read lock and deferred unlock. However, the change produced a noticeable regression. Instead add the suffix "RLocked" to the function name to declare that we should hold the read lock as a pre-requisite before calling it, hence avoiding the defer altogether. Benchmarks: name old time/op new time/op delta ServeMux-8 63.3µs ± 0% 54.6µs ± 0% -13.74% (p=0.000 n=9+9) ServeMux_SkipServe-8 41.4µs ± 2% 32.7µs ± 1% -21.05% (p=0.000 n=10+10) name old alloc/op new alloc/op delta ServeMux-8 17.3kB ± 0% 17.3kB ± 0% ~ (all equal) ServeMux_SkipServe-8 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta ServeMux-8 360 ± 0% 360 ± 0% ~ (all equal) ServeMux_SkipServe-8 0.00 0.00 ~ (all equal) Updates #25383 Updates #25482 Change-Id: I2ffa4eafe165faa961ce23bd29b5653a89facbc2 Reviewed-on: https://go-review.googlesource.com/113996 Run-TryBot: Emmanuel Odeke TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/http/server.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/net/http/server.go b/src/net/http/server.go index e8903c5346..c244b372fc 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -2236,7 +2236,10 @@ func (mux *ServeMux) match(path string) (h Handler, pattern string) { // not for path itself. If the path needs appending to, it creates a new // URL, setting the path to u.Path + "/" and returning true to indicate so. func (mux *ServeMux) redirectToPathSlash(host, path string, u *url.URL) (*url.URL, bool) { - if !mux.shouldRedirect(host, path) { + mux.mu.RLock() + shouldRedirect := mux.shouldRedirectRLocked(host, path) + mux.mu.RUnlock() + if !shouldRedirect { return u, false } path = path + "/" @@ -2244,13 +2247,10 @@ func (mux *ServeMux) redirectToPathSlash(host, path string, u *url.URL) (*url.UR return u, true } -// shouldRedirect reports whether the given path and host should be redirected to +// shouldRedirectRLocked reports whether the given path and host should be redirected to // path+"/". This should happen if a handler is registered for path+"/" but // not path -- see comments at ServeMux. -func (mux *ServeMux) shouldRedirect(host, path string) bool { - mux.mu.RLock() - defer mux.mu.RUnlock() - +func (mux *ServeMux) shouldRedirectRLocked(host, path string) bool { p := []string{path, host + path} for _, c := range p { From 0a7ac93c27c9ade79fe0f66ae0bb81484c241ae5 Mon Sep 17 00:00:00 2001 From: Wei Xiao Date: Fri, 3 Nov 2017 02:05:28 +0000 Subject: [PATCH 134/203] cmd/compile: improve atomic add intrinsics with ARMv8.1 new instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARMv8.1 has added new instruction (LDADDAL) for atomic memory operations. This CL improves existing atomic add intrinsics with the new instruction. Since the new instruction is only guaranteed to be present after ARMv8.1, we guard its usage with a conditional on CPU feature. Performance result on ARMv8.1 machine: name old time/op new time/op delta Xadd-224 1.05µs ± 6% 0.02µs ± 4% -98.06% (p=0.000 n=10+8) Xadd64-224 1.05µs ± 3% 0.02µs ±13% -98.10% (p=0.000 n=9+10) [Geo mean] 1.05µs 0.02µs -98.08% Performance result on ARMv8.0 machine: name old time/op new time/op delta Xadd-46 538ns ± 1% 541ns ± 1% +0.62% (p=0.000 n=9+9) Xadd64-46 505ns ± 1% 508ns ± 0% +0.48% (p=0.003 n=9+8) [Geo mean] 521ns 524ns +0.55% Change-Id: If4b5d8d0e2d6f84fe1492a4f5de0789910ad0ee9 Reviewed-on: https://go-review.googlesource.com/81877 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/cmd/asm/internal/arch/arm64.go | 3 +- src/cmd/asm/internal/asm/testdata/arm64.s | 2 + src/cmd/compile/internal/arm64/ssa.go | 22 +++++++++ src/cmd/compile/internal/gc/go.go | 1 + src/cmd/compile/internal/gc/ssa.go | 47 +++++++++++++++++- src/cmd/compile/internal/ssa/gen/ARM64.rules | 3 ++ src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 7 +++ .../compile/internal/ssa/gen/genericOps.go | 7 +++ src/cmd/compile/internal/ssa/opGen.go | 48 +++++++++++++++++++ src/cmd/compile/internal/ssa/rewriteARM64.go | 36 ++++++++++++++ src/cmd/internal/obj/arm64/a.out.go | 2 + src/cmd/internal/obj/arm64/anames.go | 2 + src/cmd/internal/obj/arm64/asm7.go | 12 +++-- src/runtime/internal/atomic/bench_test.go | 20 ++++++++ src/runtime/proc.go | 2 + src/runtime/runtime2.go | 3 ++ 16 files changed, 211 insertions(+), 6 deletions(-) diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index e7ef928fa2..475d7da5f9 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -77,7 +77,8 @@ func IsARM64STLXR(op obj.As) bool { arm64.ALDADDB, arm64.ALDADDH, arm64.ALDADDW, arm64.ALDADDD, arm64.ALDANDB, arm64.ALDANDH, arm64.ALDANDW, arm64.ALDANDD, arm64.ALDEORB, arm64.ALDEORH, arm64.ALDEORW, arm64.ALDEORD, - arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD: + arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD, + arm64.ALDADDALD, arm64.ALDADDALW: return true } return false diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 54be761c54..859f71a26b 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -604,6 +604,8 @@ again: LDORH R5, (RSP), R7 // e7332578 LDORB R5, (R6), R7 // c7302538 LDORB R5, (RSP), R7 // e7332538 + LDADDALD R2, (R1), R3 // 2300e2f8 + LDADDALW R5, (R4), R6 // 8600e5b8 // RET // diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 501eafe03f..c396ba06d1 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -553,6 +553,28 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p3.From.Reg = arm64.REGTMP p3.To.Type = obj.TYPE_BRANCH gc.Patch(p3, p) + case ssa.OpARM64LoweredAtomicAdd64Variant, + ssa.OpARM64LoweredAtomicAdd32Variant: + // LDADDAL Rarg1, (Rarg0), Rout + // ADD Rarg1, Rout + op := arm64.ALDADDALD + if v.Op == ssa.OpARM64LoweredAtomicAdd32Variant { + op = arm64.ALDADDALW + } + r0 := v.Args[0].Reg() + r1 := v.Args[1].Reg() + out := v.Reg0() + p := s.Prog(op) + p.From.Type = obj.TYPE_REG + p.From.Reg = r1 + p.To.Type = obj.TYPE_MEM + p.To.Reg = r0 + p.RegTo2 = out + p1 := s.Prog(arm64.AADD) + p1.From.Type = obj.TYPE_REG + p1.From.Reg = r1 + p1.To.Type = obj.TYPE_REG + p1.To.Reg = out case ssa.OpARM64LoweredAtomicCas64, ssa.OpARM64LoweredAtomicCas32: // LDAXR (Rarg0), Rtmp diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index a471a909d6..95bf562e2c 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -303,6 +303,7 @@ var ( racewriterange, supportPopcnt, supportSSE41, + arm64SupportAtomics, typedmemclr, typedmemmove, Udiv, diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 3c15c8e555..92bfa7de4f 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -78,6 +78,7 @@ func initssaconfig() { racewriterange = sysfunc("racewriterange") supportPopcnt = sysfunc("support_popcnt") supportSSE41 = sysfunc("support_sse41") + arm64SupportAtomics = sysfunc("arm64_support_atomics") typedmemclr = sysfunc("typedmemclr") typedmemmove = sysfunc("typedmemmove") Udiv = sysfunc("udiv") @@ -2935,14 +2936,56 @@ func init() { s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v) }, - sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) + sys.AMD64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) addF("runtime/internal/atomic", "Xadd64", func(s *state, n *Node, args []*ssa.Value) *ssa.Value { v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem()) s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v) }, - sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64) + sys.AMD64, sys.S390X, sys.MIPS64, sys.PPC64) + + makeXaddARM64 := func(op0 ssa.Op, op1 ssa.Op, ty types.EType) func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + return func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + // Target Atomic feature is identified by dynamic detection + addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), arm64SupportAtomics, s.sb) + v := s.load(types.Types[TBOOL], addr) + b := s.endBlock() + b.Kind = ssa.BlockIf + b.SetControl(v) + bTrue := s.f.NewBlock(ssa.BlockPlain) + bFalse := s.f.NewBlock(ssa.BlockPlain) + bEnd := s.f.NewBlock(ssa.BlockPlain) + b.AddEdgeTo(bTrue) + b.AddEdgeTo(bFalse) + b.Likely = ssa.BranchUnlikely // most machines don't have Atomics nowadays + + // We have atomic instructions - use it directly. + s.startBlock(bTrue) + v0 := s.newValue3(op1, types.NewTuple(types.Types[ty], types.TypeMem), args[0], args[1], s.mem()) + s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v0) + s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[ty], v0) + s.endBlock().AddEdgeTo(bEnd) + + // Use original instruction sequence. + s.startBlock(bFalse) + v1 := s.newValue3(op0, types.NewTuple(types.Types[ty], types.TypeMem), args[0], args[1], s.mem()) + s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v1) + s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[ty], v1) + s.endBlock().AddEdgeTo(bEnd) + + // Merge results. + s.startBlock(bEnd) + return s.variable(n, types.Types[ty]) + } + } + + addF("runtime/internal/atomic", "Xadd", + makeXaddARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32), + sys.ARM64) + addF("runtime/internal/atomic", "Xadd64", + makeXaddARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64), + sys.ARM64) addF("runtime/internal/atomic", "Cas", func(s *state, n *Node, args []*ssa.Value) *ssa.Value { diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index a1a3cccf3c..a7e747e6e7 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -544,6 +544,9 @@ (AtomicAnd8 ptr val mem) -> (Select1 (LoweredAtomicAnd8 ptr val mem)) (AtomicOr8 ptr val mem) -> (Select1 (LoweredAtomicOr8 ptr val mem)) +(AtomicAdd32Variant ptr val mem) -> (LoweredAtomicAdd32Variant ptr val mem) +(AtomicAdd64Variant ptr val mem) -> (LoweredAtomicAdd64Variant ptr val mem) + // Write barrier. (WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index 9e8b07ec4b..c87c18f3fb 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -578,6 +578,13 @@ func init() { {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + // atomic add variant. + // *arg0 += arg1. arg2=mem. returns . auxint must be zero. + // LDADDAL (Rarg0), Rarg1, Rout + // ADD Rarg1, Rout + {name: "LoweredAtomicAdd64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAdd32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + // atomic compare and swap. // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero. // if *arg0 == arg1 { diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 13581452e7..07d93ac073 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -515,6 +515,13 @@ var genericOps = []opData{ {name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory. {name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory. + // Atomic operation variants + // These variants have the same semantics as above atomic operations. + // But they are used for generating more efficient code on certain modern machines, with run-time CPU feature detection. + // Currently, they are used on ARM64 only. + {name: "AtomicAdd32Variant", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory. + {name: "AtomicAdd64Variant", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory. + // Clobber experiment op {name: "Clobber", argLength: 0, typ: "Void", aux: "SymOff", symEffect: "None"}, // write an invalid pointer value to the given pointer slot of a stack variable } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index eec5b02713..01ce5e9e7d 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -1275,6 +1275,8 @@ const ( OpARM64LoweredAtomicExchange32 OpARM64LoweredAtomicAdd64 OpARM64LoweredAtomicAdd32 + OpARM64LoweredAtomicAdd64Variant + OpARM64LoweredAtomicAdd32Variant OpARM64LoweredAtomicCas64 OpARM64LoweredAtomicCas32 OpARM64LoweredAtomicAnd8 @@ -2287,6 +2289,8 @@ const ( OpAtomicCompareAndSwap64 OpAtomicAnd8 OpAtomicOr8 + OpAtomicAdd32Variant + OpAtomicAdd64Variant OpClobber ) @@ -16722,6 +16726,38 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "LoweredAtomicAdd64Variant", + argLen: 3, + resultNotInArgs: true, + faultOnNilArg0: true, + hasSideEffects: true, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, + }, + }, + { + name: "LoweredAtomicAdd32Variant", + argLen: 3, + resultNotInArgs: true, + faultOnNilArg0: true, + hasSideEffects: true, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, + }, + }, { name: "LoweredAtomicCas64", argLen: 4, @@ -27825,6 +27861,18 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, generic: true, }, + { + name: "AtomicAdd32Variant", + argLen: 3, + hasSideEffects: true, + generic: true, + }, + { + name: "AtomicAdd64Variant", + argLen: 3, + hasSideEffects: true, + generic: true, + }, { name: "Clobber", auxType: auxSymOff, diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index 60121038e4..d039c731d3 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -341,8 +341,12 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpAndB_0(v) case OpAtomicAdd32: return rewriteValueARM64_OpAtomicAdd32_0(v) + case OpAtomicAdd32Variant: + return rewriteValueARM64_OpAtomicAdd32Variant_0(v) case OpAtomicAdd64: return rewriteValueARM64_OpAtomicAdd64_0(v) + case OpAtomicAdd64Variant: + return rewriteValueARM64_OpAtomicAdd64Variant_0(v) case OpAtomicAnd8: return rewriteValueARM64_OpAtomicAnd8_0(v) case OpAtomicCompareAndSwap32: @@ -25908,6 +25912,22 @@ func rewriteValueARM64_OpAtomicAdd32_0(v *Value) bool { return true } } +func rewriteValueARM64_OpAtomicAdd32Variant_0(v *Value) bool { + // match: (AtomicAdd32Variant ptr val mem) + // cond: + // result: (LoweredAtomicAdd32Variant ptr val mem) + for { + _ = v.Args[2] + ptr := v.Args[0] + val := v.Args[1] + mem := v.Args[2] + v.reset(OpARM64LoweredAtomicAdd32Variant) + v.AddArg(ptr) + v.AddArg(val) + v.AddArg(mem) + return true + } +} func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool { // match: (AtomicAdd64 ptr val mem) // cond: @@ -25924,6 +25944,22 @@ func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool { return true } } +func rewriteValueARM64_OpAtomicAdd64Variant_0(v *Value) bool { + // match: (AtomicAdd64Variant ptr val mem) + // cond: + // result: (LoweredAtomicAdd64Variant ptr val mem) + for { + _ = v.Args[2] + ptr := v.Args[0] + val := v.Args[1] + mem := v.Args[2] + v.reset(OpARM64LoweredAtomicAdd64Variant) + v.AddArg(ptr) + v.AddArg(val) + v.AddArg(mem) + return true + } +} func rewriteValueARM64_OpAtomicAnd8_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index 8e725c6f2c..9be0183edf 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -594,6 +594,8 @@ const ( AHVC AIC AISB + ALDADDALD + ALDADDALW ALDADDB ALDADDH ALDADDW diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go index 30be3b2732..0579e5362e 100644 --- a/src/cmd/internal/obj/arm64/anames.go +++ b/src/cmd/internal/obj/arm64/anames.go @@ -96,6 +96,8 @@ var Anames = []string{ "HVC", "IC", "ISB", + "LDADDALD", + "LDADDALW", "LDADDB", "LDADDH", "LDADDW", diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index e727143757..192d65df96 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -2011,6 +2011,8 @@ func buildop(ctxt *obj.Link) { oprangeset(ASWPB, t) oprangeset(ASWPH, t) oprangeset(ASWPW, t) + oprangeset(ALDADDALD, t) + oprangeset(ALDADDALW, t) oprangeset(ALDADDB, t) oprangeset(ALDADDH, t) oprangeset(ALDADDW, t) @@ -3363,9 +3365,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { rt := p.RegTo2 rb := p.To.Reg switch p.As { - case ASWPD, ALDADDD, ALDANDD, ALDEORD, ALDORD: // 64-bit + case ASWPD, ALDADDALD, ALDADDD, ALDANDD, ALDEORD, ALDORD: // 64-bit o1 = 3 << 30 - case ASWPW, ALDADDW, ALDANDW, ALDEORW, ALDORW: // 32-bit + case ASWPW, ALDADDALW, ALDADDW, ALDANDW, ALDEORW, ALDORW: // 32-bit o1 = 2 << 30 case ASWPH, ALDADDH, ALDANDH, ALDEORH, ALDORH: // 16-bit o1 = 1 << 30 @@ -3377,7 +3379,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { switch p.As { case ASWPD, ASWPW, ASWPH, ASWPB: o1 |= 0x20 << 10 - case ALDADDD, ALDADDW, ALDADDH, ALDADDB: + case ALDADDALD, ALDADDALW, ALDADDD, ALDADDW, ALDADDH, ALDADDB: o1 |= 0x00 << 10 case ALDANDD, ALDANDW, ALDANDH, ALDANDB: o1 |= 0x04 << 10 @@ -3386,6 +3388,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { case ALDORD, ALDORW, ALDORH, ALDORB: o1 |= 0x0c << 10 } + switch p.As { + case ALDADDALD, ALDADDALW: + o1 |= 3 << 22 + } o1 |= 0x1c1<<21 | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31) case 50: /* sys/sysl */ diff --git a/src/runtime/internal/atomic/bench_test.go b/src/runtime/internal/atomic/bench_test.go index 2a22e88fb8..083a75cb07 100644 --- a/src/runtime/internal/atomic/bench_test.go +++ b/src/runtime/internal/atomic/bench_test.go @@ -42,3 +42,23 @@ func BenchmarkAtomicStore(b *testing.B) { atomic.Store(&x, 0) } } + +func BenchmarkXadd(b *testing.B) { + var x uint32 + ptr := &x + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + atomic.Xadd(ptr, 1) + } + }) +} + +func BenchmarkXadd64(b *testing.B) { + var x uint64 + ptr := &x + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + atomic.Xadd64(ptr, 1) + } + }) +} diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 36c74a1e8c..b5486321ed 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -517,6 +517,8 @@ func cpuinit() { support_popcnt = cpu.X86.HasPOPCNT support_sse2 = cpu.X86.HasSSE2 support_sse41 = cpu.X86.HasSSE41 + + arm64_support_atomics = cpu.ARM64.HasATOMICS } // The bootstrap sequence is: diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 1ac0083828..a3193b63c5 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -840,10 +840,13 @@ var ( processorVersionInfo uint32 isIntel bool lfenceBeforeRdtsc bool + + // Set in runtime.cpuinit. support_erms bool support_popcnt bool support_sse2 bool support_sse41 bool + arm64_support_atomics bool goarm uint8 // set by cmd/link on arm systems framepointer_enabled bool // set by cmd/link From 1507502ff2a9d18c90a293728773015804992752 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 21 Jun 2018 12:01:54 -0700 Subject: [PATCH 135/203] cmd/go: re-enable a couple of tests of gccgo Updates #22472 Change-Id: I526d131f2ef8e0200f7a5634c75b31e0ee083f93 Reviewed-on: https://go-review.googlesource.com/120375 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/go/go_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 8d486b7a77..cb4a1a04b9 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -799,7 +799,6 @@ func TestBuildComplex(t *testing.T) { tg.run("build", "-x", "-o", os.DevNull, "complex") if _, err := exec.LookPath("gccgo"); err == nil { - t.Skip("golang.org/issue/22472") tg.run("build", "-x", "-o", os.DevNull, "-compiler=gccgo", "complex") } } @@ -3084,7 +3083,6 @@ func TestIssue7573(t *testing.T) { if _, err := exec.LookPath("gccgo"); err != nil { t.Skip("skipping because no gccgo compiler found") } - t.Skip("golang.org/issue/22472") tg := testgo(t) defer tg.cleanup() From 24fb2e015af156c032a6598b0773785d766a8aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20Tudor=20C=C4=83lin?= Date: Thu, 21 Jun 2018 19:11:34 +0200 Subject: [PATCH 136/203] internal/poll: use more fine-grained locking in Splice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous code acquired a read lock on src and a write lock on dst for the entire duration of Splice. This resulted in deadlock, in a situation akin to the following: Splice is blocking, waiting to read from src. The caller tries to close dst from another goroutine, but Close on dst blocks in runtime.semacquire, because Splice is still holding a write lock on it, and the Close didn't unblock any I/O. The caller cannot unblock the read side of Splice through other means, because they are stuck waiting in dst.Close(). Use more fine-grained locking instead: acquire the read lock on src just before trying to splice from the source socket to the pipe, and acquire the write lock on dst just before trying to splice from the pipe to the destination socket. Fixes #25985 Change-Id: I264c91c7a69bb6c5e28610e2bd801244804cf86d Reviewed-on: https://go-review.googlesource.com/120317 Run-TryBot: Aram Hăvărneanu TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/internal/poll/splice_linux.go | 28 +++++++------- src/net/splice_test.go | 63 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go index 5874f79a56..aa237e587a 100644 --- a/src/internal/poll/splice_linux.go +++ b/src/internal/poll/splice_linux.go @@ -34,20 +34,6 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, defer destroyTempPipe(prfd, pwfd) // From here on, the operation should be considered handled, // even if Splice doesn't transfer any data. - if err := src.readLock(); err != nil { - return 0, true, "splice", err - } - defer src.readUnlock() - if err := dst.writeLock(); err != nil { - return 0, true, "splice", err - } - defer dst.writeUnlock() - if err := src.pd.prepareRead(src.isFile); err != nil { - return 0, true, "splice", err - } - if err := dst.pd.prepareWrite(dst.isFile); err != nil { - return 0, true, "splice", err - } var inPipe, n int for err == nil && remain > 0 { max := maxSpliceSize @@ -84,6 +70,13 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, // // If spliceDrain returns (0, nil), src is at EOF. func spliceDrain(pipefd int, sock *FD, max int) (int, error) { + if err := sock.readLock(); err != nil { + return 0, err + } + defer sock.readUnlock() + if err := sock.pd.prepareRead(sock.isFile); err != nil { + return 0, err + } for { n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock) if err != syscall.EAGAIN { @@ -109,6 +102,13 @@ func spliceDrain(pipefd int, sock *FD, max int) (int, error) { // all of it to the socket. This behavior is similar to the Write // step of an io.Copy in userspace. func splicePump(sock *FD, pipefd int, inPipe int) (int, error) { + if err := sock.writeLock(); err != nil { + return 0, err + } + defer sock.writeUnlock() + if err := sock.pd.prepareWrite(sock.isFile); err != nil { + return 0, err + } written := 0 for inPipe > 0 { n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock) diff --git a/src/net/splice_test.go b/src/net/splice_test.go index 483a9e555f..2f1e69ddb6 100644 --- a/src/net/splice_test.go +++ b/src/net/splice_test.go @@ -10,6 +10,8 @@ import ( "bytes" "fmt" "io" + "io/ioutil" + "sync" "testing" ) @@ -19,6 +21,7 @@ func TestSplice(t *testing.T) { t.Run("big", testSpliceBig) t.Run("honorsLimitedReader", testSpliceHonorsLimitedReader) t.Run("readerAtEOF", testSpliceReaderAtEOF) + t.Run("issue25985", testSpliceIssue25985) } func testSpliceSimple(t *testing.T) { @@ -234,6 +237,66 @@ func testSpliceReaderAtEOF(t *testing.T) { } } +func testSpliceIssue25985(t *testing.T) { + front, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer front.Close() + back, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer back.Close() + + var wg sync.WaitGroup + wg.Add(2) + + proxy := func() { + src, err := front.Accept() + if err != nil { + return + } + dst, err := Dial("tcp", back.Addr().String()) + if err != nil { + return + } + defer dst.Close() + defer src.Close() + go func() { + io.Copy(src, dst) + wg.Done() + }() + go func() { + io.Copy(dst, src) + wg.Done() + }() + } + + go proxy() + + toFront, err := Dial("tcp", front.Addr().String()) + if err != nil { + t.Fatal(err) + } + + io.WriteString(toFront, "foo") + toFront.Close() + + fromProxy, err := back.Accept() + if err != nil { + t.Fatal(err) + } + defer fromProxy.Close() + + _, err = ioutil.ReadAll(fromProxy) + if err != nil { + t.Fatal(err) + } + + wg.Wait() +} + func BenchmarkTCPReadFrom(b *testing.B) { testHookUninstaller.Do(uninstallTestHooks) From 4b3428998d46c34efd6cbf219fbd0219d861307d Mon Sep 17 00:00:00 2001 From: Paul Jolly Date: Thu, 21 Jun 2018 18:30:04 +0100 Subject: [PATCH 137/203] misc/wasm: fix permissions on wasm_exec.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently wasm_exec.js is executable (0755) yet has no interpreter. Indeed wasm_exec.js is only ever used as an argument to Node or loaded via a