Skip to content

Commit 62cd044

Browse files
committed
cmd/compile: add cases for StringLen to prove
Tricky index-offset logic had been added for slices, but not for strings. This fixes that, and also adds tests for same behavior in string/slice cases, and adds a new test for code in prove that had been added but not explicitly tested. Fixes #76270. Change-Id: Ibd92b89e944d86b7f30b4486a9008e6f1ac6af7d Reviewed-on: https://go-review.googlesource.com/c/go/+/723980 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org>
1 parent f1e376f commit 62cd044

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

src/cmd/compile/internal/ssa/prove.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,14 +2040,14 @@ func (ft *factsTable) flowLimit(v *Value) {
20402040
//
20412041
// slicecap - index >= slicelen - index >= K
20422042
//
2043-
// Note that "index" is not useed for indexing in this pattern, but
2043+
// Note that "index" is not used for indexing in this pattern, but
20442044
// in the motivating example (chunked slice iteration) it is.
20452045
func (ft *factsTable) detectSliceLenRelation(v *Value) {
20462046
if v.Op != OpSub64 {
20472047
return
20482048
}
20492049

2050-
if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpSliceCap) {
2050+
if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpStringLen || v.Args[0].Op == OpSliceCap) {
20512051
return
20522052
}
20532053

@@ -2070,9 +2070,9 @@ func (ft *factsTable) detectSliceLenRelation(v *Value) {
20702070
continue
20712071
}
20722072
var lenOffset *Value
2073-
if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
2073+
if bound := ow.Args[0]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
20742074
lenOffset = ow.Args[1]
2075-
} else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
2075+
} else if bound := ow.Args[1]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
20762076
lenOffset = ow.Args[0]
20772077
}
20782078
if lenOffset == nil || lenOffset.Op != OpConst64 {
@@ -2332,7 +2332,7 @@ func unsignedSubUnderflows(a, b uint64) bool {
23322332
// iteration where the index is not directly compared to the length.
23332333
// if isReslice, then delta can be equal to K.
23342334
func checkForChunkedIndexBounds(ft *factsTable, b *Block, index, bound *Value, isReslice bool) bool {
2335-
if bound.Op != OpSliceLen && bound.Op != OpSliceCap {
2335+
if bound.Op != OpSliceLen && bound.Op != OpStringLen && bound.Op != OpSliceCap {
23362336
return false
23372337
}
23382338

@@ -2367,9 +2367,9 @@ func checkForChunkedIndexBounds(ft *factsTable, b *Block, index, bound *Value, i
23672367
}
23682368
if ow := o.w; ow.Op == OpAdd64 {
23692369
var lenOffset *Value
2370-
if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
2370+
if bound := ow.Args[0]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
23712371
lenOffset = ow.Args[1]
2372-
} else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
2372+
} else if bound := ow.Args[1]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
23732373
lenOffset = ow.Args[0]
23742374
}
23752375
if lenOffset == nil || lenOffset.Op != OpConst64 {

test/loopbce.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ func nobce2(a string) {
420420
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
421421
}
422422
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
423-
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
423+
useString(a[i:]) // ERROR "Proved IsSliceInBounds$" "Proved slicemask not needed"
424424
}
425425
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Disproved Less64$" "Induction variable: limits \[0,\?\), increment 1$"
426426
useString(a[i:])

test/prove.go

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2659,14 +2659,63 @@ func subLengths2(b []byte, i int) {
26592659
}
26602660

26612661
func issue76355(s []int, i int) int {
2662-
var a [10]int
2663-
if i <= len(s)-1 {
2664-
v := len(s) - i
2665-
if v < 10 {
2666-
return a[v]
2667-
}
2668-
}
2669-
return 0
2662+
var a [10]int
2663+
if i <= len(s)-1 {
2664+
v := len(s) - i
2665+
if v < 10 {
2666+
return a[v]
2667+
}
2668+
}
2669+
return 0
2670+
}
2671+
2672+
func stringDotDotDot(s string) bool {
2673+
for i := 0; i < len(s)-2; i++ { // ERROR "Induction variable: limits \[0,[?][)], increment 1"
2674+
if s[i] == '.' && // ERROR "Proved IsInBounds"
2675+
s[i+1] == '.' && // ERROR "Proved IsInBounds"
2676+
s[i+2] == '.' { // ERROR "Proved IsInBounds"
2677+
return true
2678+
}
2679+
}
2680+
return false
2681+
}
2682+
2683+
func bytesDotDotDot(s []byte) bool {
2684+
for i := 0; i < len(s)-2; i++ { // ERROR "Induction variable"
2685+
if s[i] == '.' && // ERROR "Proved IsInBounds"
2686+
s[i+1] == '.' && // ERROR "Proved IsInBounds"
2687+
s[i+2] == '.' { // ERROR "Proved IsInBounds"
2688+
return true
2689+
}
2690+
}
2691+
return false
2692+
}
2693+
2694+
// detectSliceLenRelation matches the pattern where
2695+
// 1. v := slicelen - index, OR v := slicecap - index
2696+
// AND
2697+
// 2. index <= slicelen - K
2698+
// THEN
2699+
//
2700+
// slicecap - index >= slicelen - index >= K
2701+
func detectSliceLenRelation(s []byte) bool {
2702+
for i := 0; i <= len(s)-3; i++ { // ERROR "Induction variable"
2703+
v := len(s) - i
2704+
if v >= 3 { // ERROR "Proved Leq"
2705+
return true
2706+
}
2707+
}
2708+
return false
2709+
}
2710+
2711+
func detectStringLenRelation(s string) bool {
2712+
for i := 0; i <= len(s)-3; i++ { // ERROR "Induction variable"
2713+
v := len(s) - i
2714+
if v >= 3 { // ERROR "Proved Leq"
2715+
return true
2716+
}
2717+
}
2718+
return false
26702719
}
26712720

26722721
//go:noinline

0 commit comments

Comments
 (0)