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)
|
- Parsing of maps with zero sized values (@aarzilli)
|
||||||
- Typo in the documentation of `types` command (@custa)
|
- Typo in the documentation of `types` command (@custa)
|
||||||
- Data races in tests (@aarzilli)
|
- Data races in tests (@aarzilli)
|
||||||
|
- Fixed SetBreakpoint in native and gdbserial to return the breakpoint if it already exists (@dlsniper)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Switched from godeps to glide (@derekparker)
|
- Switched from godeps to glide (@derekparker)
|
||||||
- Better performance of linux native backend (@aarzilli)
|
- Better performance of linux native backend (@aarzilli)
|
||||||
- Collect breakpoints information if necessary after a next, step or stepout command (@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
|
## [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")
|
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
|
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,
|
// Variable represents a variable. It contains the address, name,
|
||||||
// type and other information parsed from both the Dwarf information
|
// type and other information parsed from both the Dwarf information
|
||||||
// and the memory of the debugged process.
|
// and the memory of the debugged process.
|
||||||
@ -59,6 +66,8 @@ type Variable struct {
|
|||||||
Len int64
|
Len int64
|
||||||
Cap int64
|
Cap int64
|
||||||
|
|
||||||
|
Flags VariableFlags
|
||||||
|
|
||||||
// Base address of arrays, Base address of the backing array for slices (0 for nil slices)
|
// 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
|
// Base address of the backing byte array for strings
|
||||||
// address of the struct backing chan and map variables
|
// 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)
|
v.loadValue(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -121,6 +121,7 @@ func ConvertVar(v *proc.Variable) *Variable {
|
|||||||
Kind: v.Kind,
|
Kind: v.Kind,
|
||||||
Len: v.Len,
|
Len: v.Len,
|
||||||
Cap: v.Cap,
|
Cap: v.Cap,
|
||||||
|
Flags: VariableFlags(v.Flags),
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Type = prettyTypeName(v.DwarfType)
|
r.Type = prettyTypeName(v.DwarfType)
|
||||||
|
|||||||
@ -147,6 +147,12 @@ type Function struct {
|
|||||||
GoType uint64 `json:"goType"`
|
GoType uint64 `json:"goType"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VariableFlags uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
VariableEscaped = VariableFlags(proc.VariableEscaped)
|
||||||
|
)
|
||||||
|
|
||||||
// Variable describes a variable.
|
// Variable describes a variable.
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
// Name of the variable or struct member
|
// Name of the variable or struct member
|
||||||
@ -160,6 +166,8 @@ type Variable struct {
|
|||||||
// Type of the variable after resolving any typedefs
|
// Type of the variable after resolving any typedefs
|
||||||
RealType string `json:"realType"`
|
RealType string `json:"realType"`
|
||||||
|
|
||||||
|
Flags VariableFlags `json:"flags"`
|
||||||
|
|
||||||
Kind reflect.Kind `json:"kind"`
|
Kind reflect.Kind `json:"kind"`
|
||||||
|
|
||||||
//Strings have their length capped at proc.maxArrayValues, use Len for the real length of a string
|
//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