Skip to content

Commit f454f70

Browse files
mdempskydmitshur
authored andcommitted
[release-branch.go1.15] cmd/compile: fix checkptr handling of &^
checkptr has code to recognize &^ expressions, but it didn't take into account that "p &^ x" gets rewritten to "p & ^x" during walk, which resulted in false positive diagnostics. This CL changes walkexpr to mark OANDNOT expressions with Implicit when they're rewritten to OAND, so that walkCheckPtrArithmetic can still recognize them later. It would be slightly more idiomatic to instead mark the OBITNOT expression as Implicit (as it's a compiler-generated Node), but the OBITNOT expression might get constant folded. It's not worth the extra complexity/subtlety of relying on n.Right.Orig, so we set Implicit on the OAND node instead. To atone for this transgression, I add documentation for nodeImplicit. Updates #40917. Fixes #40934. Change-Id: I386304171ad299c530e151e5924f179e9a5fd5b8 Reviewed-on: https://go-review.googlesource.com/c/go/+/249477 Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> (cherry picked from commit e94544c) Reviewed-on: https://go-review.googlesource.com/c/go/+/249879 Run-TryBot: Dmitri Shuralyov <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent f2b7109 commit f454f70

File tree

5 files changed

+40
-3
lines changed

5 files changed

+40
-3
lines changed

src/cmd/compile/internal/gc/syntax.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ const (
141141
nodeInitorder, _ // tracks state during init1; two bits
142142
_, _ // second nodeInitorder bit
143143
_, nodeHasBreak
144-
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
145-
_, nodeImplicit
144+
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
145+
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
146146
_, nodeIsDDD // is the argument variadic
147147
_, nodeDiag // already printed error about this
148148
_, nodeColas // OAS resulting from :=

src/cmd/compile/internal/gc/walk.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,7 @@ opswitch:
968968
case OANDNOT:
969969
n.Left = walkexpr(n.Left, init)
970970
n.Op = OAND
971+
n.SetImplicit(true) // for walkCheckPtrArithmetic
971972
n.Right = nod(OBITNOT, n.Right, nil)
972973
n.Right = typecheck(n.Right, ctxExpr)
973974
n.Right = walkexpr(n.Right, init)
@@ -3993,8 +3994,12 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
39933994
case OADD:
39943995
walk(n.Left)
39953996
walk(n.Right)
3996-
case OSUB, OANDNOT:
3997+
case OSUB:
39973998
walk(n.Left)
3999+
case OAND:
4000+
if n.Implicit() { // was OANDNOT
4001+
walk(n.Left)
4002+
}
39984003
case OCONVNOP:
39994004
if n.Left.Type.Etype == TUNSAFEPTR {
40004005
n.Left = cheapexpr(n.Left, init)

src/runtime/checkptr_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func TestCheckPtr(t *testing.T) {
2727
{"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"},
2828
{"CheckPtrAlignmentNoPtr", ""},
2929
{"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
30+
{"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
3031
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
3132
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
3233
}

src/runtime/testdata/testprog/checkptr.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ func init() {
1010
register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr)
1111
register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr)
1212
register("CheckPtrArithmetic", CheckPtrArithmetic)
13+
register("CheckPtrArithmetic2", CheckPtrArithmetic2)
1314
register("CheckPtrSize", CheckPtrSize)
1415
register("CheckPtrSmall", CheckPtrSmall)
1516
}
@@ -32,6 +33,13 @@ func CheckPtrArithmetic() {
3233
sink2 = (*int)(unsafe.Pointer(i))
3334
}
3435

36+
func CheckPtrArithmetic2() {
37+
var x [2]int64
38+
p := unsafe.Pointer(&x[1])
39+
var one uintptr = 1
40+
sink2 = unsafe.Pointer(uintptr(p) & ^one)
41+
}
42+
3543
func CheckPtrSize() {
3644
p := new(int64)
3745
sink2 = p

test/fixedbugs/issue40917.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// run -gcflags=-d=checkptr
2+
3+
// Copyright 2020 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import "unsafe"
10+
11+
func main() {
12+
var x [2]uint64
13+
a := unsafe.Pointer(&x[1])
14+
15+
b := a
16+
b = unsafe.Pointer(uintptr(b) + 2)
17+
b = unsafe.Pointer(uintptr(b) - 1)
18+
b = unsafe.Pointer(uintptr(b) &^ 1)
19+
20+
if a != b {
21+
panic("pointer arithmetic failed")
22+
}
23+
}

0 commit comments

Comments
 (0)