]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.14] cmd/compile: fix checkptr handling of &^
authorMatthew Dempsky <mdempsky@google.com>
Thu, 20 Aug 2020 04:39:12 +0000 (21:39 -0700)
committerDmitri Shuralyov <dmitshur@golang.org>
Fri, 21 Aug 2020 23:45:28 +0000 (23:45 +0000)
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 #40968.

Change-Id: I386304171ad299c530e151e5924f179e9a5fd5b8
Reviewed-on: https://go-review.googlesource.com/c/go/+/249477
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/249838
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/walk.go
src/runtime/checkptr_test.go
src/runtime/testdata/testprog/checkptr.go
test/fixedbugs/issue40917.go [new file with mode: 0644]

index de187959fde5169f4d9aa6527e3779560ad3f28b..8bad47d62b8205bcfa8707baace1f913d0904990 100644 (file)
@@ -141,8 +141,8 @@ const (
        nodeInitorder, _                   // tracks state during init1; two bits
        _, _                               // second nodeInitorder bit
        _, nodeHasBreak
-       _, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
-       _, nodeImplicit
+       _, nodeNoInline  // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
+       _, nodeImplicit  // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
        _, nodeIsDDD     // is the argument variadic
        _, nodeDiag      // already printed error about this
        _, nodeColas     // OAS resulting from :=
index b8b954c4fc117425fa846762a3744bf3d02c14da..483f338f0e9ba2f461465182efaf10cfde3803b0 100644 (file)
@@ -984,6 +984,7 @@ opswitch:
        case OANDNOT:
                n.Left = walkexpr(n.Left, init)
                n.Op = OAND
+               n.SetImplicit(true) // for walkCheckPtrArithmetic
                n.Right = nod(OBITNOT, n.Right, nil)
                n.Right = typecheck(n.Right, ctxExpr)
                n.Right = walkexpr(n.Right, init)
@@ -4056,8 +4057,12 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
                case OADD:
                        walk(n.Left)
                        walk(n.Right)
-               case OSUB, OANDNOT:
+               case OSUB:
                        walk(n.Left)
+               case OAND:
+                       if n.Implicit() { // was OANDNOT
+                               walk(n.Left)
+                       }
                case OCONVNOP:
                        if n.Left.Type.Etype == TUNSAFEPTR {
                                n.Left = cheapexpr(n.Left, init)
index 624f1b62d2f2454d8aab514b72257ebcfbe2b45f..8887254e93b8f63b0fde31ecd3674d83a0f42246 100644 (file)
@@ -27,6 +27,7 @@ func TestCheckPtr(t *testing.T) {
                {"CheckPtrAlignmentPtr", "fatal error: checkptr: unsafe pointer conversion\n"},
                {"CheckPtrAlignmentNoPtr", ""},
                {"CheckPtrArithmetic", "fatal error: checkptr: unsafe pointer arithmetic\n"},
+               {"CheckPtrArithmetic2", "fatal error: checkptr: unsafe pointer arithmetic\n"},
                {"CheckPtrSize", "fatal error: checkptr: unsafe pointer conversion\n"},
                {"CheckPtrSmall", "fatal error: checkptr: unsafe pointer arithmetic\n"},
        }
index 45e6fb1aa53f6c463ad7a8196439505372a00526..e0a2794f4c1da108a7883285a20526e3738bebed 100644 (file)
@@ -10,6 +10,7 @@ func init() {
        register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr)
        register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr)
        register("CheckPtrArithmetic", CheckPtrArithmetic)
+       register("CheckPtrArithmetic2", CheckPtrArithmetic2)
        register("CheckPtrSize", CheckPtrSize)
        register("CheckPtrSmall", CheckPtrSmall)
 }
@@ -32,6 +33,13 @@ func CheckPtrArithmetic() {
        sink2 = (*int)(unsafe.Pointer(i))
 }
 
+func CheckPtrArithmetic2() {
+       var x [2]int64
+       p := unsafe.Pointer(&x[1])
+       var one uintptr = 1
+       sink2 = unsafe.Pointer(uintptr(p) & ^one)
+}
+
 func CheckPtrSize() {
        p := new(int64)
        sink2 = p
diff --git a/test/fixedbugs/issue40917.go b/test/fixedbugs/issue40917.go
new file mode 100644 (file)
index 0000000..2128be5
--- /dev/null
@@ -0,0 +1,23 @@
+// run -gcflags=-d=checkptr
+
+// 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 main
+
+import "unsafe"
+
+func main() {
+       var x [2]uint64
+       a := unsafe.Pointer(&x[1])
+
+       b := a
+       b = unsafe.Pointer(uintptr(b) + 2)
+       b = unsafe.Pointer(uintptr(b) - 1)
+       b = unsafe.Pointer(uintptr(b) &^ 1)
+
+       if a != b {
+               panic("pointer arithmetic failed")
+       }
+}