From fa44af7df1a96235fca2ec10c3129a4d2711ee28 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 15 Jun 2020 16:20:53 -0400 Subject: [PATCH 01/16] [release-branch.go1.14] runtime: set g to gsignal before adjustSignalStack When a signal is received, the runtime probes whether an alternate signal stack is set, if so, adjust gsignal's stack to point to the alternate signal stack. This is done in adjustSignalStack, which calls sigaltstack "syscall", which is a libc call on darwin through asmcgocall. asmcgocall decides whether to do stack switch based on whether we're running on g0 stack, gsignal stack, or regular g stack. If g is not set to gsignal, asmcgocall may make wrong decision. Set g first. adjustSignalStack is recursively nosplit, so it is okay that temporarily gsignal.stack doesn't match the stack we're running on. Updates #39079. Fixes #41991. Change-Id: I59b2c5dc08c3c951f1098fff038bf2e06d7ca055 Reviewed-on: https://go-review.googlesource.com/c/go/+/238020 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor (cherry picked from commit d286e61b6787fe2b55bf0ec8a814962ebda8d202) Reviewed-on: https://go-review.googlesource.com/c/go/+/262557 Trust: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Austin Clements --- src/runtime/signal_unix.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index f18e6b5785..dbac55c3d1 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -435,6 +435,8 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) { return } + setg(g.m.gsignal) + // If some non-Go code called sigaltstack, adjust. var gsignalStack gsignalStack setStack := adjustSignalStack(sig, g.m, &gsignalStack) @@ -442,8 +444,6 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) { g.m.gsignal.stktopsp = getcallersp() } - setg(g.m.gsignal) - if g.stackguard0 == stackFork { signalDuringFork(sig) } From d9dab4f15e7cfc9553e3abd70cbe2a1a8e3d5547 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 14 Oct 2020 16:03:48 -0700 Subject: [PATCH 02/16] [release-branch.go1.14] runtime: stop preemption during syscall.Exec on Darwin On current macOS versions a program that receives a signal during an execve can fail with a SIGILL signal. This appears to be a macOS kernel bug. It has been reported to Apple. This CL partially works around the problem by using execLock to not send preemption signals during execve. Of course some other stray signal could occur, but at least we can avoid exacerbating the problem. We can't simply disable signals, as that would mean that the exec'ed process would start with all signals blocked, which it likely does not expect. For #41702 Fixes #41703 Change-Id: I91b0add967b315671ddcf73269c4d30136e579b4 Reviewed-on: https://go-review.googlesource.com/c/go/+/262438 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang (cherry picked from commit 64fb6ae95f1c322486cbfb758552bb8439a8e6e8) Reviewed-on: https://go-review.googlesource.com/c/go/+/262737 --- src/runtime/signal_unix.go | 11 +++++++++ src/syscall/exec_unix_test.go | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index dbac55c3d1..c7a6c2197c 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -360,6 +360,13 @@ func preemptM(mp *m) { // required). return } + + // On Darwin, don't try to preempt threads during exec. + // Issue #41702. + if GOOS == "darwin" { + execLock.rlock() + } + if atomic.Cas(&mp.signalPending, 0, 1) { // If multiple threads are preempting the same M, it may send many // signals to the same M such that it hardly make progress, causing @@ -368,6 +375,10 @@ func preemptM(mp *m) { // Only send a signal if there isn't already one pending. signalM(mp, sigPreempt) } + + if GOOS == "darwin" { + execLock.runlock() + } } // sigFetchG fetches the value of G safely when running in a signal handler. diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go index 33614f5221..722534af78 100644 --- a/src/syscall/exec_unix_test.go +++ b/src/syscall/exec_unix_test.go @@ -9,11 +9,14 @@ package syscall_test import ( "internal/testenv" "io" + "math/rand" "os" "os/exec" "os/signal" + "runtime" "syscall" "testing" + "time" "unsafe" ) @@ -213,3 +216,45 @@ func TestForeground(t *testing.T) { signal.Reset() } + +// TestExec is for issue #41702. +func TestExec(t *testing.T) { + cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper") + cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2") + o, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("%s\n%v", o, err) + } +} + +// TestExecHelper is used by TestExec. It does nothing by itself. +// In testing on macOS 10.14, this used to fail with +// "signal: illegal instruction" more than half the time. +func TestExecHelper(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" { + return + } + + // We don't have to worry about restoring these values. + // We are in a child process that only runs this test, + // and we are going to call syscall.Exec anyhow. + runtime.GOMAXPROCS(50) + os.Setenv("GO_WANT_HELPER_PROCESS", "3") + + stop := time.Now().Add(time.Second) + for i := 0; i < 100; i++ { + go func(i int) { + r := rand.New(rand.NewSource(int64(i))) + for time.Now().Before(stop) { + r.Uint64() + } + }(i) + } + + time.Sleep(10 * time.Millisecond) + + argv := []string{os.Args[0], "-test.run=TestExecHelper"} + syscall.Exec(os.Args[0], argv, os.Environ()) + + t.Error("syscall.Exec returned") +} From b581ccd46ef243c6a64c343e79b039022da8a7a2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 15 Oct 2020 14:19:10 -0700 Subject: [PATCH 03/16] [release-branch.go1.14] syscall: use MustHaveExec in TestExec For #41702 For #41703 Change-Id: Ib2b15e52aa1fef2f5e644b316c726150252fa9f8 Reviewed-on: https://go-review.googlesource.com/c/go/+/262738 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang (cherry picked from commit 11cfb48df192c14d185c1cfcaad1ba3e7b84c807) Reviewed-on: https://go-review.googlesource.com/c/go/+/264021 --- src/syscall/exec_unix_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go index 722534af78..7f68319517 100644 --- a/src/syscall/exec_unix_test.go +++ b/src/syscall/exec_unix_test.go @@ -219,6 +219,7 @@ func TestForeground(t *testing.T) { // TestExec is for issue #41702. func TestExec(t *testing.T) { + testenv.MustHaveExec(t) cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper") cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2") o, err := cmd.CombinedOutput() From 768b64711ae4292bd9a02c9cc8d44282f5fac66b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 15 Oct 2020 14:39:12 -0700 Subject: [PATCH 04/16] [release-branch.go1.14] runtime: wait for preemption signals before syscall.Exec For #41702 For #41703 For #42023 Change-Id: If07f40b1d73b8f276ee28ffb8b7214175e56c24d Reviewed-on: https://go-review.googlesource.com/c/go/+/262817 Trust: Ian Lance Taylor Trust: Bryan C. Mills Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Cherry Zhang (cherry picked from commit 05739d6f17c57f09264272621b88725a463234d0) Reviewed-on: https://go-review.googlesource.com/c/go/+/264023 --- src/runtime/proc.go | 21 +++++++++++++++++++++ src/runtime/signal_unix.go | 11 +++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 378d02dea7..76a71be123 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1221,6 +1221,14 @@ found: checkdead() unlock(&sched.lock) + if GOOS == "darwin" { + // Make sure pendingPreemptSignals is correct when an M exits. + // For #41702. + if atomic.Load(&m.signalPending) != 0 { + atomic.Xadd(&pendingPreemptSignals, -1) + } + } + if osStack { // Return from mstart and let the system thread // library free the g0 stack and terminate the thread. @@ -3375,11 +3383,24 @@ func syscall_runtime_AfterForkInChild() { inForkedChild = false } +// pendingPreemptSignals is the number of preemption signals +// that have been sent but not received. This is only used on Darwin. +// For #41702. +var pendingPreemptSignals uint32 + // Called from syscall package before Exec. //go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec func syscall_runtime_BeforeExec() { // Prevent thread creation during exec. execLock.lock() + + // On Darwin, wait for all pending preemption signals to + // be received. See issue #41702. + if GOOS == "darwin" { + for int32(atomic.Load(&pendingPreemptSignals)) > 0 { + osyield() + } + } } // Called from syscall package after Exec. diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index c7a6c2197c..9f081d41c5 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -334,6 +334,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) { // Acknowledge the preemption. atomic.Xadd(&gp.m.preemptGen, 1) atomic.Store(&gp.m.signalPending, 0) + + if GOOS == "darwin" { + atomic.Xadd(&pendingPreemptSignals, -1) + } } const preemptMSupported = pushCallSupported @@ -368,6 +372,10 @@ func preemptM(mp *m) { } if atomic.Cas(&mp.signalPending, 0, 1) { + if GOOS == "darwin" { + atomic.Xadd(&pendingPreemptSignals, 1) + } + // If multiple threads are preempting the same M, it may send many // signals to the same M such that it hardly make progress, causing // live-lock problem. Apparently this could happen on darwin. See @@ -439,6 +447,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) { // no non-Go signal handler for sigPreempt. // The default behavior for sigPreempt is to ignore // the signal, so badsignal will be a no-op anyway. + if GOOS == "darwin" { + atomic.Xadd(&pendingPreemptSignals, -1) + } return } c.fixsigcode(sig) From 7bc838165d362d27bb2481c37680bb32e986b2d9 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Wed, 30 Sep 2020 12:07:36 -0700 Subject: [PATCH 05/16] [release-branch.go1.14] src, net/http: update vendor, regenerate h2_bundle.go Features CL: net/http2: send WINDOW_UPDATE on a body's write failure (fixes #41386) https://golang.org/cl/258497 Created by: go get -d golang.org/x/net@release-branch.go1.14 go mod tidy go mod vendor go generate -run=bundle std Updates #40423 Fixes #41386 Change-Id: I3e75527d381dd4c4262db5f2ff755029d448c48b Reviewed-on: https://go-review.googlesource.com/c/go/+/258538 Run-TryBot: Emmanuel Odeke Reviewed-by: Dmitri Shuralyov Trust: Emmanuel Odeke TryBot-Result: Go Bot --- src/go.mod | 2 +- src/go.sum | 5 ++--- src/net/http/h2_bundle.go | 1 + src/vendor/modules.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/go.mod b/src/go.mod index a003f71b5a..8b4faa0296 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d - golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 + golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf // indirect golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f // indirect ) diff --git a/src/go.sum b/src/go.sum index 14aa96f333..2968b35317 100644 --- a/src/go.sum +++ b/src/go.sum @@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe h1:bea4OrKKl5Xs3lVowY+U6d4AgoAmwTzwqwe3KvM9MOE= +golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf h1:+4j7oujXP478CVb/AFvHJmVX5+Pczx2NGts5yirA0oY= @@ -11,5 +11,4 @@ golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f h1:wYBuYA3M/ZC3iBpL1jKHNRNEK7d8D3JoJmM+zx6rLVQ= golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index a5bdb09113..3a575e3f2c 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -5267,6 +5267,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error { if len(data) > 0 { wrote, err := st.body.Write(data) if err != nil { + sc.sendWindowUpdate(nil, int(f.Length)-wrote) return http2streamError(id, http2ErrCodeStreamClosed) } if wrote != len(data) { diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index c702be0bda..54989a2630 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/subtle golang.org/x/crypto/poly1305 -# golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 +# golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe ## explicit golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts From 3109de2a0d0968eda8321d943a68ba90eec5779b Mon Sep 17 00:00:00 2001 From: dqu123 Date: Sat, 10 Oct 2020 16:25:07 -0400 Subject: [PATCH 06/16] [release-branch.go1.14] net/http: deep copy Request.TransferEncoding The existing implementation in Request.Clone() assigns the wrong pointer to r2.TransferEncoding. Updates #41907. Fixes #41913. Change-Id: I7f220a41b1b46a55d1a1005e47c6dd69478cb025 Reviewed-on: https://go-review.googlesource.com/c/go/+/261377 Reviewed-by: Emmanuel Odeke Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Trust: Carlos Amedee Trust: Emmanuel Odeke --- src/net/http/request.go | 2 +- src/net/http/request_test.go | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/net/http/request.go b/src/net/http/request.go index 88fa0939f2..cb2edd2ef9 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -387,7 +387,7 @@ func (r *Request) Clone(ctx context.Context) *Request { if s := r.TransferEncoding; s != nil { s2 := make([]string, len(s)) copy(s2, s) - r2.TransferEncoding = s + r2.TransferEncoding = s2 } r2.Form = cloneURLValues(r.Form) r2.PostForm = cloneURLValues(r.PostForm) diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index 42c16d00ea..461d66e05d 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -828,6 +828,27 @@ func TestWithContextDeepCopiesURL(t *testing.T) { } } +// Ensure that Request.Clone creates a deep copy of TransferEncoding. +// See issue 41907. +func TestRequestCloneTransferEncoding(t *testing.T) { + body := strings.NewReader("body") + req, _ := NewRequest("POST", "https://example.org/", body) + req.TransferEncoding = []string{ + "encoding1", + } + + clonedReq := req.Clone(context.Background()) + // modify original after deep copy + req.TransferEncoding[0] = "encoding2" + + if req.TransferEncoding[0] != "encoding2" { + t.Error("expected req.TransferEncoding to be changed") + } + if clonedReq.TransferEncoding[0] != "encoding1" { + t.Error("expected clonedReq.TransferEncoding to be unchanged") + } +} + func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) { testNoPanicWithBasicAuth(t, h1Mode) } From 1f040e0a6184ef813b8aaf7ce8e409a663939f75 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 20 Jan 2020 17:00:48 -0800 Subject: [PATCH 07/16] [release-branch.go1.14] time: use extended time format past end of zone transitions This gives us better expected information for daylight savings time transitions in year 2038 and beyond. For #36654 For #42155 Change-Id: I5a39aed3c40b184e1d7bb7d6ce3aff5307c4c146 Reviewed-on: https://go-review.googlesource.com/c/go/+/215539 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick (cherry picked from commit b71eafbcece175db33acfb205e9090ca99a8f984) Reviewed-on: https://go-review.googlesource.com/c/go/+/264302 Trust: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Tobias Klauser --- src/time/export_test.go | 31 ++++ src/time/time.go | 50 +++--- src/time/time_test.go | 7 + src/time/zoneinfo.go | 348 ++++++++++++++++++++++++++++++++++++++ src/time/zoneinfo_read.go | 15 +- src/time/zoneinfo_test.go | 94 ++++++++++ 6 files changed, 523 insertions(+), 22 deletions(-) diff --git a/src/time/export_test.go b/src/time/export_test.go index 442c8da4a6..b8ed7cdc53 100644 --- a/src/time/export_test.go +++ b/src/time/export_test.go @@ -36,8 +36,39 @@ var ( ReadFile = readFile LoadTzinfo = loadTzinfo NextStdChunk = nextStdChunk + Tzset = tzset + TzsetName = tzsetName + TzsetOffset = tzsetOffset ) +type RuleKind int + +const ( + RuleJulian = RuleKind(ruleJulian) + RuleDOY = RuleKind(ruleDOY) + RuleMonthWeekDay = RuleKind(ruleMonthWeekDay) +) + +type Rule struct { + Kind RuleKind + Day int + Week int + Mon int + Time int +} + +func TzsetRule(s string) (Rule, string, bool) { + r, rs, ok := tzsetRule(s) + rr := Rule{ + Kind: RuleKind(r.kind), + Day: r.day, + Week: r.week, + Mon: r.mon, + Time: r.time, + } + return rr, rs, ok +} + // StdChunkNames maps from nextStdChunk results to the matched strings. var StdChunkNames = map[int]string{ 0: "", diff --git a/src/time/time.go b/src/time/time.go index 5dc9fa68ac..69668897b5 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -1074,6 +1074,34 @@ func daysIn(m Month, year int) int { return int(daysBefore[m] - daysBefore[m-1]) } +// daysSinceEpoch takes a year and returns the number of days from +// the absolute epoch to the start of that year. +// This is basically (year - zeroYear) * 365, but accounting for leap days. +func daysSinceEpoch(year int) uint64 { + y := uint64(int64(year) - absoluteZeroYear) + + // Add in days from 400-year cycles. + n := y / 400 + y -= 400 * n + d := daysPer400Years * n + + // Add in 100-year cycles. + n = y / 100 + y -= 100 * n + d += daysPer100Years * n + + // Add in 4-year cycles. + n = y / 4 + y -= 4 * n + d += daysPer4Years * n + + // Add in non-leap years. + n = y + d += 365 * n + + return d +} + // Provided by package runtime. func now() (sec int64, nsec int32, mono int64) @@ -1382,28 +1410,8 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T hour, min = norm(hour, min, 60) day, hour = norm(day, hour, 24) - y := uint64(int64(year) - absoluteZeroYear) - // Compute days since the absolute epoch. - - // Add in days from 400-year cycles. - n := y / 400 - y -= 400 * n - d := daysPer400Years * n - - // Add in 100-year cycles. - n = y / 100 - y -= 100 * n - d += daysPer100Years * n - - // Add in 4-year cycles. - n = y / 4 - y -= 4 * n - d += daysPer4Years * n - - // Add in non-leap years. - n = y - d += 365 * n + d := daysSinceEpoch(year) // Add in days before this month. d += uint64(daysBefore[month-1]) diff --git a/src/time/time_test.go b/src/time/time_test.go index 2fc23c4fee..f8483fc454 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -66,6 +66,13 @@ var nanoutctests = []TimeTest{ var localtests = []TimeTest{ {0, parsedTime{1969, December, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}}, {1221681866, parsedTime{2008, September, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}}, + {2159200800, parsedTime{2038, June, 3, 11, 0, 0, 0, Thursday, -7 * 60 * 60, "PDT"}}, + {2152173599, parsedTime{2038, March, 14, 1, 59, 59, 0, Sunday, -8 * 60 * 60, "PST"}}, + {2152173600, parsedTime{2038, March, 14, 3, 0, 0, 0, Sunday, -7 * 60 * 60, "PDT"}}, + {2152173601, parsedTime{2038, March, 14, 3, 0, 1, 0, Sunday, -7 * 60 * 60, "PDT"}}, + {2172733199, parsedTime{2038, November, 7, 1, 59, 59, 0, Sunday, -7 * 60 * 60, "PDT"}}, + {2172733200, parsedTime{2038, November, 7, 1, 0, 0, 0, Sunday, -8 * 60 * 60, "PST"}}, + {2172733201, parsedTime{2038, November, 7, 1, 0, 1, 0, Sunday, -8 * 60 * 60, "PST"}}, } var nanolocaltests = []TimeTest{ diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go index 558803f24e..c3662297c7 100644 --- a/src/time/zoneinfo.go +++ b/src/time/zoneinfo.go @@ -21,6 +21,13 @@ type Location struct { zone []zone tx []zoneTrans + // The tzdata information can be followed by a string that describes + // how to handle DST transitions not recorded in zoneTrans. + // The format is the TZ environment variable without a colon; see + // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html. + // Example string, for America/Los_Angeles: PST8PDT,M3.2.0,M11.1.0 + extend string + // Most lookups will be for the current time. // To avoid the binary search through tx, keep a // static one-element cache that gives the correct @@ -167,6 +174,15 @@ func (l *Location) lookup(sec int64) (name string, offset int, start, end int64) offset = zone.offset start = tx[lo].when // end = maintained during the search + + // If we're at the end of the known zone transitions, + // try the extend string. + if lo == len(tx)-1 && l.extend != "" { + if ename, eoffset, estart, eend, ok := tzset(l.extend, end, sec); ok { + return ename, eoffset, estart, eend + } + } + return } @@ -222,6 +238,338 @@ func (l *Location) firstZoneUsed() bool { return false } +// tzset takes a timezone string like the one found in the TZ environment +// variable, the end of the last time zone transition expressed as seconds +// since January 1, 1970 00:00:00 UTC, and a time expressed the same way. +// We call this a tzset string since in C the function tzset reads TZ. +// The return values are as for lookup, plus ok which reports whether the +// parse succeeded. +func tzset(s string, initEnd, sec int64) (name string, offset int, start, end int64, ok bool) { + var ( + stdName, dstName string + stdOffset, dstOffset int + ) + + stdName, s, ok = tzsetName(s) + if ok { + stdOffset, s, ok = tzsetOffset(s) + } + if !ok { + return "", 0, 0, 0, false + } + + // The numbers in the tzset string are added to local time to get UTC, + // but our offsets are added to UTC to get local time, + // so we negate the number we see here. + stdOffset = -stdOffset + + if len(s) == 0 || s[0] == ',' { + // No daylight savings time. + return stdName, stdOffset, initEnd, omega, true + } + + dstName, s, ok = tzsetName(s) + if ok { + if len(s) == 0 || s[0] == ',' { + dstOffset = stdOffset + secondsPerHour + } else { + dstOffset, s, ok = tzsetOffset(s) + dstOffset = -dstOffset // as with stdOffset, above + } + } + if !ok { + return "", 0, 0, 0, false + } + + if len(s) == 0 { + // Default DST rules per tzcode. + s = ",M3.2.0,M11.1.0" + } + // The TZ definition does not mention ';' here but tzcode accepts it. + if s[0] != ',' && s[0] != ';' { + return "", 0, 0, 0, false + } + s = s[1:] + + var startRule, endRule rule + startRule, s, ok = tzsetRule(s) + if !ok || len(s) == 0 || s[0] != ',' { + return "", 0, 0, 0, false + } + s = s[1:] + endRule, s, ok = tzsetRule(s) + if !ok || len(s) > 0 { + return "", 0, 0, 0, false + } + + year, _, _, yday := absDate(uint64(sec+unixToInternal+internalToAbsolute), false) + + ysec := int64(yday*secondsPerDay) + sec%secondsPerDay + + // Compute start of year in seconds since Unix epoch. + d := daysSinceEpoch(year) + abs := int64(d * secondsPerDay) + abs += absoluteToInternal + internalToUnix + + startSec := int64(tzruleTime(year, startRule, stdOffset)) + endSec := int64(tzruleTime(year, endRule, dstOffset)) + if endSec < startSec { + startSec, endSec = endSec, startSec + stdName, dstName = dstName, stdName + stdOffset, dstOffset = dstOffset, stdOffset + } + + // The start and end values that we return are accurate + // close to a daylight savings transition, but are otherwise + // just the start and end of the year. That suffices for + // the only caller that cares, which is Date. + if ysec < startSec { + return stdName, stdOffset, abs, startSec + abs, true + } else if ysec >= endSec { + return stdName, stdOffset, endSec + abs, abs + 365*secondsPerDay, true + } else { + return dstName, dstOffset, startSec + abs, endSec + abs, true + } +} + +// tzsetName returns the timezone name at the start of the tzset string s, +// and the remainder of s, and reports whether the parsing is OK. +func tzsetName(s string) (string, string, bool) { + if len(s) == 0 { + return "", "", false + } + if s[0] != '<' { + for i, r := range s { + switch r { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '-', '+': + if i < 3 { + return "", "", false + } + return s[:i], s[i:], true + } + } + if len(s) < 3 { + return "", "", false + } + return s, "", true + } else { + for i, r := range s { + if r == '>' { + return s[1:i], s[i+1:], true + } + } + return "", "", false + } +} + +// tzsetOffset returns the timezone offset at the start of the tzset string s, +// and the remainder of s, and reports whether the parsing is OK. +// The timezone offset is returned as a number of seconds. +func tzsetOffset(s string) (offset int, rest string, ok bool) { + if len(s) == 0 { + return 0, "", false + } + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + s = s[1:] + neg = true + } + + var hours int + hours, s, ok = tzsetNum(s, 0, 24) + if !ok { + return 0, "", false + } + off := hours * secondsPerHour + if len(s) == 0 || s[0] != ':' { + if neg { + off = -off + } + return off, s, true + } + + var mins int + mins, s, ok = tzsetNum(s[1:], 0, 59) + if !ok { + return 0, "", false + } + off += mins * secondsPerMinute + if len(s) == 0 || s[0] != ':' { + if neg { + off = -off + } + return off, s, true + } + + var secs int + secs, s, ok = tzsetNum(s[1:], 0, 59) + if !ok { + return 0, "", false + } + off += secs + + if neg { + off = -off + } + return off, s, true +} + +// ruleKind is the kinds of rules that can be seen in a tzset string. +type ruleKind int + +const ( + ruleJulian ruleKind = iota + ruleDOY + ruleMonthWeekDay +) + +// rule is a rule read from a tzset string. +type rule struct { + kind ruleKind + day int + week int + mon int + time int // transition time +} + +// tzsetRule parses a rule from a tzset string. +// It returns the rule, and the remainder of the string, and reports success. +func tzsetRule(s string) (rule, string, bool) { + var r rule + if len(s) == 0 { + return rule{}, "", false + } + ok := false + if s[0] == 'J' { + var jday int + jday, s, ok = tzsetNum(s[1:], 1, 365) + if !ok { + return rule{}, "", false + } + r.kind = ruleJulian + r.day = jday + } else if s[0] == 'M' { + var mon int + mon, s, ok = tzsetNum(s[1:], 1, 12) + if !ok || len(s) == 0 || s[0] != '.' { + return rule{}, "", false + + } + var week int + week, s, ok = tzsetNum(s[1:], 1, 5) + if !ok || len(s) == 0 || s[0] != '.' { + return rule{}, "", false + } + var day int + day, s, ok = tzsetNum(s[1:], 0, 6) + if !ok { + return rule{}, "", false + } + r.kind = ruleMonthWeekDay + r.day = day + r.week = week + r.mon = mon + } else { + var day int + day, s, ok = tzsetNum(s, 0, 365) + if !ok { + return rule{}, "", false + } + r.kind = ruleDOY + r.day = day + } + + if len(s) == 0 || s[0] != '/' { + r.time = 2 * secondsPerHour // 2am is the default + return r, s, true + } + + offset, s, ok := tzsetOffset(s[1:]) + if !ok || offset < 0 { + return rule{}, "", false + } + r.time = offset + + return r, s, true +} + +// tzsetNum parses a number from a tzset string. +// It returns the number, and the remainder of the string, and reports success. +// The number must be between min and max. +func tzsetNum(s string, min, max int) (num int, rest string, ok bool) { + if len(s) == 0 { + return 0, "", false + } + num = 0 + for i, r := range s { + if r < '0' || r > '9' { + if i == 0 || num < min { + return 0, "", false + } + return num, s[i:], true + } + num *= 10 + num += int(r) - '0' + if num > max { + return 0, "", false + } + } + if num < min { + return 0, "", false + } + return num, "", true +} + +// tzruleTime takes a year, a rule, and a timezone offset, +// and returns the number of seconds since the start of the year +// that the rule takes effect. +func tzruleTime(year int, r rule, off int) int { + var s int + switch r.kind { + case ruleJulian: + s = (r.day - 1) * secondsPerDay + if isLeap(year) && r.day >= 60 { + s += secondsPerDay + } + case ruleDOY: + s = r.day * secondsPerDay + case ruleMonthWeekDay: + // Zeller's Congruence. + m1 := (r.mon+9)%12 + 1 + yy0 := year + if r.mon <= 2 { + yy0-- + } + yy1 := yy0 / 100 + yy2 := yy0 % 100 + dow := ((26*m1-2)/10 + 1 + yy2 + yy2/4 + yy1/4 - 2*yy1) % 7 + if dow < 0 { + dow += 7 + } + // Now dow is the day-of-week of the first day of r.mon. + // Get the day-of-month of the first "dow" day. + d := r.day - dow + if d < 0 { + d += 7 + } + for i := 1; i < r.week; i++ { + if d+7 >= daysIn(Month(r.mon), year) { + break + } + d += 7 + } + d += int(daysBefore[r.mon-1]) + if isLeap(year) && r.mon > 2 { + d++ + } + s = d * secondsPerDay + } + + return s + r.time - off +} + // lookupName returns information about the time zone with // the given name (such as "EST") at the given pseudo-Unix time // (what the given time of day would be in UTC). diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go index 1e559a62cc..38c40b53d4 100644 --- a/src/time/zoneinfo_read.go +++ b/src/time/zoneinfo_read.go @@ -78,6 +78,13 @@ func (d *dataIO) byte() (n byte, ok bool) { return p[0], true } +// read returns the read of the data in the buffer. +func (d *dataIO) rest() []byte { + r := d.p + d.p = nil + return r +} + // Make a string by stopping at the first NUL func byteString(p []byte) string { for i := 0; i < len(p); i++ { @@ -213,6 +220,12 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { return nil, badData } + var extend string + rest := d.rest() + if len(rest) > 2 && rest[0] == '\n' && rest[len(rest)-1] == '\n' { + extend = string(rest[1 : len(rest)-1]) + } + // Now we can build up a useful data structure. // First the zone information. // utcoff[4] isdst[1] nameindex[1] @@ -289,7 +302,7 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { } // Committed to succeed. - l := &Location{zone: zone, tx: tx, name: name} + l := &Location{zone: zone, tx: tx, name: name, extend: extend} // Fill in the cache with information about right now, // since that will be the most common lookup. diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index a7ef10c6bc..72829bc9fb 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -182,3 +182,97 @@ func TestMalformedTZData(t *testing.T) { t.Error("expected error, got none") } } + +func TestTzset(t *testing.T) { + for _, test := range []struct { + inStr string + inEnd int64 + inSec int64 + name string + off int + start int64 + end int64 + ok bool + }{ + {"", 0, 0, "", 0, 0, 0, false}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2159200800, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173599, "PST", -8 * 60 * 60, 2145916800, 2152173600, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173600, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2152173601, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733199, "PDT", -7 * 60 * 60, 2152173600, 2172733200, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733200, "PST", -8 * 60 * 60, 2172733200, 2177452800, true}, + {"PST8PDT,M3.2.0,M11.1.0", 0, 2172733201, "PST", -8 * 60 * 60, 2172733200, 2177452800, true}, + } { + name, off, start, end, ok := time.Tzset(test.inStr, test.inEnd, test.inSec) + if name != test.name || off != test.off || start != test.start || end != test.end || ok != test.ok { + t.Errorf("tzset(%q, %d, %d) = %q, %d, %d, %d, %t, want %q, %d, %d, %d, %t", test.inStr, test.inEnd, test.inSec, name, off, start, end, ok, test.name, test.off, test.start, test.end, test.ok) + } + } +} + +func TestTzsetName(t *testing.T) { + for _, test := range []struct { + in string + name string + out string + ok bool + }{ + {"", "", "", false}, + {"X", "", "", false}, + {"PST", "PST", "", true}, + {"PST8PDT", "PST", "8PDT", true}, + {"PST-08", "PST", "-08", true}, + {"+08", "A+B", "+08", true}, + } { + name, out, ok := time.TzsetName(test.in) + if name != test.name || out != test.out || ok != test.ok { + t.Errorf("tzsetName(%q) = %q, %q, %t, want %q, %q, %t", test.in, name, out, ok, test.name, test.out, test.ok) + } + } +} + +func TestTzsetOffset(t *testing.T) { + for _, test := range []struct { + in string + off int + out string + ok bool + }{ + {"", 0, "", false}, + {"X", 0, "", false}, + {"+", 0, "", false}, + {"+08", 8 * 60 * 60, "", true}, + {"-01:02:03", -1*60*60 - 2*60 - 3, "", true}, + {"01", 1 * 60 * 60, "", true}, + {"100", 0, "", false}, + {"8PDT", 8 * 60 * 60, "PDT", true}, + } { + off, out, ok := time.TzsetOffset(test.in) + if off != test.off || out != test.out || ok != test.ok { + t.Errorf("tzsetName(%q) = %d, %q, %t, want %d, %q, %t", test.in, off, out, ok, test.off, test.out, test.ok) + } + } +} + +func TestTzsetRule(t *testing.T) { + for _, test := range []struct { + in string + r time.Rule + out string + ok bool + }{ + {"", time.Rule{}, "", false}, + {"X", time.Rule{}, "", false}, + {"J10", time.Rule{Kind: time.RuleJulian, Day: 10, Time: 2 * 60 * 60}, "", true}, + {"20", time.Rule{Kind: time.RuleDOY, Day: 20, Time: 2 * 60 * 60}, "", true}, + {"M1.2.3", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 1, Week: 2, Day: 3, Time: 2 * 60 * 60}, "", true}, + {"30/03:00:00", time.Rule{Kind: time.RuleDOY, Day: 30, Time: 3 * 60 * 60}, "", true}, + {"M4.5.6/03:00:00", time.Rule{Kind: time.RuleMonthWeekDay, Mon: 4, Week: 5, Day: 6, Time: 3 * 60 * 60}, "", true}, + {"M4.5.7/03:00:00", time.Rule{}, "", false}, + } { + r, out, ok := time.TzsetRule(test.in) + if r != test.r || out != test.out || ok != test.ok { + t.Errorf("tzsetName(%q) = %#v, %q, %t, want %#v, %q, %t", test.in, r, out, ok, test.r, test.out, test.ok) + } + } +} From cfc89399c9e3c9409efce3d0e88f7cde58cc469d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 22 Oct 2020 15:25:00 -0700 Subject: [PATCH 08/16] [release-branch.go1.14] time: support slim tzdata format Backport of part of https://golang.org/cl/261877 to support the slim tzdata format. As of tzdata 2020b, the default is to use the slim format. We need to support that format so that Go installations continue to work when tzdata is updated. Relevant part of the CL description: The reason for the failed tests was that when caching location data, the extended time format past the end of zone transitions was not considered. The respective change was introduced in (*Location).lookup by CL 215539. For #42155 Change-Id: I37f52a0917b2c6e3957e6b4612c8ef104c736e65 Reviewed-on: https://go-review.googlesource.com/c/go/+/264301 Trust: Ian Lance Taylor Reviewed-by: Tobias Klauser (cherry picked from commit 414668cfbc41fd8cadf74e981849d1e05cc23b2e) Reviewed-on: https://go-review.googlesource.com/c/go/+/266298 Run-TryBot: Ian Lance Taylor --- src/time/zoneinfo_read.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go index 38c40b53d4..b79bd474c7 100644 --- a/src/time/zoneinfo_read.go +++ b/src/time/zoneinfo_read.go @@ -313,8 +313,16 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { l.cacheEnd = omega if i+1 < len(tx) { l.cacheEnd = tx[i+1].when + } else if l.extend != "" { + // If we're at the end of the known zone transitions, + // try the extend string. + if _, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok { + l.cacheStart = estart + l.cacheEnd = eend + } } l.cacheZone = &l.zone[tx[i].index] + break } } From 592e24a783f7a68ce301f01401d4efb09099b205 Mon Sep 17 00:00:00 2001 From: Christopher Hlubek Date: Mon, 26 Oct 2020 13:44:44 +0100 Subject: [PATCH 09/16] [release-branch.go1.14] time: fix LoadLocationFromTZData with slim tzdata The extend information of a time zone file with last transition < now could result in a wrong cached zone because it used the zone of the last transition. This could lead to wrong zones in systems with slim zoneinfo. Fixes #42155 Change-Id: I7c57c35b5cfa58482ac7925b5d86618c52f5444d Reviewed-on: https://go-review.googlesource.com/c/go/+/264939 Trust: Tobias Klauser Run-TryBot: Tobias Klauser TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor (cherry picked from commit 70e022e4a83dc996ac4f108e811fbc399ad5565b) Reviewed-on: https://go-review.googlesource.com/c/go/+/266303 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Tobias Klauser --- src/time/zoneinfo_read.go | 13 +++++++++++-- src/time/zoneinfo_test.go | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go index b79bd474c7..698427b779 100644 --- a/src/time/zoneinfo_read.go +++ b/src/time/zoneinfo_read.go @@ -311,17 +311,26 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) { if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) { l.cacheStart = tx[i].when l.cacheEnd = omega + zoneIdx := tx[i].index if i+1 < len(tx) { l.cacheEnd = tx[i+1].when } else if l.extend != "" { // If we're at the end of the known zone transitions, // try the extend string. - if _, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok { + if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok { l.cacheStart = estart l.cacheEnd = eend + // Find the zone that is returned by tzset, + // the last transition is not always the correct zone. + for i, z := range l.zone { + if z.name == name { + zoneIdx = uint8(i) + break + } + } } } - l.cacheZone = &l.zone[tx[i].index] + l.cacheZone = &l.zone[zoneIdx] break } } diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go index 72829bc9fb..277b68f798 100644 --- a/src/time/zoneinfo_test.go +++ b/src/time/zoneinfo_test.go @@ -183,6 +183,25 @@ func TestMalformedTZData(t *testing.T) { } } +func TestLoadLocationFromTZDataSlim(t *testing.T) { + // A 2020b slim tzdata for Europe/Berlin + tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00# Date: Wed, 28 Oct 2020 13:44:53 +0100 Subject: [PATCH 10/16] [release-branch.go1.14] cmd/go/internal/modfetch: drop gopkg.in/russross/blackfriday.v2 from TestCodeRepoVersions Follow-up for CL 265819. Given the -pre tag added recently, a new stable version is likely tagged soon. This would break TestCodeRepoVersions on the longtest builders again. Since the other test cases in codeRepoVersionsTests already provide enough coverage, drop gopkg.in/russross/blackfriday.v2 to avoid breaking TestCodeRepoVersions once the release happens. Updates #28856 Change-Id: If86a637b5e47f59faf9048fc1cbbae6e8f1dcc53 Reviewed-on: https://go-review.googlesource.com/c/go/+/265917 Trust: Tobias Klauser Run-TryBot: Tobias Klauser Reviewed-by: Bryan C. Mills Reviewed-by: Jay Conrod TryBot-Result: Go Bot (cherry picked from commit 421d4e72de802ed65cb38317660654771cfb13e9) Reviewed-on: https://go-review.googlesource.com/c/go/+/266178 Trust: Dmitri Shuralyov Trust: Jay Conrod Run-TryBot: Dmitri Shuralyov Reviewed-by: Tobias Klauser (cherry picked from commit 8687f6d924ee3a311e08db855c6dc1024c1f9349) Reviewed-on: https://go-review.googlesource.com/c/go/+/266302 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov --- src/cmd/go/internal/modfetch/coderepo_test.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go index 39830948fb..2c0a2792e1 100644 --- a/src/cmd/go/internal/modfetch/coderepo_test.go +++ b/src/cmd/go/internal/modfetch/coderepo_test.go @@ -655,11 +655,6 @@ var codeRepoVersionsTests = []struct { path: "swtch.com/testmod", versions: []string{"v1.0.0", "v1.1.1"}, }, - { - vcs: "git", - path: "gopkg.in/russross/blackfriday.v2", - versions: []string{"v2.0.0", "v2.0.1"}, - }, { vcs: "git", path: "gopkg.in/natefinch/lumberjack.v2", From 162b65e05cec843b1a6bee493362f2a3046dba7b Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Thu, 29 Oct 2020 18:43:36 -0400 Subject: [PATCH 11/16] [release-branch.go1.14] net/http: update bundled x/net/http2 Bring in the change in CL 266157 with: go get -d golang.org/x/net@release-branch.go1.14 go mod tidy go mod vendor go generate -run=bundle std Updates #39337. Fixes #42112. Change-Id: Iefd0012369c7f0c58201256e29d21210cb9f2f7a Reviewed-on: https://go-review.googlesource.com/c/go/+/266374 Run-TryBot: Dmitri Shuralyov Reviewed-by: Emmanuel Odeke TryBot-Result: Go Bot Trust: Dmitri Shuralyov --- src/go.mod | 2 +- src/go.sum | 4 ++-- src/net/http/h2_bundle.go | 10 ++++++++++ src/vendor/modules.txt | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/go.mod b/src/go.mod index 8b4faa0296..faf848d5df 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d - golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe + golang.org/x/net v0.0.0-20201029202311-70d85028bad3 golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf // indirect golang.org/x/text v0.3.3-0.20191031172631-4b67af870c6f // indirect ) diff --git a/src/go.sum b/src/go.sum index 2968b35317..58d6621a2f 100644 --- a/src/go.sum +++ b/src/go.sum @@ -2,8 +2,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe h1:bea4OrKKl5Xs3lVowY+U6d4AgoAmwTzwqwe3KvM9MOE= -golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201029202311-70d85028bad3 h1:zhmuDiUI8/S25xjIBeUn8XwfxP7SKYR41pTuOoa1O+w= +golang.org/x/net v0.0.0-20201029202311-70d85028bad3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200201011859-915c9c3d4ccf h1:+4j7oujXP478CVb/AFvHJmVX5+Pczx2NGts5yirA0oY= diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 3a575e3f2c..0e9139b9ef 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -7169,6 +7169,7 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize) cc.bw.Flush() if cc.werr != nil { + cc.Close() return nil, cc.werr } @@ -7534,6 +7535,15 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe bodyWriter := cc.t.getBodyWriterState(cs, body) cs.on100 = bodyWriter.on100 + defer func() { + cc.wmu.Lock() + werr := cc.werr + cc.wmu.Unlock() + if werr != nil { + cc.Close() + } + }() + cc.wmu.Lock() endStream := !hasBody && !hasTrailers werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 54989a2630..7c6c478b12 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519 golang.org/x/crypto/hkdf golang.org/x/crypto/internal/subtle golang.org/x/crypto/poly1305 -# golang.org/x/net v0.0.0-20201012150639-9ef5ab9c4fbe +# golang.org/x/net v0.0.0-20201029202311-70d85028bad3 ## explicit golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts From e82710b825958f30b924fc6dba1fd0a63b517199 Mon Sep 17 00:00:00 2001 From: Alexander Rakoczy Date: Thu, 5 Nov 2020 13:12:54 -0500 Subject: [PATCH 12/16] [release-branch.go1.14] go1.14.11 Change-Id: I1b4231179d0825113f2cbb6e84e92b3453e2ee45 Reviewed-on: https://go-review.googlesource.com/c/go/+/267878 Run-TryBot: Alexander Rakoczy TryBot-Result: Go Bot Reviewed-by: Dmitri Shuralyov Trust: Alexander Rakoczy --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7624397d62..75ab4edfdc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.14.10 \ No newline at end of file +go1.14.11 \ No newline at end of file From 57ffa7b101296229328eaec6219a7c211a4ac49b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 Nov 2020 09:38:38 -0800 Subject: [PATCH 13/16] [release-branch.go1.14-security] cmd/go, cmd/cgo: don't let bogus symbol set cgo_ldflag A hand-edited object file can have a symbol name that uses newline and other normally invalid characters. The cgo tool will generate Go files containing symbol names, unquoted. That can permit those symbol names to inject Go code into a cgo-generated file. If that Go code uses the //go:cgo_ldflag pragma, it can cause the C linker to run arbitrary code when building a package. If you build an imported package we permit arbitrary code at run time, but we don't want to permit it at package build time. This CL prevents this in two ways. In cgo, reject invalid symbols that contain non-printable or space characters, or that contain anything that looks like a Go comment. In the go tool, double check all //go:cgo_ldflag directives in generated code, to make sure they follow the existing LDFLAG restrictions. Thanks to Chris Brown and Tempus Ex for reporting this. Fixes CVE-2020-28366 Change-Id: Ia1ad8f3791ea79612690fa7d26ac451d0f6df7c1 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/895832 Reviewed-by: Than McIntosh Reviewed-by: Cherry Zhang (cherry picked from commit 6bc814dd2bbfeaafa41d314dd4cc591b575dfbf6) Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/901055 Reviewed-by: Filippo Valsorda Reviewed-by: Roland Shoemaker --- misc/cgo/errors/badsym_test.go | 224 +++++++++++++++++++++++++++++++ src/cmd/cgo/out.go | 24 ++++ src/cmd/go/internal/work/exec.go | 60 +++++++++ 3 files changed, 308 insertions(+) create mode 100644 misc/cgo/errors/badsym_test.go diff --git a/misc/cgo/errors/badsym_test.go b/misc/cgo/errors/badsym_test.go new file mode 100644 index 0000000000..bef6b1e9e1 --- /dev/null +++ b/misc/cgo/errors/badsym_test.go @@ -0,0 +1,224 @@ +// Copyright 2020 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 errorstest + +import ( + "bytes" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "unicode" +) + +// A manually modified object file could pass unexpected characters +// into the files generated by cgo. + +const magicInput = "abcdefghijklmnopqrstuvwxyz0123" +const magicReplace = "\n//go:cgo_ldflag \"-badflag\"\n//" + +const cSymbol = "BadSymbol" + magicInput + "Name" +const cDefSource = "int " + cSymbol + " = 1;" +const cRefSource = "extern int " + cSymbol + "; int F() { return " + cSymbol + "; }" + +// goSource is the source code for the trivial Go file we use. +// We will replace TMPDIR with the temporary directory name. +const goSource = ` +package main + +// #cgo LDFLAGS: TMPDIR/cbad.o TMPDIR/cbad.so +// extern int F(); +import "C" + +func main() { + println(C.F()) +} +` + +func TestBadSymbol(t *testing.T) { + dir, err := ioutil.TempDir("", "testbadsymbol") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + t.Cleanup(func() { + if err := os.RemoveAll(dir); err != nil { + t.Errorf("TempDir RemoveAll cleanup: %v", err) + } + }) + + mkdir := func(base string) string { + ret := filepath.Join(dir, base) + if err := os.Mkdir(ret, 0755); err != nil { + t.Fatal(err) + } + return ret + } + + cdir := mkdir("c") + godir := mkdir("go") + + makeFile := func(mdir, base, source string) string { + ret := filepath.Join(mdir, base) + if err := ioutil.WriteFile(ret, []byte(source), 0644); err != nil { + t.Fatal(err) + } + return ret + } + + cDefFile := makeFile(cdir, "cdef.c", cDefSource) + cRefFile := makeFile(cdir, "cref.c", cRefSource) + + ccCmd := cCompilerCmd(t) + + cCompile := func(arg, base, src string) string { + out := filepath.Join(cdir, base) + run := append(ccCmd, arg, "-o", out, src) + output, err := exec.Command(run[0], run[1:]...).CombinedOutput() + if err != nil { + t.Log(run) + t.Logf("%s", output) + t.Fatal(err) + } + if err := os.Remove(src); err != nil { + t.Fatal(err) + } + return out + } + + // Build a shared library that defines a symbol whose name + // contains magicInput. + + cShared := cCompile("-shared", "c.so", cDefFile) + + // Build an object file that refers to the symbol whose name + // contains magicInput. + + cObj := cCompile("-c", "c.o", cRefFile) + + // Rewrite the shared library and the object file, replacing + // magicInput with magicReplace. This will have the effect of + // introducing a symbol whose name looks like a cgo command. + // The cgo tool will use that name when it generates the + // _cgo_import.go file, thus smuggling a magic //go:cgo_ldflag + // pragma into a Go file. We used to not check the pragmas in + // _cgo_import.go. + + rewrite := func(from, to string) { + obj, err := ioutil.ReadFile(from) + if err != nil { + t.Fatal(err) + } + + if bytes.Count(obj, []byte(magicInput)) == 0 { + t.Fatalf("%s: did not find magic string", from) + } + + if len(magicInput) != len(magicReplace) { + t.Fatalf("internal test error: different magic lengths: %d != %d", len(magicInput), len(magicReplace)) + } + + obj = bytes.ReplaceAll(obj, []byte(magicInput), []byte(magicReplace)) + + if err := ioutil.WriteFile(to, obj, 0644); err != nil { + t.Fatal(err) + } + } + + cBadShared := filepath.Join(godir, "cbad.so") + rewrite(cShared, cBadShared) + + cBadObj := filepath.Join(godir, "cbad.o") + rewrite(cObj, cBadObj) + + goSourceBadObject := strings.ReplaceAll(goSource, "TMPDIR", godir) + makeFile(godir, "go.go", goSourceBadObject) + + makeFile(godir, "go.mod", "module badsym") + + // Try to build our little package. + cmd := exec.Command("go", "build", "-ldflags=-v") + cmd.Dir = godir + output, err := cmd.CombinedOutput() + + // The build should fail, but we want it to fail because we + // detected the error, not because we passed a bad flag to the + // C linker. + + if err == nil { + t.Errorf("go build succeeded unexpectedly") + } + + t.Logf("%s", output) + + for _, line := range bytes.Split(output, []byte("\n")) { + if bytes.Contains(line, []byte("dynamic symbol")) && bytes.Contains(line, []byte("contains unsupported character")) { + // This is the error from cgo. + continue + } + + // We passed -ldflags=-v to see the external linker invocation, + // which should not include -badflag. + if bytes.Contains(line, []byte("-badflag")) { + t.Error("output should not mention -badflag") + } + + // Also check for compiler errors, just in case. + // GCC says "unrecognized command line option". + // clang says "unknown argument". + if bytes.Contains(line, []byte("unrecognized")) || bytes.Contains(output, []byte("unknown")) { + t.Error("problem should have been caught before invoking C linker") + } + } +} + +func cCompilerCmd(t *testing.T) []string { + cc := []string{goEnv(t, "CC")} + + out := goEnv(t, "GOGCCFLAGS") + quote := '\000' + start := 0 + lastSpace := true + backslash := false + s := string(out) + for i, c := range s { + if quote == '\000' && unicode.IsSpace(c) { + if !lastSpace { + cc = append(cc, s[start:i]) + lastSpace = true + } + } else { + if lastSpace { + start = i + lastSpace = false + } + if quote == '\000' && !backslash && (c == '"' || c == '\'') { + quote = c + backslash = false + } else if !backslash && quote == c { + quote = '\000' + } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' { + backslash = true + } else { + backslash = false + } + } + } + if !lastSpace { + cc = append(cc, s[start:]) + } + return cc +} + +func goEnv(t *testing.T, key string) string { + out, err := exec.Command("go", "env", key).CombinedOutput() + if err != nil { + t.Logf("go env %s\n", key) + t.Logf("%s", out) + t.Fatal(err) + } + return strings.TrimSpace(string(out)) +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index e32a3a607b..d447bcb543 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -22,6 +22,7 @@ import ( "regexp" "sort" "strings" + "unicode" ) var ( @@ -325,6 +326,8 @@ func dynimport(obj string) { if s.Version != "" { targ += "#" + s.Version } + checkImportSymName(s.Name) + checkImportSymName(targ) fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) } lib, _ := f.ImportedLibraries() @@ -340,6 +343,7 @@ func dynimport(obj string) { if len(s) > 0 && s[0] == '_' { s = s[1:] } + checkImportSymName(s) fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "") } lib, _ := f.ImportedLibraries() @@ -354,6 +358,8 @@ func dynimport(obj string) { for _, s := range sym { ss := strings.Split(s, ":") name := strings.Split(ss[0], "@")[0] + checkImportSymName(name) + checkImportSymName(ss[0]) fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) } return @@ -371,6 +377,7 @@ func dynimport(obj string) { // Go symbols. continue } + checkImportSymName(s.Name) fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library) } lib, err := f.ImportedLibraries() @@ -386,6 +393,23 @@ func dynimport(obj string) { fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj) } +// checkImportSymName checks a symbol name we are going to emit as part +// of a //go:cgo_import_dynamic pragma. These names come from object +// files, so they may be corrupt. We are going to emit them unquoted, +// so while they don't need to be valid symbol names (and in some cases, +// involving symbol versions, they won't be) they must contain only +// graphic characters and must not contain Go comments. +func checkImportSymName(s string) { + for _, c := range s { + if !unicode.IsGraphic(c) || unicode.IsSpace(c) { + fatalf("dynamic symbol %q contains unsupported character", s) + } + } + if strings.Index(s, "//") >= 0 || strings.Index(s, "/*") >= 0 { + fatalf("dynamic symbol %q contains Go comment") + } +} + // Construct a gcc struct matching the gc argument frame. // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes. // These assumptions are checked by the gccProlog. diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 25d15079e4..6e20c055fa 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -2632,6 +2632,66 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo noCompiler() } + // Double check the //go:cgo_ldflag comments in the generated files. + // The compiler only permits such comments in files whose base name + // starts with "_cgo_". Make sure that the comments in those files + // are safe. This is a backstop against people somehow smuggling + // such a comment into a file generated by cgo. + if cfg.BuildToolchainName == "gc" && !cfg.BuildN { + var flags []string + for _, f := range outGo { + if !strings.HasPrefix(filepath.Base(f), "_cgo_") { + continue + } + + src, err := ioutil.ReadFile(f) + if err != nil { + return nil, nil, err + } + + const cgoLdflag = "//go:cgo_ldflag" + idx := bytes.Index(src, []byte(cgoLdflag)) + for idx >= 0 { + // We are looking at //go:cgo_ldflag. + // Find start of line. + start := bytes.LastIndex(src[:idx], []byte("\n")) + if start == -1 { + start = 0 + } + + // Find end of line. + end := bytes.Index(src[idx:], []byte("\n")) + if end == -1 { + end = len(src) + } else { + end += idx + } + + // Check for first line comment in line. + // We don't worry about /* */ comments, + // which normally won't appear in files + // generated by cgo. + commentStart := bytes.Index(src[start:], []byte("//")) + commentStart += start + // If that line comment is //go:cgo_ldflag, + // it's a match. + if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) { + // Pull out the flag, and unquote it. + // This is what the compiler does. + flag := string(src[idx+len(cgoLdflag) : end]) + flag = strings.TrimSpace(flag) + flag = strings.Trim(flag, `"`) + flags = append(flags, flag) + } + src = src[end:] + idx = bytes.Index(src, []byte(cgoLdflag)) + } + } + if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil { + return nil, nil, err + } + } + return outGo, outObj, nil } From ff5addb6be2fb3001f0cb026c3e4931090a85664 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 2 Nov 2020 21:31:06 -0800 Subject: [PATCH 14/16] [release-branch.go1.14-security] cmd/go: in cgoflags, permit -DX1, prohibit -Wp,-D,opt Restrict -D and -U to ASCII C identifiers, but do permit trailing digits. When using -Wp, prohibit commas in -D values. Thanks to Imre Rad (https://www.linkedin.com/in/imre-rad-2358749b) for reporting this. Fixes CVE-2020-28367 Change-Id: Ibfc4dfdd6e6c258e131448e7682610c44eee9492 Reviewed-on: https://go-review.googlesource.com/c/go/+/267277 Trust: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Go Bot Reviewed-by: Bryan C. Mills Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/899923 Reviewed-by: Filippo Valsorda --- src/cmd/go/internal/work/security.go | 8 ++++---- src/cmd/go/internal/work/security_test.go | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index 0ce1664c16..a823b20b6d 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -42,8 +42,8 @@ import ( var re = lazyregexp.New var validCompilerFlags = []*lazyregexp.Regexp{ - re(`-D([A-Za-z_].*)`), - re(`-U([A-Za-z_]*)`), + re(`-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?`), + re(`-U([A-Za-z_][A-Za-z0-9_]*)`), re(`-F([^@\-].*)`), re(`-I([^@\-].*)`), re(`-O`), @@ -51,8 +51,8 @@ var validCompilerFlags = []*lazyregexp.Regexp{ re(`-W`), re(`-W([^@,]+)`), // -Wall but not -Wa,-foo. re(`-Wa,-mbig-obj`), - re(`-Wp,-D([A-Za-z_].*)`), - re(`-Wp,-U([A-Za-z_]*)`), + re(`-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?`), + re(`-Wp,-U([A-Za-z_][A-Za-z0-9_]*)`), re(`-ansi`), re(`-f(no-)?asynchronous-unwind-tables`), re(`-f(no-)?blocks`), diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 6b85c40b13..bd707ff623 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -13,6 +13,7 @@ var goodCompilerFlags = [][]string{ {"-DFOO"}, {"-Dfoo=bar"}, {"-Ufoo"}, + {"-Ufoo1"}, {"-F/Qt"}, {"-I/"}, {"-I/etc/passwd"}, @@ -24,6 +25,8 @@ var goodCompilerFlags = [][]string{ {"-Wall"}, {"-Wp,-Dfoo=bar"}, {"-Wp,-Ufoo"}, + {"-Wp,-Dfoo1"}, + {"-Wp,-Ufoo1"}, {"-fobjc-arc"}, {"-fno-objc-arc"}, {"-fomit-frame-pointer"}, @@ -78,6 +81,8 @@ var badCompilerFlags = [][]string{ {"-O@1"}, {"-Wa,-foo"}, {"-W@foo"}, + {"-Wp,-DX,-D@X"}, + {"-Wp,-UX,-U@X"}, {"-g@gdb"}, {"-g-gdb"}, {"-march=@dawn"}, From f7a1fcf7a55d6b0bc97b02f5b9dd4a15d54aeafa Mon Sep 17 00:00:00 2001 From: Katie Hockman Date: Tue, 10 Nov 2020 15:54:12 -0500 Subject: [PATCH 15/16] [release-branch.go1.14-security] math/big: fix shift for recursive division MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous s value could cause a crash for certain inputs. Will check in tests and documentation improvements later. Thanks to the Go Ethereum team and the OSS-Fuzz project for reporting this. Thanks to Rémy Oudompheng and Robert Griesemer for their help developing and validating the fix. Fixes CVE-2020-28362 Change-Id: Ibbf455c4436bcdb07c84a34fa6551fb3422356d3 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/899974 Reviewed-by: Roland Shoemaker Reviewed-by: Filippo Valsorda (cherry picked from commit 28015462c2a83239543dc2bef651e9a5f234b633) Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/901064 --- src/math/big/nat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/big/nat.go b/src/math/big/nat.go index c31ec5156b..b967621250 100644 --- a/src/math/big/nat.go +++ b/src/math/big/nat.go @@ -928,7 +928,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // Now u < (v< Date: Thu, 12 Nov 2020 09:43:57 -0500 Subject: [PATCH 16/16] [release-branch.go1.14-security] go1.14.12 Change-Id: I8ce7093f7e119216d3a5d8941968788b70b6afaf Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/901408 Reviewed-by: Katie Hockman --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 75ab4edfdc..9a04965382 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.14.11 \ No newline at end of file +go1.14.12 \ No newline at end of file