proc: auto-dereference local variables that escape to the heap
The compiler a variable 'v' that escapes to the heap with a '&v' entry. Auto dereference those local variables. Fixe #871
This commit is contained in:
parent
04adb46ccb
commit
731829c349
@ -24,12 +24,14 @@ All changes mention the author, unless contributed by me (@derekparker).
|
||||
- Parsing of maps with zero sized values (@aarzilli)
|
||||
- Typo in the documentation of `types` command (@custa)
|
||||
- Data races in tests (@aarzilli)
|
||||
- Fixed SetBreakpoint in native and gdbserial to return the breakpoint if it already exists (@dlsniper)
|
||||
|
||||
### Changed
|
||||
|
||||
- Switched from godeps to glide (@derekparker)
|
||||
- Better performance of linux native backend (@aarzilli)
|
||||
- Collect breakpoints information if necessary after a next, step or stepout command (@aarzilli)
|
||||
- Autodereference escaped variables (@aarzilli)
|
||||
|
||||
## [1.0.0-rc.1] 2017-05-05
|
||||
|
||||
|
13
_fixtures/issue871.go
Normal file
13
_fixtures/issue871.go
Normal file
@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := [3]int{1, 2, 3}
|
||||
b := &a
|
||||
runtime.Breakpoint()
|
||||
fmt.Println(b, *b) // set breakpoint here
|
||||
}
|
@ -2984,3 +2984,49 @@ func TestStepInstructionNoGoroutine(t *testing.T) {
|
||||
assertNoError(p.StepInstruction(), t, "StepInstruction")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIssue871(t *testing.T) {
|
||||
protest.AllowRecording(t)
|
||||
withTestProcess("issue871", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue")
|
||||
|
||||
var scope *proc.EvalScope
|
||||
var err error
|
||||
if testBackend == "rr" {
|
||||
var frame proc.Stackframe
|
||||
frame, err = findFirstNonRuntimeFrame(p)
|
||||
if err == nil {
|
||||
scope = proc.FrameToScope(p, frame)
|
||||
}
|
||||
} else {
|
||||
scope, err = proc.GoroutineScope(p.CurrentThread())
|
||||
}
|
||||
assertNoError(err, t, "scope")
|
||||
|
||||
locals, err := scope.LocalVariables(normalLoadConfig)
|
||||
assertNoError(err, t, "LocalVariables")
|
||||
|
||||
foundA, foundB := false, false
|
||||
|
||||
for _, v := range locals {
|
||||
t.Logf("local %v", v)
|
||||
switch v.Name {
|
||||
case "a":
|
||||
foundA = true
|
||||
if v.Flags&proc.VariableEscaped == 0 {
|
||||
t.Errorf("variable a not flagged as escaped")
|
||||
}
|
||||
case "b":
|
||||
foundB = true
|
||||
}
|
||||
}
|
||||
|
||||
if !foundA {
|
||||
t.Errorf("variable a not found")
|
||||
}
|
||||
|
||||
if !foundB {
|
||||
t.Errorf("variable b not found")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -39,6 +39,13 @@ const (
|
||||
FloatIsNegInf
|
||||
)
|
||||
|
||||
type VariableFlags uint16
|
||||
|
||||
const (
|
||||
// VariableEscaped is set for local variables that escaped to the heap
|
||||
VariableEscaped VariableFlags = (1 << iota)
|
||||
)
|
||||
|
||||
// Variable represents a variable. It contains the address, name,
|
||||
// type and other information parsed from both the Dwarf information
|
||||
// and the memory of the debugged process.
|
||||
@ -59,6 +66,8 @@ type Variable struct {
|
||||
Len int64
|
||||
Cap int64
|
||||
|
||||
Flags VariableFlags
|
||||
|
||||
// Base address of arrays, Base address of the backing array for slices (0 for nil slices)
|
||||
// Base address of the backing byte array for strings
|
||||
// address of the struct backing chan and map variables
|
||||
@ -1717,7 +1726,13 @@ func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg LoadConfig) ([]*Variab
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range vars {
|
||||
for i, v := range vars {
|
||||
if name := v.Name; len(name) > 1 && name[0] == '&' {
|
||||
v = v.maybeDereference()
|
||||
v.Name = name[1:]
|
||||
v.Flags |= VariableEscaped
|
||||
vars[i] = v
|
||||
}
|
||||
v.loadValue(cfg)
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,7 @@ func ConvertVar(v *proc.Variable) *Variable {
|
||||
Kind: v.Kind,
|
||||
Len: v.Len,
|
||||
Cap: v.Cap,
|
||||
Flags: VariableFlags(v.Flags),
|
||||
}
|
||||
|
||||
r.Type = prettyTypeName(v.DwarfType)
|
||||
|
@ -147,6 +147,12 @@ type Function struct {
|
||||
GoType uint64 `json:"goType"`
|
||||
}
|
||||
|
||||
type VariableFlags uint16
|
||||
|
||||
const (
|
||||
VariableEscaped = VariableFlags(proc.VariableEscaped)
|
||||
)
|
||||
|
||||
// Variable describes a variable.
|
||||
type Variable struct {
|
||||
// Name of the variable or struct member
|
||||
@ -160,6 +166,8 @@ type Variable struct {
|
||||
// Type of the variable after resolving any typedefs
|
||||
RealType string `json:"realType"`
|
||||
|
||||
Flags VariableFlags `json:"flags"`
|
||||
|
||||
Kind reflect.Kind `json:"kind"`
|
||||
|
||||
//Strings have their length capped at proc.maxArrayValues, use Len for the real length of a string
|
||||
|
Loading…
Reference in New Issue
Block a user