proc: fill bi member of constants (#4026)

Fill the bi field of constant variables when we create them. This is
meant to address #4021 which is caused by trying to access a member
field of a variable with a nil bi. I couldn't find a way to make a
constant reach that point into the code but this still looks like the
most likely explanation.

Fixes #4021
This commit is contained in:
Alessandro Arzilli
2025-06-13 23:22:10 +02:00
committed by GitHub
parent 2ac3573b74
commit 99ec109dd3
5 changed files with 46 additions and 46 deletions

View File

@ -1014,11 +1014,11 @@ func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable
g, err := GetG(thread) g, err := GetG(thread)
if err != nil { if err != nil {
return returnInfoError("could not get g", err, thread.ProcessMemory()) return returnInfoError("could not get g", err, thread.BinInfo(), thread.ProcessMemory())
} }
scope, err := GoroutineScope(t, thread) scope, err := GoroutineScope(t, thread)
if err != nil { if err != nil {
return returnInfoError("could not get scope", err, thread.ProcessMemory()) return returnInfoError("could not get scope", err, thread.BinInfo(), thread.ProcessMemory())
} }
v, err := scope.evalAST(rbpi.retFrameCond) v, err := scope.evalAST(rbpi.retFrameCond)
if err != nil || v.Unreadable != nil || v.Kind != reflect.Bool { if err != nil || v.Unreadable != nil || v.Kind != reflect.Bool {
@ -1036,12 +1036,12 @@ func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable
oldSP := uint64(rbpi.spOffset + int64(g.stack.hi)) oldSP := uint64(rbpi.spOffset + int64(g.stack.hi))
err = fakeFunctionEntryScope(scope, rbpi.fn, oldFrameOffset, oldSP) err = fakeFunctionEntryScope(scope, rbpi.fn, oldFrameOffset, oldSP)
if err != nil { if err != nil {
return returnInfoError("could not read function entry", err, thread.ProcessMemory()) return returnInfoError("could not read function entry", err, thread.BinInfo(), thread.ProcessMemory())
} }
vars, err := scope.Locals(0, "") vars, err := scope.Locals(0, "")
if err != nil { if err != nil {
return returnInfoError("could not evaluate return variables", err, thread.ProcessMemory()) return returnInfoError("could not evaluate return variables", err, thread.BinInfo(), thread.ProcessMemory())
} }
vars = filterVariables(vars, func(v *Variable) bool { vars = filterVariables(vars, func(v *Variable) bool {
return (v.Flags & VariableReturnArgument) != 0 return (v.Flags & VariableReturnArgument) != 0
@ -1050,8 +1050,8 @@ func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable
return vars return vars
} }
func returnInfoError(descr string, err error, mem MemoryReadWriter) []*Variable { func returnInfoError(descr string, err error, bi *BinaryInfo, mem MemoryReadWriter) []*Variable {
v := newConstant(constant.MakeString(fmt.Sprintf("%s: %v", descr, err.Error())), mem) v := newConstant(constant.MakeString(fmt.Sprintf("%s: %v", descr, err.Error())), bi, mem)
v.Name = "return value read error" v.Name = "return value read error"
return []*Variable{v} return []*Variable{v}
} }

View File

@ -1068,29 +1068,29 @@ func (stack *evalStack) executeOp() {
gvar := newVariable("curg", fakeAddressUnresolv, typ, scope.BinInfo, scope.Mem) gvar := newVariable("curg", fakeAddressUnresolv, typ, scope.BinInfo, scope.Mem)
gvar.loaded = true gvar.loaded = true
gvar.Flags = VariableFakeAddress gvar.Flags = VariableFakeAddress
gvar.Children = append(gvar.Children, *newConstant(constant.MakeInt64(0), scope.Mem)) gvar.Children = append(gvar.Children, *newConstant(constant.MakeInt64(0), scope.BinInfo, scope.Mem))
gvar.Children[0].Name = "goid" gvar.Children[0].Name = "goid"
stack.push(gvar) stack.push(gvar)
} }
case *evalop.PushFrameoff: case *evalop.PushFrameoff:
stack.push(newConstant(constant.MakeInt64(scope.frameOffset), scope.Mem)) stack.push(newConstant(constant.MakeInt64(scope.frameOffset), scope.BinInfo, scope.Mem))
case *evalop.PushRangeParentOffset: case *evalop.PushRangeParentOffset:
if scope.rangeFrames == nil { if scope.rangeFrames == nil {
stack.err = scope.setupRangeFrames() stack.err = scope.setupRangeFrames()
} }
if len(scope.rangeFrames) > 0 { if len(scope.rangeFrames) > 0 {
stack.push(newConstant(constant.MakeInt64(scope.rangeFrames[len(scope.rangeFrames)-2].FrameOffset()), scope.Mem)) stack.push(newConstant(constant.MakeInt64(scope.rangeFrames[len(scope.rangeFrames)-2].FrameOffset()), scope.BinInfo, scope.Mem))
} else { } else {
stack.push(newConstant(constant.MakeInt64(0), scope.Mem)) stack.push(newConstant(constant.MakeInt64(0), scope.BinInfo, scope.Mem))
} }
case *evalop.PushThreadID: case *evalop.PushThreadID:
stack.push(newConstant(constant.MakeInt64(int64(scope.threadID)), scope.Mem)) stack.push(newConstant(constant.MakeInt64(int64(scope.threadID)), scope.BinInfo, scope.Mem))
case *evalop.PushConst: case *evalop.PushConst:
stack.push(newConstant(op.Value, scope.Mem)) stack.push(newConstant(op.Value, scope.BinInfo, scope.Mem))
case *evalop.PushLocal: case *evalop.PushLocal:
found := stack.pushLocal(scope, op.Name, op.Frame) found := stack.pushLocal(scope, op.Name, op.Frame)
@ -1133,7 +1133,7 @@ func (stack *evalStack) executeOp() {
case *evalop.PushLen: case *evalop.PushLen:
v := stack.peek() v := stack.peek()
stack.push(newConstant(constant.MakeInt64(v.Len), scope.Mem)) stack.push(newConstant(constant.MakeInt64(v.Len), scope.BinInfo, scope.Mem))
case *evalop.Select: case *evalop.Select:
scope.evalStructSelector(op, stack) scope.evalStructSelector(op, stack)
@ -1172,7 +1172,7 @@ func (stack *evalStack) executeOp() {
return return
} }
x.loadValue(loadFullValue) x.loadValue(loadFullValue)
stack.push(newConstant(x.Value, scope.Mem)) stack.push(newConstant(x.Value, scope.BinInfo, scope.Mem))
case *evalop.Pop: case *evalop.Pop:
stack.pop() stack.pop()
@ -1335,7 +1335,7 @@ func (stack *evalStack) pushIdent(scope *EvalScope, name string) (found bool) {
switch name { switch name {
case "true", "false": case "true", "false":
stack.push(newConstant(constant.MakeBool(name == "true"), scope.Mem)) stack.push(newConstant(constant.MakeBool(name == "true"), scope.BinInfo, scope.Mem))
return true return true
case "nil": case "nil":
stack.push(nilVariable) stack.push(nilVariable)
@ -1846,18 +1846,18 @@ func capBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
} }
fallthrough fallthrough
case reflect.Array: case reflect.Array:
return newConstant(constant.MakeInt64(arg.Len), arg.mem), nil return newConstant(constant.MakeInt64(arg.Len), arg.bi, arg.mem), nil
case reflect.Slice: case reflect.Slice:
return newConstant(constant.MakeInt64(arg.Cap), arg.mem), nil return newConstant(constant.MakeInt64(arg.Cap), arg.bi, arg.mem), nil
case reflect.Chan: case reflect.Chan:
arg.loadValue(loadFullValue) arg.loadValue(loadFullValue)
if arg.Unreadable != nil { if arg.Unreadable != nil {
return nil, arg.Unreadable return nil, arg.Unreadable
} }
if arg.Base == 0 { if arg.Base == 0 {
return newConstant(constant.MakeInt64(0), arg.mem), nil return newConstant(constant.MakeInt64(0), arg.bi, arg.mem), nil
} }
return newConstant(arg.Children[1].Value, arg.mem), nil return newConstant(arg.Children[1].Value, arg.bi, arg.mem), nil
default: default:
return nil, invalidArgErr return nil, invalidArgErr
} }
@ -1881,25 +1881,25 @@ func lenBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
if arg.Unreadable != nil { if arg.Unreadable != nil {
return nil, arg.Unreadable return nil, arg.Unreadable
} }
return newConstant(constant.MakeInt64(arg.Len), arg.mem), nil return newConstant(constant.MakeInt64(arg.Len), arg.bi, arg.mem), nil
case reflect.Chan: case reflect.Chan:
arg.loadValue(loadFullValue) arg.loadValue(loadFullValue)
if arg.Unreadable != nil { if arg.Unreadable != nil {
return nil, arg.Unreadable return nil, arg.Unreadable
} }
if arg.Base == 0 { if arg.Base == 0 {
return newConstant(constant.MakeInt64(0), arg.mem), nil return newConstant(constant.MakeInt64(0), arg.bi, arg.mem), nil
} }
return newConstant(arg.Children[0].Value, arg.mem), nil return newConstant(arg.Children[0].Value, arg.bi, arg.mem), nil
case reflect.Map: case reflect.Map:
it := arg.mapIterator(0) it := arg.mapIterator(0)
if arg.Unreadable != nil { if arg.Unreadable != nil {
return nil, arg.Unreadable return nil, arg.Unreadable
} }
if it == nil { if it == nil {
return newConstant(constant.MakeInt64(0), arg.mem), nil return newConstant(constant.MakeInt64(0), arg.bi, arg.mem), nil
} }
return newConstant(constant.MakeInt64(arg.Len), arg.mem), nil return newConstant(constant.MakeInt64(arg.Len), arg.bi, arg.mem), nil
default: default:
return nil, invalidArgErr return nil, invalidArgErr
} }
@ -1970,7 +1970,7 @@ func imagBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
return nil, fmt.Errorf("invalid argument %s (type %s) to imag", astutil.ExprToString(nodeargs[0]), arg.TypeString()) return nil, fmt.Errorf("invalid argument %s (type %s) to imag", astutil.ExprToString(nodeargs[0]), arg.TypeString())
} }
return newConstant(constant.Imag(arg.Value), arg.mem), nil return newConstant(constant.Imag(arg.Value), arg.bi, arg.mem), nil
} }
func realBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { func realBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
@ -1989,7 +1989,7 @@ func realBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
return nil, fmt.Errorf("invalid argument %s (type %s) to real", astutil.ExprToString(nodeargs[0]), arg.TypeString()) return nil, fmt.Errorf("invalid argument %s (type %s) to real", astutil.ExprToString(nodeargs[0]), arg.TypeString())
} }
return newConstant(constant.Real(arg.Value), arg.mem), nil return newConstant(constant.Real(arg.Value), arg.bi, arg.mem), nil
} }
func minBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) { func minBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
@ -2121,7 +2121,7 @@ func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {
s := constant.StringVal(idxev.Value) s := constant.StringVal(idxev.Value)
thc, err := totalHitCountByName(scope.target.Breakpoints().Logical, s) thc, err := totalHitCountByName(scope.target.Breakpoints().Logical, s)
if err == nil { if err == nil {
stack.push(newConstant(constant.MakeUint64(thc), scope.Mem)) stack.push(newConstant(constant.MakeUint64(thc), scope.BinInfo, scope.Mem))
} }
stack.err = err stack.err = err
return return
@ -2137,7 +2137,7 @@ func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {
} }
thc, err := totalHitCountByID(scope.target.Breakpoints().Logical, int(n)) thc, err := totalHitCountByID(scope.target.Breakpoints().Logical, int(n))
if err == nil { if err == nil {
stack.push(newConstant(constant.MakeUint64(thc), scope.Mem)) stack.push(newConstant(constant.MakeUint64(thc), scope.BinInfo, scope.Mem))
} }
stack.err = err stack.err = err
return return
@ -2371,7 +2371,7 @@ func (scope *EvalScope) evalUnary(op *evalop.Unary, stack *evalStack) {
stack.push(r) stack.push(r)
return return
} }
stack.push(newConstant(rc, xv.mem)) stack.push(newConstant(rc, xv.bi, xv.mem))
} }
func negotiateType(op token.Token, xv, yv *Variable) (godwarf.Type, error) { func negotiateType(op token.Token, xv, yv *Variable) (godwarf.Type, error) {
@ -2502,7 +2502,7 @@ func (scope *EvalScope) evalBinary(binop *evalop.Binary, stack *evalStack) {
stack.err = err stack.err = err
return return
} }
stack.push(newConstant(constant.MakeBool(v), xv.mem)) stack.push(newConstant(constant.MakeBool(v), xv.bi, xv.mem))
default: default:
if xv.Kind == reflect.String { if xv.Kind == reflect.String {
@ -2528,7 +2528,7 @@ func (scope *EvalScope) evalBinary(binop *evalop.Binary, stack *evalStack) {
} }
if typ == nil { if typ == nil {
stack.push(newConstant(rc, xv.mem)) stack.push(newConstant(rc, xv.bi, xv.mem))
return return
} }

View File

@ -390,7 +390,7 @@ func (scope *EvalScope) evalCallInjectionStart(op *evalop.CallInjectionStart, st
p.fncallForG[scope.g.ID].startThreadID = thread.ThreadID() p.fncallForG[scope.g.ID].startThreadID = thread.ThreadID()
stack.fncallPush(&fncall) stack.fncallPush(&fncall)
stack.push(newConstant(constant.MakeBool(!fncall.hasDebugPinner && (fncall.fn == nil || fncall.receiver != nil || fncall.closureAddr != 0)), scope.Mem)) stack.push(newConstant(constant.MakeBool(!fncall.hasDebugPinner && (fncall.fn == nil || fncall.receiver != nil || fncall.closureAddr != 0)), scope.BinInfo, scope.Mem))
stack.callInjectionContinue = true stack.callInjectionContinue = true
} }

View File

@ -356,7 +356,7 @@ func setAsyncPreemptOff(p *Target, v int64) {
p.asyncPreemptChanged = true p.asyncPreemptChanged = true
p.asyncPreemptOff, _ = constant.Int64Val(asyncpreemptoffv.Value) p.asyncPreemptOff, _ = constant.Int64Val(asyncpreemptoffv.Value)
err = scope.setValue(asyncpreemptoffv, newConstant(constant.MakeInt64(v), scope.Mem), "") err = scope.setValue(asyncpreemptoffv, newConstant(constant.MakeInt64(v), scope.BinInfo, scope.Mem), "")
if err != nil { if err != nil {
logger.Warnf("could not set asyncpreemptoff %v", err) logger.Warnf("could not set asyncpreemptoff %v", err)
} }

View File

@ -776,8 +776,8 @@ func newVariable(name string, addr uint64, dwarfType godwarf.Type, bi *BinaryInf
var constantMaxInt64 = constant.MakeInt64(1<<63 - 1) var constantMaxInt64 = constant.MakeInt64(1<<63 - 1)
func newConstant(val constant.Value, mem MemoryReadWriter) *Variable { func newConstant(val constant.Value, bi *BinaryInfo, mem MemoryReadWriter) *Variable {
v := &Variable{Value: val, mem: mem, loaded: true} v := &Variable{Value: val, mem: mem, loaded: true, bi: bi}
switch val.Kind() { switch val.Kind() {
case constant.Int: case constant.Int:
v.Kind = reflect.Int v.Kind = reflect.Int
@ -2197,47 +2197,47 @@ func (v *Variable) registerVariableTypeConv(newtyp string) (*Variable, error) {
var child *Variable var child *Variable
switch newtyp { switch newtyp {
case "int8": case "int8":
child = newConstant(constant.MakeInt64(int64(int8(v.reg.Bytes[i]))), v.mem) child = newConstant(constant.MakeInt64(int64(int8(v.reg.Bytes[i]))), v.bi, v.mem)
child.Kind = reflect.Int8 child.Kind = reflect.Int8
n = 1 n = 1
case "int16": case "int16":
child = newConstant(constant.MakeInt64(int64(int16(binary.LittleEndian.Uint16(v.reg.Bytes[i:])))), v.mem) child = newConstant(constant.MakeInt64(int64(int16(binary.LittleEndian.Uint16(v.reg.Bytes[i:])))), v.bi, v.mem)
child.Kind = reflect.Int16 child.Kind = reflect.Int16
n = 2 n = 2
case "int32": case "int32":
child = newConstant(constant.MakeInt64(int64(int32(binary.LittleEndian.Uint32(v.reg.Bytes[i:])))), v.mem) child = newConstant(constant.MakeInt64(int64(int32(binary.LittleEndian.Uint32(v.reg.Bytes[i:])))), v.bi, v.mem)
child.Kind = reflect.Int32 child.Kind = reflect.Int32
n = 4 n = 4
case "int64": case "int64":
child = newConstant(constant.MakeInt64(int64(binary.LittleEndian.Uint64(v.reg.Bytes[i:]))), v.mem) child = newConstant(constant.MakeInt64(int64(binary.LittleEndian.Uint64(v.reg.Bytes[i:]))), v.bi, v.mem)
child.Kind = reflect.Int64 child.Kind = reflect.Int64
n = 8 n = 8
case "uint8": case "uint8":
child = newConstant(constant.MakeUint64(uint64(v.reg.Bytes[i])), v.mem) child = newConstant(constant.MakeUint64(uint64(v.reg.Bytes[i])), v.bi, v.mem)
child.Kind = reflect.Uint8 child.Kind = reflect.Uint8
n = 1 n = 1
case "uint16": case "uint16":
child = newConstant(constant.MakeUint64(uint64(binary.LittleEndian.Uint16(v.reg.Bytes[i:]))), v.mem) child = newConstant(constant.MakeUint64(uint64(binary.LittleEndian.Uint16(v.reg.Bytes[i:]))), v.bi, v.mem)
child.Kind = reflect.Uint16 child.Kind = reflect.Uint16
n = 2 n = 2
case "uint32": case "uint32":
child = newConstant(constant.MakeUint64(uint64(binary.LittleEndian.Uint32(v.reg.Bytes[i:]))), v.mem) child = newConstant(constant.MakeUint64(uint64(binary.LittleEndian.Uint32(v.reg.Bytes[i:]))), v.bi, v.mem)
child.Kind = reflect.Uint32 child.Kind = reflect.Uint32
n = 4 n = 4
case "uint64": case "uint64":
child = newConstant(constant.MakeUint64(binary.LittleEndian.Uint64(v.reg.Bytes[i:])), v.mem) child = newConstant(constant.MakeUint64(binary.LittleEndian.Uint64(v.reg.Bytes[i:])), v.bi, v.mem)
child.Kind = reflect.Uint64 child.Kind = reflect.Uint64
n = 8 n = 8
case "float32": case "float32":
a := binary.LittleEndian.Uint32(v.reg.Bytes[i:]) a := binary.LittleEndian.Uint32(v.reg.Bytes[i:])
x := *(*float32)(unsafe.Pointer(&a)) x := *(*float32)(unsafe.Pointer(&a))
child = newConstant(constant.MakeFloat64(float64(x)), v.mem) child = newConstant(constant.MakeFloat64(float64(x)), v.bi, v.mem)
child.Kind = reflect.Float32 child.Kind = reflect.Float32
n = 4 n = 4
case "float64": case "float64":
a := binary.LittleEndian.Uint64(v.reg.Bytes[i:]) a := binary.LittleEndian.Uint64(v.reg.Bytes[i:])
x := *(*float64)(unsafe.Pointer(&a)) x := *(*float64)(unsafe.Pointer(&a))
child = newConstant(constant.MakeFloat64(x), v.mem) child = newConstant(constant.MakeFloat64(x), v.bi, v.mem)
child.Kind = reflect.Float64 child.Kind = reflect.Float64
n = 8 n = 8
default: default:
@ -2253,7 +2253,7 @@ func (v *Variable) registerVariableTypeConv(newtyp string) (*Variable, error) {
} }
n = n / 8 n = n / 8
} }
child = newConstant(constant.MakeString(fmt.Sprintf("%x", v.reg.Bytes[i:][:n])), v.mem) child = newConstant(constant.MakeString(fmt.Sprintf("%x", v.reg.Bytes[i:][:n])), v.bi, v.mem)
} }
v.Children = append(v.Children, *child) v.Children = append(v.Children, *child)
} }