Skip to content

Commit 7b58581

Browse files
committed
cmd/compile: recognize (*[Big]T)(ptr)[:n:m] pattern for -d=checkptr
A common idiom for turning an unsafe.Pointer into a slice is to write: s := (*[Big]T)(ptr)[:n:m] This technically violates Go's unsafe pointer rules (rule #1 says T2 can't be bigger than T1), but it's fairly common and not too difficult to recognize, so might as well allow it for now so we can make progress on #34972. This should be revisited if #19367 is accepted. Updates #22218. Updates #34972. Change-Id: Id824e2461904e770910b6e728b4234041d2cc8bc Reviewed-on: https://go-review.googlesource.com/c/go/+/201839 Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent dba19c6 commit 7b58581

File tree

4 files changed

+41
-13
lines changed

4 files changed

+41
-13
lines changed

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

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/gc/builtin/runtime.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func racewriterange(addr, size uintptr)
235235
func msanread(addr, size uintptr)
236236
func msanwrite(addr, size uintptr)
237237

238-
func checkptrAlignment(unsafe.Pointer, *byte)
238+
func checkptrAlignment(unsafe.Pointer, *byte, uintptr)
239239
func checkptrArithmetic(unsafe.Pointer, []unsafe.Pointer)
240240

241241
// architecture variants

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

+29-5
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ opswitch:
953953
n.Left = walkexpr(n.Left, init)
954954
if n.Op == OCONVNOP && checkPtr(Curfn, 1) {
955955
if n.Type.IsPtr() && n.Left.Type.Etype == TUNSAFEPTR { // unsafe.Pointer to *T
956-
n = walkCheckPtrAlignment(n, init)
956+
n = walkCheckPtrAlignment(n, init, nil)
957957
break
958958
}
959959
if n.Type.Etype == TUNSAFEPTR && n.Left.Type.Etype == TUINTPTR { // uintptr to unsafe.Pointer
@@ -1120,7 +1120,12 @@ opswitch:
11201120
n.List.SetSecond(walkexpr(n.List.Second(), init))
11211121

11221122
case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
1123-
n.Left = walkexpr(n.Left, init)
1123+
checkSlice := checkPtr(Curfn, 1) && n.Op == OSLICE3ARR && n.Left.Op == OCONVNOP && n.Left.Left.Type.Etype == TUNSAFEPTR
1124+
if checkSlice {
1125+
n.Left.Left = walkexpr(n.Left.Left, init)
1126+
} else {
1127+
n.Left = walkexpr(n.Left, init)
1128+
}
11241129
low, high, max := n.SliceBounds()
11251130
low = walkexpr(low, init)
11261131
if low != nil && isZero(low) {
@@ -1130,6 +1135,9 @@ opswitch:
11301135
high = walkexpr(high, init)
11311136
max = walkexpr(max, init)
11321137
n.SetSliceBounds(low, high, max)
1138+
if checkSlice {
1139+
n.Left = walkCheckPtrAlignment(n.Left, init, max)
1140+
}
11331141
if n.Op.IsSlice3() {
11341142
if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
11351143
// Reduce x[i:j:cap(x)] to x[i:j].
@@ -3912,13 +3920,29 @@ func isRuneCount(n *Node) bool {
39123920
return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
39133921
}
39143922

3915-
func walkCheckPtrAlignment(n *Node, init *Nodes) *Node {
3916-
if n.Type.Elem().Alignment() == 1 && n.Type.Elem().Size() == 1 {
3923+
func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {
3924+
if !n.Type.IsPtr() {
3925+
Fatalf("expected pointer type: %v", n.Type)
3926+
}
3927+
elem := n.Type.Elem()
3928+
if count != nil {
3929+
if !elem.IsArray() {
3930+
Fatalf("expected array type: %v", elem)
3931+
}
3932+
elem = elem.Elem()
3933+
}
3934+
3935+
size := elem.Size()
3936+
if elem.Alignment() == 1 && (size == 0 || size == 1 && count == nil) {
39173937
return n
39183938
}
39193939

3940+
if count == nil {
3941+
count = nodintconst(1)
3942+
}
3943+
39203944
n.Left = cheapexpr(n.Left, init)
3921-
init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.Left, types.Types[TUNSAFEPTR]), typename(n.Type.Elem())))
3945+
init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.Left, types.Types[TUNSAFEPTR]), typename(elem), conv(count, types.Types[TUINTPTR])))
39223946
return n
39233947
}
39243948

src/runtime/checkptr.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@ import "unsafe"
99
type ptrAlign struct {
1010
ptr unsafe.Pointer
1111
elem *_type
12+
n uintptr
1213
}
1314

14-
func checkptrAlignment(p unsafe.Pointer, elem *_type) {
15-
// Check that (*T)(p) is appropriately aligned.
15+
func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
16+
// Check that (*[n]elem)(p) is appropriately aligned.
1617
// TODO(mdempsky): What about fieldAlign?
1718
if uintptr(p)&(uintptr(elem.align)-1) != 0 {
18-
panic(ptrAlign{p, elem})
19+
panic(ptrAlign{p, elem, n})
1920
}
2021

21-
// Check that (*T)(p) doesn't straddle multiple heap objects.
22-
if elem.size != 1 && checkptrBase(p) != checkptrBase(add(p, elem.size-1)) {
23-
panic(ptrAlign{p, elem})
22+
// Check that (*[n]elem)(p) doesn't straddle multiple heap objects.
23+
if size := n * elem.size; size > 1 && checkptrBase(p) != checkptrBase(add(p, size-1)) {
24+
panic(ptrAlign{p, elem, n})
2425
}
2526
}
2627

@@ -34,6 +35,9 @@ func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) {
3435
panic(ptrArith{p, originals})
3536
}
3637

38+
// Check that if the computed pointer p points into a heap
39+
// object, then one of the original pointers must have pointed
40+
// into the same object.
3741
base := checkptrBase(p)
3842
if base == 0 {
3943
return

0 commit comments

Comments
 (0)