@@ -3573,16 +3573,14 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
35733573 bound := n .X .Type ().NumElem ()
35743574 a := s .expr (n .X )
35753575 i := s .expr (n .Index )
3576+ len := s .constInt (types .Types [types .TINT ], bound )
35763577 if bound == 0 {
3577- // Bounds check will never succeed. Might as well
3578- // use constants for the bounds check.
3579- z := s .constInt (types .Types [types .TINT ], 0 )
3580- s .boundsCheck (z , z , ssa .BoundsIndex , false )
3578+ // Bounds check will never succeed.
3579+ s .boundsCheck (i , len , ssa .BoundsIndex , false )
35813580 // The return value won't be live. In case bounds checks
35823581 // are turned off, load from (*T)(nil) to cause a segfault.
35833582 return s .load (n .Type (), s .constNil (n .Type ().PtrTo ()))
35843583 }
3585- len := s .constInt (types .Types [types .TINT ], bound )
35863584 s .boundsCheck (i , len , ssa .BoundsIndex , n .Bounded ()) // checks i == 0
35873585 return s .newValue1I (ssa .OpArraySelect , n .Type (), 0 , a )
35883586 }
@@ -4545,12 +4543,21 @@ func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool
45454543
45464544 i := s .expr (left .Index ) // index
45474545 if n == 0 {
4546+ _ = s .expr (left .X ) // Evaluating left.X for any side-effects.
45484547 // The bounds check must fail. Might as well
45494548 // ignore the actual index and just use zeros.
45504549 z := s .constInt (types .Types [types .TINT ], 0 )
45514550 s .boundsCheck (z , z , ssa .BoundsIndex , false )
45524551 return
45534552 }
4553+ if t .Size () == 0 {
4554+ _ = s .expr (left .X ) // Evaluating left.X for any side-effects.
4555+ // Generate bounds check for left, since this can happen
4556+ // for 0-size assignment case, see issue #79236.
4557+ len := s .constInt (types .Types [types .TINT ], n )
4558+ s .boundsCheck (i , len , ssa .BoundsIndex , false )
4559+ return
4560+ }
45544561 if n != 1 {
45554562 // This can happen in weird, always-panics cases, like:
45564563 // var x [0][2]int
@@ -4560,11 +4567,8 @@ func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool
45604567 // they are somewhere inside an outer [0].
45614568 // We can ignore the actual assignment, it is dynamically
45624569 // unreachable. See issue 77635.
4563- return
4564- }
4565- if t .Size () == 0 {
4566- len := s .constInt (types .Types [types .TINT ], n )
4567- s .boundsCheck (i , len , ssa .BoundsIndex , false )
4570+ // Still, evaluating left.X for any side-effects.
4571+ _ = s .expr (left .X )
45684572 return
45694573 }
45704574
@@ -5276,6 +5280,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
52765280 // &x[i], which will always panic when evaluated.
52775281 // We just return something reasonable in this case.
52785282 // It will be dynamically unreachable. See issue 77635.
5283+ s .boundsCheckArrayIndex (n )
52795284 return s .newValue1A (ssa .OpAddr , n .Type ().PtrTo (), ir .Syms .Zerobase , s .sb )
52805285 }
52815286
@@ -5458,6 +5463,21 @@ func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value {
54585463 return s .newValue2 (ssa .OpNilCheck , ptr .Type , ptr , s .mem ())
54595464}
54605465
5466+ // boundsCheckArrayIndex generates bounds checking code for array indexing operations.
5467+ func (s * state ) boundsCheckArrayIndex (n ir.Node ) {
5468+ if n .Op () != ir .OINDEX {
5469+ return
5470+ }
5471+ nn := n .(* ir.IndexExpr )
5472+ typ := nn .X .Type ()
5473+ if typ .IsArray () {
5474+ _ = s .expr (nn .X ) // for side effects
5475+ idx := s .expr (nn .Index )
5476+ len := s .constInt (types .Types [types .TINT ], typ .NumElem ())
5477+ s .boundsCheck (idx , len , ssa .BoundsIndex , nn .Bounded ())
5478+ }
5479+ }
5480+
54615481// boundsCheck generates bounds checking code. Checks if 0 <= idx <[=] len, branches to exit if not.
54625482// Starts a new block on return.
54635483// On input, len must be converted to full int width and be nonnegative.
0 commit comments