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)
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)
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)
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))
err = fakeFunctionEntryScope(scope, rbpi.fn, oldFrameOffset, oldSP)
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, "")
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 {
return (v.Flags & VariableReturnArgument) != 0
@ -1050,8 +1050,8 @@ func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable
return vars
}
func returnInfoError(descr string, err error, mem MemoryReadWriter) []*Variable {
v := newConstant(constant.MakeString(fmt.Sprintf("%s: %v", descr, err.Error())), mem)
func returnInfoError(descr string, err error, bi *BinaryInfo, mem MemoryReadWriter) []*Variable {
v := newConstant(constant.MakeString(fmt.Sprintf("%s: %v", descr, err.Error())), bi, mem)
v.Name = "return value read error"
return []*Variable{v}
}

View File

@ -1068,29 +1068,29 @@ func (stack *evalStack) executeOp() {
gvar := newVariable("curg", fakeAddressUnresolv, typ, scope.BinInfo, scope.Mem)
gvar.loaded = true
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"
stack.push(gvar)
}
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:
if scope.rangeFrames == nil {
stack.err = scope.setupRangeFrames()
}
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 {
stack.push(newConstant(constant.MakeInt64(0), scope.Mem))
stack.push(newConstant(constant.MakeInt64(0), scope.BinInfo, scope.Mem))
}
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:
stack.push(newConstant(op.Value, scope.Mem))
stack.push(newConstant(op.Value, scope.BinInfo, scope.Mem))
case *evalop.PushLocal:
found := stack.pushLocal(scope, op.Name, op.Frame)
@ -1133,7 +1133,7 @@ func (stack *evalStack) executeOp() {
case *evalop.PushLen:
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:
scope.evalStructSelector(op, stack)
@ -1172,7 +1172,7 @@ func (stack *evalStack) executeOp() {
return
}
x.loadValue(loadFullValue)
stack.push(newConstant(x.Value, scope.Mem))
stack.push(newConstant(x.Value, scope.BinInfo, scope.Mem))
case *evalop.Pop:
stack.pop()
@ -1335,7 +1335,7 @@ func (stack *evalStack) pushIdent(scope *EvalScope, name string) (found bool) {
switch name {
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
case "nil":
stack.push(nilVariable)
@ -1846,18 +1846,18 @@ func capBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
}
fallthrough
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:
return newConstant(constant.MakeInt64(arg.Cap), arg.mem), nil
return newConstant(constant.MakeInt64(arg.Cap), arg.bi, arg.mem), nil
case reflect.Chan:
arg.loadValue(loadFullValue)
if arg.Unreadable != nil {
return nil, arg.Unreadable
}
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:
return nil, invalidArgErr
}
@ -1881,25 +1881,25 @@ func lenBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
if arg.Unreadable != nil {
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:
arg.loadValue(loadFullValue)
if arg.Unreadable != nil {
return nil, arg.Unreadable
}
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:
it := arg.mapIterator(0)
if arg.Unreadable != nil {
return nil, arg.Unreadable
}
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:
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 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) {
@ -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 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) {
@ -2121,7 +2121,7 @@ func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {
s := constant.StringVal(idxev.Value)
thc, err := totalHitCountByName(scope.target.Breakpoints().Logical, s)
if err == nil {
stack.push(newConstant(constant.MakeUint64(thc), scope.Mem))
stack.push(newConstant(constant.MakeUint64(thc), scope.BinInfo, scope.Mem))
}
stack.err = err
return
@ -2137,7 +2137,7 @@ func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {
}
thc, err := totalHitCountByID(scope.target.Breakpoints().Logical, int(n))
if err == nil {
stack.push(newConstant(constant.MakeUint64(thc), scope.Mem))
stack.push(newConstant(constant.MakeUint64(thc), scope.BinInfo, scope.Mem))
}
stack.err = err
return
@ -2371,7 +2371,7 @@ func (scope *EvalScope) evalUnary(op *evalop.Unary, stack *evalStack) {
stack.push(r)
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) {
@ -2502,7 +2502,7 @@ func (scope *EvalScope) evalBinary(binop *evalop.Binary, stack *evalStack) {
stack.err = err
return
}
stack.push(newConstant(constant.MakeBool(v), xv.mem))
stack.push(newConstant(constant.MakeBool(v), xv.bi, xv.mem))
default:
if xv.Kind == reflect.String {
@ -2528,7 +2528,7 @@ func (scope *EvalScope) evalBinary(binop *evalop.Binary, stack *evalStack) {
}
if typ == nil {
stack.push(newConstant(rc, xv.mem))
stack.push(newConstant(rc, xv.bi, xv.mem))
return
}

View File

@ -390,7 +390,7 @@ func (scope *EvalScope) evalCallInjectionStart(op *evalop.CallInjectionStart, st
p.fncallForG[scope.g.ID].startThreadID = thread.ThreadID()
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
}

View File

@ -356,7 +356,7 @@ func setAsyncPreemptOff(p *Target, v int64) {
p.asyncPreemptChanged = true
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 {
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)
func newConstant(val constant.Value, mem MemoryReadWriter) *Variable {
v := &Variable{Value: val, mem: mem, loaded: true}
func newConstant(val constant.Value, bi *BinaryInfo, mem MemoryReadWriter) *Variable {
v := &Variable{Value: val, mem: mem, loaded: true, bi: bi}
switch val.Kind() {
case constant.Int:
v.Kind = reflect.Int
@ -2197,47 +2197,47 @@ func (v *Variable) registerVariableTypeConv(newtyp string) (*Variable, error) {
var child *Variable
switch newtyp {
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
n = 1
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
n = 2
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
n = 4
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
n = 8
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
n = 1
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
n = 2
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
n = 4
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
n = 8
case "float32":
a := binary.LittleEndian.Uint32(v.reg.Bytes[i:])
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
n = 4
case "float64":
a := binary.LittleEndian.Uint64(v.reg.Bytes[i:])
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
n = 8
default:
@ -2253,7 +2253,7 @@ func (v *Variable) registerVariableTypeConv(newtyp string) (*Variable, error) {
}
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)
}