mirror of
https://github.com/golang/go
synced 2024-11-14 21:10:29 -07:00
[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 <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>
(cherry picked from commit e94544cf01
)
Reviewed-on: https://go-review.googlesource.com/c/go/+/249879
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
f2b7109989
commit
f454f70344
@ -141,8 +141,8 @@ const (
|
|||||||
nodeInitorder, _ // tracks state during init1; two bits
|
nodeInitorder, _ // tracks state during init1; two bits
|
||||||
_, _ // second nodeInitorder bit
|
_, _ // second nodeInitorder bit
|
||||||
_, nodeHasBreak
|
_, nodeHasBreak
|
||||||
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
||||||
_, nodeImplicit
|
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
|
||||||
_, nodeIsDDD // is the argument variadic
|
_, nodeIsDDD // is the argument variadic
|
||||||
_, nodeDiag // already printed error about this
|
_, nodeDiag // already printed error about this
|
||||||
_, nodeColas // OAS resulting from :=
|
_, nodeColas // OAS resulting from :=
|
||||||
|
@ -968,6 +968,7 @@ opswitch:
|
|||||||
case OANDNOT:
|
case OANDNOT:
|
||||||
n.Left = walkexpr(n.Left, init)
|
n.Left = walkexpr(n.Left, init)
|
||||||
n.Op = OAND
|
n.Op = OAND
|
||||||
|
n.SetImplicit(true) // for walkCheckPtrArithmetic
|
||||||
n.Right = nod(OBITNOT, n.Right, nil)
|
n.Right = nod(OBITNOT, n.Right, nil)
|
||||||
n.Right = typecheck(n.Right, ctxExpr)
|
n.Right = typecheck(n.Right, ctxExpr)
|
||||||
n.Right = walkexpr(n.Right, init)
|
n.Right = walkexpr(n.Right, init)
|
||||||
@ -3993,8 +3994,12 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
|
|||||||
case OADD:
|
case OADD:
|
||||||
walk(n.Left)
|
walk(n.Left)
|
||||||
walk(n.Right)
|
walk(n.Right)
|
||||||
case OSUB, OANDNOT:
|
case OSUB:
|
||||||
walk(n.Left)
|
walk(n.Left)
|
||||||
|
case OAND:
|
||||||
|
if n.Implicit() { // was OANDNOT
|
||||||
|
walk(n.Left)
|
||||||
|
}
|
||||||
case OCONVNOP:
|
case OCONVNOP:
|
||||||
if n.Left.Type.Etype == TUNSAFEPTR {
|
if n.Left.Type.Etype == TUNSAFEPTR {
|
||||||
n.Left = cheapexpr(n.Left, init)
|
n.Left = cheapexpr(n.Left, init)
|
||||||
|
@ -27,6 +27,7 @@ func TestCheckPtr(t *testing.T) {
|
|||||||
{"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"},
|
{"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"},
|
||||||
{"CheckPtrAlignmentNoPtr", ""},
|
{"CheckPtrAlignmentNoPtr", ""},
|
||||||
{"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
|
{"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
|
||||||
|
{"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
|
||||||
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
|
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},
|
||||||
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
|
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
|
||||||
}
|
}
|
||||||
|
8
src/runtime/testdata/testprog/checkptr.go
vendored
8
src/runtime/testdata/testprog/checkptr.go
vendored
@ -10,6 +10,7 @@ func init() {
|
|||||||
register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr)
|
register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr)
|
||||||
register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr)
|
register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr)
|
||||||
register("CheckPtrArithmetic", CheckPtrArithmetic)
|
register("CheckPtrArithmetic", CheckPtrArithmetic)
|
||||||
|
register("CheckPtrArithmetic2", CheckPtrArithmetic2)
|
||||||
register("CheckPtrSize", CheckPtrSize)
|
register("CheckPtrSize", CheckPtrSize)
|
||||||
register("CheckPtrSmall", CheckPtrSmall)
|
register("CheckPtrSmall", CheckPtrSmall)
|
||||||
}
|
}
|
||||||
@ -32,6 +33,13 @@ func CheckPtrArithmetic() {
|
|||||||
sink2 = (*int)(unsafe.Pointer(i))
|
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() {
|
func CheckPtrSize() {
|
||||||
p := new(int64)
|
p := new(int64)
|
||||||
sink2 = p
|
sink2 = p
|
||||||
|
23
test/fixedbugs/issue40917.go
Normal file
23
test/fixedbugs/issue40917.go
Normal file
@ -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")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user