proc/variables: fix infinite recursion with pointer loop (#725)

loadValue didn't react correctly to pointer loops going through
slice -> interface{} -> slice or pointer -> interface{} -> pointer.
This commit is contained in:
Alessandro Arzilli 2017-02-10 01:26:38 +01:00 committed by Derek Parker
parent ce01a67d8b
commit fc0d40144a
4 changed files with 27 additions and 9 deletions

@ -212,6 +212,14 @@ func main() {
ninf := math.Inf(-1) ninf := math.Inf(-1)
nan := math.NaN() nan := math.NaN()
var iface6 interface{}
var ptrinf *interface{}
iface6 = &ptrinf
ptrinf = &iface6
sliceinf := make([]interface{}, 1)
sliceinf[0] = sliceinf
var amb1 = 1 var amb1 = 1
runtime.Breakpoint() runtime.Breakpoint()
for amb1 := 0; amb1 < 10; amb1++ { for amb1 := 0; amb1 < 10; amb1++ {

@ -1440,14 +1440,17 @@ func TestIssue305(t *testing.T) {
}) })
} }
func TestIssue341(t *testing.T) { func TestPointerLoops(t *testing.T) {
// pointer loop through map entries // Pointer loops through map entries, pointers and slices
// Regression test for issue #341
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) { withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
assertNoError(p.Continue(), t, "Continue()") assertNoError(p.Continue(), t, "Continue()")
t.Logf("requesting mapinf") for _, expr := range []string{"mapinf", "ptrinf", "sliceinf"} {
mapinf, err := evalVariable(p, "mapinf") t.Logf("requesting %s", expr)
assertNoError(err, t, "EvalVariable()") v, err := evalVariable(p, expr)
t.Logf("mapinf: %v\n", mapinf) assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", expr))
t.Logf("%s: %v\n", expr, v)
}
}) })
} }

@ -812,7 +812,12 @@ func (v *Variable) loadValueInternal(recurseLevel int, cfg LoadConfig) {
v.Children = []Variable{*v.maybeDereference()} v.Children = []Variable{*v.maybeDereference()}
if cfg.FollowPointers { if cfg.FollowPointers {
// Don't increase the recursion level when dereferencing pointers // Don't increase the recursion level when dereferencing pointers
v.Children[0].loadValueInternal(recurseLevel, cfg) // unless this is a pointer to interface (which could cause an infinite loop)
nextLvl := recurseLevel
if v.Children[0].Kind == reflect.Interface {
nextLvl++
}
v.Children[0].loadValueInternal(nextLvl, cfg)
} else { } else {
v.Children[0].OnlyAddr = true v.Children[0].OnlyAddr = true
} }
@ -1630,7 +1635,7 @@ func (v *Variable) loadInterface(recurseLevel int, loadData bool, cfg LoadConfig
data = data.newVariable("data", data.Addr, typ) data = data.newVariable("data", data.Addr, typ)
v.Children = []Variable{*data} v.Children = []Variable{*data}
if loadData { if loadData && recurseLevel <= cfg.MaxVariableRecurse {
v.Children[0].loadValueInternal(recurseLevel, cfg) v.Children[0].loadValueInternal(recurseLevel, cfg)
} else { } else {
v.Children[0].OnlyAddr = true v.Children[0].OnlyAddr = true

@ -87,7 +87,9 @@ func (v *Variable) writeTo(buf io.Writer, top, newlines, includeType bool, inden
} }
data := v.Children[0] data := v.Children[0]
if data.Kind == reflect.Ptr { if data.Kind == reflect.Ptr {
if data.Children[0].Addr == 0 { if len(data.Children) == 0 {
fmt.Fprintf(buf, "...")
} else if data.Children[0].Addr == 0 {
fmt.Fprintf(buf, "nil") fmt.Fprintf(buf, "nil")
} else if data.Children[0].OnlyAddr { } else if data.Children[0].OnlyAddr {
fmt.Fprintf(buf, "0x%x", v.Children[0].Addr) fmt.Fprintf(buf, "0x%x", v.Children[0].Addr)