//
// slicecap - index >= slicelen - index >= K
//
-// Note that "index" is not useed for indexing in this pattern, but
+// Note that "index" is not used for indexing in this pattern, but
// in the motivating example (chunked slice iteration) it is.
func (ft *factsTable) detectSliceLenRelation(v *Value) {
if v.Op != OpSub64 {
return
}
- if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpSliceCap) {
+ if !(v.Args[0].Op == OpSliceLen || v.Args[0].Op == OpStringLen || v.Args[0].Op == OpSliceCap) {
return
}
continue
}
var lenOffset *Value
- if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
+ if bound := ow.Args[0]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
lenOffset = ow.Args[1]
- } else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
+ } else if bound := ow.Args[1]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
lenOffset = ow.Args[0]
}
if lenOffset == nil || lenOffset.Op != OpConst64 {
// iteration where the index is not directly compared to the length.
// if isReslice, then delta can be equal to K.
func checkForChunkedIndexBounds(ft *factsTable, b *Block, index, bound *Value, isReslice bool) bool {
- if bound.Op != OpSliceLen && bound.Op != OpSliceCap {
+ if bound.Op != OpSliceLen && bound.Op != OpStringLen && bound.Op != OpSliceCap {
return false
}
}
if ow := o.w; ow.Op == OpAdd64 {
var lenOffset *Value
- if bound := ow.Args[0]; bound.Op == OpSliceLen && bound.Args[0] == slice {
+ if bound := ow.Args[0]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
lenOffset = ow.Args[1]
- } else if bound := ow.Args[1]; bound.Op == OpSliceLen && bound.Args[0] == slice {
+ } else if bound := ow.Args[1]; (bound.Op == OpSliceLen || bound.Op == OpStringLen) && bound.Args[0] == slice {
lenOffset = ow.Args[0]
}
if lenOffset == nil || lenOffset.Op != OpConst64 {
useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
}
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
- useString(a[i:]) // ERROR "Proved IsSliceInBounds$"
+ useString(a[i:]) // ERROR "Proved IsSliceInBounds$" "Proved slicemask not needed"
}
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Disproved Less64$" "Induction variable: limits \[0,\?\), increment 1$"
useString(a[i:])
}
func issue76355(s []int, i int) int {
- var a [10]int
- if i <= len(s)-1 {
- v := len(s) - i
- if v < 10 {
- return a[v]
- }
- }
- return 0
+ var a [10]int
+ if i <= len(s)-1 {
+ v := len(s) - i
+ if v < 10 {
+ return a[v]
+ }
+ }
+ return 0
+}
+
+func stringDotDotDot(s string) bool {
+ for i := 0; i < len(s)-2; i++ { // ERROR "Induction variable: limits \[0,[?][)], increment 1"
+ if s[i] == '.' && // ERROR "Proved IsInBounds"
+ s[i+1] == '.' && // ERROR "Proved IsInBounds"
+ s[i+2] == '.' { // ERROR "Proved IsInBounds"
+ return true
+ }
+ }
+ return false
+}
+
+func bytesDotDotDot(s []byte) bool {
+ for i := 0; i < len(s)-2; i++ { // ERROR "Induction variable"
+ if s[i] == '.' && // ERROR "Proved IsInBounds"
+ s[i+1] == '.' && // ERROR "Proved IsInBounds"
+ s[i+2] == '.' { // ERROR "Proved IsInBounds"
+ return true
+ }
+ }
+ return false
+}
+
+// detectSliceLenRelation matches the pattern where
+// 1. v := slicelen - index, OR v := slicecap - index
+// AND
+// 2. index <= slicelen - K
+// THEN
+//
+// slicecap - index >= slicelen - index >= K
+func detectSliceLenRelation(s []byte) bool {
+ for i := 0; i <= len(s)-3; i++ { // ERROR "Induction variable"
+ v := len(s) - i
+ if v >= 3 { // ERROR "Proved Leq"
+ return true
+ }
+ }
+ return false
+}
+
+func detectStringLenRelation(s string) bool {
+ for i := 0; i <= len(s)-3; i++ { // ERROR "Induction variable"
+ v := len(s) - i
+ if v >= 3 { // ERROR "Proved Leq"
+ return true
+ }
+ }
+ return false
}
//go:noinline