diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go index 5a4bc1d60a..fd03efb417 100644 --- a/src/cmd/compile/internal/ssa/loopbce.go +++ b/src/cmd/compile/internal/ssa/loopbce.go @@ -159,6 +159,13 @@ func findIndVar(f *Func) []indVar { step = -step } + if flags&indVarMaxInc != 0 && max.Op == OpConst64 && max.AuxInt+step < max.AuxInt { + // For a <= comparison, we need to make sure that a value equal to + // max can be incremented without overflowing. + // (For a < comparison, the %step check below ensures no overflow.) + continue + } + // Up to now we extracted the induction variable (ind), // the increment delta (inc), the temporary sum (nxt), // the mininum value (min) and the maximum value (max). diff --git a/src/cmd/compile/internal/walk/complit.go b/src/cmd/compile/internal/walk/complit.go index abd920d646..1f288d21c1 100644 --- a/src/cmd/compile/internal/walk/complit.go +++ b/src/cmd/compile/internal/walk/complit.go @@ -621,6 +621,12 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool { // not a special composite literal assignment return false } + if x.Addrtaken() { + // If x is address-taken, the RHS may (implicitly) uses LHS. + // Not safe to do a special composite literal assignment + // (which may expand to multiple assignments). + return false + } switch n.Y.Op() { default: @@ -629,7 +635,7 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool { case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) { - // not a special composite literal assignment + // not safe to do a special composite literal assignment if RHS uses LHS. return false } anylit(n.Y, n.X, init) diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go index d1c1dab069..990e085abe 100644 --- a/src/math/big/floatmarsh.go +++ b/src/math/big/floatmarsh.go @@ -8,6 +8,7 @@ package big import ( "encoding/binary" + "errors" "fmt" ) @@ -67,6 +68,9 @@ func (z *Float) GobDecode(buf []byte) error { *z = Float{} return nil } + if len(buf) < 6 { + return errors.New("Float.GobDecode: buffer too small") + } if buf[0] != floatGobVersion { return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0]) @@ -83,6 +87,9 @@ func (z *Float) GobDecode(buf []byte) error { z.prec = binary.BigEndian.Uint32(buf[2:]) if z.form == finite { + if len(buf) < 10 { + return errors.New("Float.GobDecode: buffer too small for finite form float") + } z.exp = int32(binary.BigEndian.Uint32(buf[6:])) z.mant = z.mant.setBytes(buf[10:]) } diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go index c056d78b80..401f45a51f 100644 --- a/src/math/big/floatmarsh_test.go +++ b/src/math/big/floatmarsh_test.go @@ -137,3 +137,15 @@ func TestFloatJSONEncoding(t *testing.T) { } } } + +func TestFloatGobDecodeShortBuffer(t *testing.T) { + for _, tc := range [][]byte{ + []byte{0x1, 0x0, 0x0, 0x0}, + []byte{0x1, 0xfa, 0x0, 0x0, 0x0, 0x0}, + } { + err := NewFloat(0).GobDecode(tc) + if err == nil { + t.Error("expected GobDecode to return error for malformed input") + } + } +} diff --git a/src/math/big/ratmarsh.go b/src/math/big/ratmarsh.go index fbc7b6002d..56102e845b 100644 --- a/src/math/big/ratmarsh.go +++ b/src/math/big/ratmarsh.go @@ -45,12 +45,18 @@ func (z *Rat) GobDecode(buf []byte) error { *z = Rat{} return nil } + if len(buf) < 5 { + return errors.New("Rat.GobDecode: buffer too small") + } b := buf[0] if b>>1 != ratGobVersion { return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) } const j = 1 + 4 i := j + binary.BigEndian.Uint32(buf[j-4:j]) + if len(buf) < int(i) { + return errors.New("Rat.GobDecode: buffer too small") + } z.a.neg = b&1 != 0 z.a.abs = z.a.abs.setBytes(buf[j:i]) z.b.abs = z.b.abs.setBytes(buf[i:]) diff --git a/src/math/big/ratmarsh_test.go b/src/math/big/ratmarsh_test.go index 351d109f8d..55a9878bb8 100644 --- a/src/math/big/ratmarsh_test.go +++ b/src/math/big/ratmarsh_test.go @@ -123,3 +123,15 @@ func TestRatXMLEncoding(t *testing.T) { } } } + +func TestRatGobDecodeShortBuffer(t *testing.T) { + for _, tc := range [][]byte{ + []byte{0x2}, + []byte{0x2, 0x0, 0x0, 0x0, 0xff}, + } { + err := NewRat(1, 2).GobDecode(tc) + if err == nil { + t.Error("expected GobDecode to return error for malformed input") + } + } +} diff --git a/src/runtime/time.go b/src/runtime/time.go index 517a493a70..70e21d4482 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -390,7 +390,11 @@ func dodeltimer(pp *p, i int) int { if i == 0 { updateTimer0When(pp) } - atomic.Xadd(&pp.numTimers, -1) + n := atomic.Xadd(&pp.numTimers, -1) + if n == 0 { + // If there are no timers, then clearly none are modified. + atomic.Store64(&pp.timerModifiedEarliest, 0) + } return smallestChanged } @@ -414,7 +418,11 @@ func dodeltimer0(pp *p) { siftdownTimer(pp.timers, 0) } updateTimer0When(pp) - atomic.Xadd(&pp.numTimers, -1) + n := atomic.Xadd(&pp.numTimers, -1) + if n == 0 { + // If there are no timers, then clearly none are modified. + atomic.Store64(&pp.timerModifiedEarliest, 0) + } } // modtimer modifies an existing timer. diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 814c323634..de593491a1 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -116,6 +116,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in } waspanic := false cgoCtxt := gp.cgoCtxt + stack := gp.stack printing := pcbuf == nil && callback == nil // If the PC is zero, it's likely a nil function call. @@ -134,7 +135,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in if !f.valid() { if callback != nil || printing { print("runtime: unknown pc ", hex(frame.pc), "\n") - tracebackHexdump(gp.stack, &frame, 0) + tracebackHexdump(stack, &frame, 0) } if callback != nil { throw("unknown pc") @@ -194,12 +195,15 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in frame.fn = findfunc(frame.pc) f = frame.fn flag = f.flag + frame.lr = gp.m.curg.sched.lr frame.sp = gp.m.curg.sched.sp + stack = gp.m.curg.stack cgoCtxt = gp.m.curg.cgoCtxt case funcID_systemstack: // systemstack returns normally, so just follow the // stack transition. frame.sp = gp.m.curg.sched.sp + stack = gp.m.curg.stack cgoCtxt = gp.m.curg.cgoCtxt flag &^= funcFlag_SPWRITE } @@ -268,7 +272,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in } if callback != nil || doPrint { print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n") - tracebackHexdump(gp.stack, &frame, lrPtr) + tracebackHexdump(stack, &frame, lrPtr) } if callback != nil { throw("unknown caller pc") @@ -497,6 +501,13 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in break } + if frame.pc == frame.lr && frame.sp == frame.fp { + // If the next frame is identical to the current frame, we cannot make progress. + print("runtime: traceback stuck. pc=", hex(frame.pc), " sp=", hex(frame.sp), "\n") + tracebackHexdump(stack, &frame, frame.sp) + throw("traceback stuck") + } + // Unwind to next frame. frame.fn = flr frame.pc = frame.lr diff --git a/test/fixedbugs/issue52953.go b/test/fixedbugs/issue52953.go new file mode 100644 index 0000000000..2085e4e3fe --- /dev/null +++ b/test/fixedbugs/issue52953.go @@ -0,0 +1,29 @@ +// run + +// Copyright 2022 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. + +// Issue 52953: miscompilation for composite literal assignment +// when LHS is address-taken. + +package main + +type T struct { + Field1 bool +} + +func main() { + var ret T + ret.Field1 = true + var v *bool = &ret.Field1 + ret = T{Field1: *v} + check(ret.Field1) +} + +//go:noinline +func check(b bool) { + if !b { + panic("FAIL") + } +} diff --git a/test/fixedbugs/issue53600.go b/test/fixedbugs/issue53600.go new file mode 100644 index 0000000000..fd3a9e5e47 --- /dev/null +++ b/test/fixedbugs/issue53600.go @@ -0,0 +1,42 @@ +// run + +// Copyright 2022 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 + +import "math" + +func main() { + f() + g() + h() +} +func f() { + for i := int64(math.MaxInt64); i <= math.MaxInt64; i++ { + if i < 0 { + println("done") + return + } + println(i, i < 0) + } +} +func g() { + for i := int64(math.MaxInt64) - 1; i <= math.MaxInt64; i++ { + if i < 0 { + println("done") + return + } + println(i, i < 0) + } +} +func h() { + for i := int64(math.MaxInt64) - 2; i <= math.MaxInt64; i += 2 { + if i < 0 { + println("done") + return + } + println(i, i < 0) + } +} diff --git a/test/fixedbugs/issue53600.out b/test/fixedbugs/issue53600.out new file mode 100644 index 0000000000..5590c7dcfb --- /dev/null +++ b/test/fixedbugs/issue53600.out @@ -0,0 +1,8 @@ +9223372036854775807 false +done +9223372036854775806 false +9223372036854775807 false +done +9223372036854775805 false +9223372036854775807 false +done