go-delve/delve · critical

Could not unread byte

Error message

Could not unread byte

What it means

lookupFunc panics when it needs to restore the opcode's argument byte via buf.UnreadByte() and the underlying byte reader refuses the unread. Since a ReadByte just succeeded, an UnreadByte failure means the buffer implementation cannot step back — effectively an invariant violation in the frame decoder's stream handling.

Source

Thrown at pkg/dwarf/frame/table.go:245

	switch instruction & high_2_bits {
	case DW_CFA_advance_loc:
		instruction = DW_CFA_advance_loc
		restore = true

	case DW_CFA_offset:
		instruction = DW_CFA_offset
		restore = true

	case DW_CFA_restore:
		instruction = DW_CFA_restore
		restore = true
	}

	if restore {
		// Restore the last byte as it actually contains the argument for the opcode.
		err := buf.UnreadByte()
		if err != nil {
			panic("Could not unread byte")
		}
	}

	return fnlookup[instruction]
}

func advanceloc(frame *FrameContext) {
	b, err := frame.buf.ReadByte()
	if err != nil {
		panic("Could not read byte")
	}

	delta := b & low_6_offset
	frame.loc += uint64(delta) * frame.codeAlignment
}

func advanceloc1(frame *FrameContext) {
	delta, err := frame.buf.ReadByte()

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Report it as a bug: a just-succeeded ReadByte followed by UnreadByte should not fail on the internal buffer
  2. Regenerate/recheck the binary being analyzed for corruption
  3. Wrap calls in recover() to convert the panic into a parse error
  4. Upgrade delve — parser robustness fixes may already exist

Example fix

// before
fde, err := frameTable.ExecuteUntilPC(pc) // may panic
// after
func safeLookup(t *frame.FrameDescriptionEntry) (out *frame.FrameDescriptionEntry, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("frame decode failed: %v", r)
        }
    }()
    return t, nil
}
Defensive patterns

Strategy: try-catch

Try / catch

func safeCFIParse(parse func()) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("frame decode failed: %v", r)
        }
    }()
    parse()
    return nil
}

Prevention

When it happens

Trigger: Decoding an extended DWARF CFI opcode (DW_CFA_advance_loc family / restore handling) where the last byte read is the opcode argument; only occurs if the byte-slice-backed buffer is mis-positioned or a custom/different buffer type is passed into the frame parser.

Common situations: Practically rare for users; seen when the frame table is constructed over unexpected data, or in fuzzing/corpus testing of pkg/dwarf/frame with malformed inputs.

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/c7b4ebeae56b894d. Report an issue: GitHub.