go-delve/delve · error
ErrStackUnderflow
ErrStackUnderflow
Error message
DWARF stack underflow
What it means
ErrStackUnderflow is a sentinel error indicating a DWARF location-expression stack operation ran out of operands. Operations like dup/drop/swap/rot (stack manipulation), unaryop and binaryop pop one or two values off the DWARF value stack; if the stack has too few values, this error is returned by ExecuteStackProgram.
Source
Thrown at pkg/dwarf/op/op.go:53
// Piece is a piece of memory stored either at an address or in a register.
type Piece struct {
Size int
Kind PieceKind
Val uint64
Bytes []byte
}
// PieceKind describes the kind of a piece.
type PieceKind uint8
const (
AddrPiece PieceKind = iota // The piece is stored in memory, Val is the address
RegPiece // The piece is stored in a register, Val is the register number
ImmPiece // The piece is an immediate value, Val or Bytes is the value
)
var (
ErrStackUnderflow = errors.New("DWARF stack underflow")
ErrStackIndexOutOfBounds = errors.New("DWARF stack index out of bounds")
ErrMemoryReadUnavailable = errors.New("memory read unavailable")
)
const arbitraryExecutionLimitFactor = 10
// ExecuteStackProgram executes a DWARF location expression and returns
// either an address (int64), or a slice of Pieces for location expressions
// that don't evaluate to an address (such as register and composite expressions).
func ExecuteStackProgram(regs DwarfRegisters, instructions []byte, ptrSize int, readMemory ReadMemoryFunc) (int64, []Piece, error) {
ctxt := &context{
buf: bytes.NewBuffer(instructions),
prog: instructions,
stack: make([]int64, 0, 3),
DwarfRegisters: regs,
ptrSize: ptrSize,
readMemory: readMemory,
}View on GitHub (pinned to a23773e6c3)
Solutions
- Verify the binary's DWARF data is intact and produced by a standard toolchain (recompile with debug info)
- Check that the byte slice passed as instructions is the raw DWARF expression, not a padded or offset slice
- If you control the expression generation, validate that every producer opcode precedes its consumers
- Catch errors.Is(err, op.ErrStackUnderflow) and fall back to reporting the variable as unavailable
Example fix
// before
val, pieces, err := op.ExecuteStackProgram(regs, instr, ptrSize, nil)
// after
val, pieces, err := op.ExecuteStackProgram(regs, instr, ptrSize, nil)
if errors.Is(err, op.ErrStackUnderflow) {
return 0, nil, fmt.Errorf("malformed DWARF expression: %w", err)
} Defensive patterns
Strategy: try-catch
Try / catch
val, pieces, err := op.ExecuteStackProgram(regs, instr, ptrSize, mem)
if errors.Is(err, op.ErrStackUnderflow) {
// malformed expression: report variable as unavailable
} Prevention
- Ensure debug info comes from a standard, current toolchain
- Never hand-truncate DWARF expression byte slices
- Unit-test custom expressions with assertExprResult before shipping
When it happens
Trigger: Executing a malformed or truncated DWARF location expression via op.ExecuteStackProgram where a dup, drop, swap, rot, unaryop, or binaryop opcode needs more stack operands than are present.
Common situations: Corrupted or hand-crafted DWARF debug info, compiler bugs emitting bad expression streams, or a mis-parsed byte slice passed as 'instructions' so the opcode stream is misaligned.
Related errors
- ErrStackIndexOutOfBounds
- ErrMemoryReadUnavailable
- empty OP stack
- could not retrieve CFA for current PC
- type assertion failed
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/bd9bf8c3836e495e.
Report an issue: GitHub.