proc: if a reslice operator is used load the whole slice (#3623)

When the users uses a reslice operation load the whole resliced
variable, ignoring the MaxArrayValues setting.
Only apply this when the 'high' part is specified and a literal and the
'low' part is either unspecified or a literal.

Fixes #3600
This commit is contained in:
Alessandro Arzilli 2024-01-24 18:21:59 +01:00 committed by GitHub
parent ef20fbbf12
commit 6cd0b70b30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 27 additions and 11 deletions

@ -1904,7 +1904,7 @@ func (scope *EvalScope) evalReslice(op *evalop.Reslice, stack *evalStack) {
stack.err = fmt.Errorf("can not slice %q", exprToString(op.Node.X))
return
}
stack.pushErr(xev.reslice(low, high))
stack.pushErr(xev.reslice(low, high, op.TrustLen))
return
case reflect.Map:
if op.Node.High != nil {
@ -1921,7 +1921,7 @@ func (scope *EvalScope) evalReslice(op *evalop.Reslice, stack *evalStack) {
return
case reflect.Ptr:
if xev.Flags&VariableCPtr != 0 {
stack.pushErr(xev.reslice(low, high))
stack.pushErr(xev.reslice(low, high, op.TrustLen))
return
}
fallthrough
@ -2550,7 +2550,7 @@ func (v *Variable) LoadResliced(start int, cfg LoadConfig) (newV *Variable, err
if high > v.Len {
high = v.Len
}
newV, err = v.reslice(low, high)
newV, err = v.reslice(low, high, false)
if err != nil {
return nil, err
}
@ -2566,7 +2566,7 @@ func (v *Variable) LoadResliced(start int, cfg LoadConfig) (newV *Variable, err
return newV, nil
}
func (v *Variable) reslice(low int64, high int64) (*Variable, error) {
func (v *Variable) reslice(low int64, high int64, trustLen bool) (*Variable, error) {
wrong := false
cptrNeedsFakeSlice := false
if v.Flags&VariableCPtr == 0 {
@ -2606,6 +2606,9 @@ func (v *Variable) reslice(low int64, high int64) (*Variable, error) {
r.stride = v.stride
r.fieldType = v.fieldType
r.Flags = v.Flags
if trustLen {
r.Flags |= variableTrustLen
}
r.reg = v.reg
return r, nil

@ -483,6 +483,7 @@ func (ctx *compileCtx) compileReslice(node *ast.SliceExpr) error {
return err
}
trustLen := true
hasHigh := false
if node.High != nil {
hasHigh = true
@ -490,6 +491,10 @@ func (ctx *compileCtx) compileReslice(node *ast.SliceExpr) error {
if err != nil {
return err
}
_, isbasiclit := node.High.(*ast.BasicLit)
trustLen = trustLen && isbasiclit
} else {
trustLen = false
}
if node.Low != nil {
@ -497,11 +502,13 @@ func (ctx *compileCtx) compileReslice(node *ast.SliceExpr) error {
if err != nil {
return err
}
_, isbasiclit := node.Low.(*ast.BasicLit)
trustLen = trustLen && isbasiclit
} else {
ctx.pushOp(&PushConst{constant.MakeInt64(0)})
}
ctx.pushOp(&Reslice{Node: node, HasHigh: hasHigh})
ctx.pushOp(&Reslice{Node: node, HasHigh: hasHigh, TrustLen: trustLen})
return nil
}

@ -114,8 +114,10 @@ func (*TypeCast) depthCheck() (npop, npush int) { return 1, 1 }
// If HasHigh is set it pops three variables, low, high and v, and pushes
// v[low:high].
// Otherwise it pops two variables, low and v, and pushes v[low:].
// If TrustLen is set when the variable resulting from the reslice is loaded it will be fully loaded.
type Reslice struct {
HasHigh bool
TrustLen bool
Node *ast.SliceExpr
}

@ -86,6 +86,9 @@ const (
VariableCPtr
// VariableCPURegister means this variable is a CPU register.
VariableCPURegister
// variableTrustLen means that when this variable is loaded its length
// should be trusted and used instead of MaxArrayValues
variableTrustLen
)
// Variable represents a variable. It contains the address, name,
@ -1683,7 +1686,7 @@ func (v *Variable) loadArrayValues(recurseLevel int, cfg LoadConfig) {
count := v.Len
// Cap number of elements
if count > int64(cfg.MaxArrayValues) {
if (v.Flags&variableTrustLen == 0) && (count > int64(cfg.MaxArrayValues)) {
count = int64(cfg.MaxArrayValues)
}
if v.Base+uint64(v.stride*count) < v.Base {

@ -553,8 +553,8 @@ func getEvalExpressionTestCases() []varTest {
{"str1[11]", false, "", "", "byte", fmt.Errorf("index out of bounds")},
// slice/array/string reslicing
{"a1[2:4]", false, "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string len: 2, cap: 2, [...]", "[]string", nil},
{"s1[2:4]", false, "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string len: 2, cap: 2, [...]", "[]string", nil},
{"a1[2:4]", false, "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string", nil},
{"s1[2:4]", false, "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string len: 2, cap: 2, [\"three\",\"four\"]", "[]string", nil},
{"str1[2:4]", false, "\"23\"", "\"23\"", "string", nil},
{"str1[0:11]", false, "\"01234567890\"", "\"01234567890\"", "string", nil},
{"str1[:3]", false, "\"012\"", "\"012\"", "string", nil},
@ -562,6 +562,7 @@ func getEvalExpressionTestCases() []varTest {
{"str1[0:12]", false, "", "", "string", fmt.Errorf("index out of bounds")},
{"str1[5:3]", false, "", "", "string", fmt.Errorf("index out of bounds")},
{"str1[11:]", false, "\"\"", "\"\"", "string", nil},
{"longbyteslice[:70]", false, "[]uint8 len: 70, cap: 70, [118,101,114,121,32,108,111,110,103,32,115,116,114,105,110,103,32,48,49,50,51,52,53,54,55,56,57,97,48,49,50,51,52,53,54,55,56,57,98,48,49,50,51,52,53,54,55,56,57,99,48,49,50,51,52,53,54,55,56,57,100,48,49,50,51,52,53,54,55,56]", "[]uint8 len: 70, cap: 70, [118,101,114,121,32,108,111,110,103,32,115,116,114,105,110,103,32,48,49,50,51,52,53,54,55,56,57,97,48,49,50,51,52,53,54,55,56,57,98,48,49,50,51,52,53,54,55,56,57,99,48,49,50,51,52,53,54,55,56,57,100,48,49,50,51,52,53,54,55,56]", "[]uint8", nil},
// NaN and Inf floats
{"pinf", false, "+Inf", "+Inf", "float64", nil},
@ -1579,7 +1580,7 @@ func TestCgoEval(t *testing.T) {
{"v", true, "*0", "(*int)(…", "*int", nil},
{"v[1]", false, "1", "1", "int", nil},
{"v[90]", false, "90", "90", "int", nil},
{"v[:5]", false, "[]int len: 5, cap: 5, [0,1,2,3,4]", "[]int len: 5, cap: 5, [...]", "[]int", nil},
{"v[:5]", false, "[]int len: 5, cap: 5, [0,1,2,3,4]", "[]int len: 5, cap: 5, [0,1,2,3,4]", "[]int", nil},
{"v_align_check", true, "*align_check {a: 0, b: 0}", "(*struct align_check)(…", "*struct align_check", nil},
{"v_align_check[1]", false, "align_check {a: 1, b: 1}", "align_check {a: 1, b: 1}", "align_check", nil},
{"v_align_check[90]", false, "align_check {a: 90, b: 90}", "align_check {a: 90, b: 90}", "align_check", nil},