cmd/compile: ensure we evaluate side effects of len() arg

For any len() which requires the evaluation of its arg (according to the spec).

Update #72844

Change-Id: Id2b0bcc78073a6d5051abd000131dafdf65e7f26
Reviewed-on: https://go-review.googlesource.com/c/go/+/658097
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
Keith Randall 2025-03-14 13:36:58 -07:00
parent 8af32240c6
commit 336626bac4
3 changed files with 22 additions and 12 deletions

View File

@ -3469,19 +3469,28 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
case ir.OLEN, ir.OCAP: case ir.OLEN, ir.OCAP:
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
// Note: all constant cases are handled by the frontend. If len or cap
// makes it here, we want the side effects of the argument. See issue 72844.
a := s.expr(n.X)
t := n.X.Type()
switch { switch {
case n.X.Type().IsSlice(): case t.IsSlice():
op := ssa.OpSliceLen op := ssa.OpSliceLen
if n.Op() == ir.OCAP { if n.Op() == ir.OCAP {
op = ssa.OpSliceCap op = ssa.OpSliceCap
} }
return s.newValue1(op, types.Types[types.TINT], s.expr(n.X)) return s.newValue1(op, types.Types[types.TINT], a)
case n.X.Type().IsString(): // string; not reachable for OCAP case t.IsString(): // string; not reachable for OCAP
return s.newValue1(ssa.OpStringLen, types.Types[types.TINT], s.expr(n.X)) return s.newValue1(ssa.OpStringLen, types.Types[types.TINT], a)
case n.X.Type().IsMap(), n.X.Type().IsChan(): case t.IsMap(), t.IsChan():
return s.referenceTypeBuiltin(n, s.expr(n.X)) return s.referenceTypeBuiltin(n, a)
default: // array case t.IsArray():
return s.constInt(types.Types[types.TINT], n.X.Type().NumElem()) return s.constInt(types.Types[types.TINT], t.NumElem())
case t.IsPtr() && t.Elem().IsArray():
return s.constInt(types.Types[types.TINT], t.Elem().NumElem())
default:
s.Fatalf("bad type in len/cap: %v", t)
return nil
} }
case ir.OSPTR: case ir.OSPTR:

View File

@ -278,12 +278,13 @@ func walkLenCap(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
// replace len(*[10]int) with 10. // replace len(*[10]int) with 10.
// delayed until now to preserve side effects. // delayed until now to preserve side effects.
t := n.X.Type() t := n.X.Type()
if t.IsPtr() { if t.IsPtr() {
t = t.Elem() t = t.Elem()
} }
if t.IsArray() { if t.IsArray() {
safeExpr(n.X, init) // evaluate any side effects in n.X. See issue 72844.
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.BlankNode, n.X))
con := ir.NewConstExpr(constant.MakeInt64(t.NumElem()), n) con := ir.NewConstExpr(constant.MakeInt64(t.NumElem()), n)
con.SetTypecheck(1) con.SetTypecheck(1)
return con return con

View File

@ -47,11 +47,11 @@ func testRange4() {
} }
func main() { func main() {
//shouldPanic(testLen1) shouldPanic(testLen1)
shouldNotPanic(testLen2) shouldNotPanic(testLen2)
shouldNotPanic(testLen3) shouldNotPanic(testLen3)
shouldNotPanic(testLen4) shouldNotPanic(testLen4)
//shouldPanic(testRange1) shouldPanic(testRange1)
shouldNotPanic(testRange2) shouldNotPanic(testRange2)
shouldNotPanic(testRange3) shouldNotPanic(testRange3)
shouldNotPanic(testRange4) shouldNotPanic(testRange4)