{"record":{"id":"c7b4ebeae56b894d","repo":"go-delve/delve","slug":"could-not-unread-byte","errorCode":null,"errorMessage":"Could not unread byte","messagePattern":"Could not unread byte","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/dwarf/frame/table.go","lineNumber":245,"sourceCode":"\tswitch instruction & high_2_bits {\n\tcase DW_CFA_advance_loc:\n\t\tinstruction = DW_CFA_advance_loc\n\t\trestore = true\n\n\tcase DW_CFA_offset:\n\t\tinstruction = DW_CFA_offset\n\t\trestore = true\n\n\tcase DW_CFA_restore:\n\t\tinstruction = DW_CFA_restore\n\t\trestore = true\n\t}\n\n\tif restore {\n\t\t// Restore the last byte as it actually contains the argument for the opcode.\n\t\terr := buf.UnreadByte()\n\t\tif err != nil {\n\t\t\tpanic(\"Could not unread byte\")\n\t\t}\n\t}\n\n\treturn fnlookup[instruction]\n}\n\nfunc advanceloc(frame *FrameContext) {\n\tb, err := frame.buf.ReadByte()\n\tif err != nil {\n\t\tpanic(\"Could not read byte\")\n\t}\n\n\tdelta := b & low_6_offset\n\tframe.loc += uint64(delta) * frame.codeAlignment\n}\n\nfunc advanceloc1(frame *FrameContext) {\n\tdelta, err := frame.buf.ReadByte()","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/dwarf/frame/table.go#L227-L263","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Report it as a bug: a just-succeeded ReadByte followed by UnreadByte should not fail on the internal buffer","Regenerate/recheck the binary being analyzed for corruption","Wrap calls in recover() to convert the panic into a parse error","Upgrade delve — parser robustness fixes may already exist"],"exampleFix":"// before\nfde, err := frameTable.ExecuteUntilPC(pc) // may panic\n// after\nfunc safeLookup(t *frame.FrameDescriptionEntry) (out *frame.FrameDescriptionEntry, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"frame decode failed: %v\", r)\n        }\n    }()\n    return t, nil\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"func safeCFIParse(parse func()) (err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"frame decode failed: %v\", r)\n        }\n    }()\n    parse()\n    return nil\n}","preventionTips":["Treat any panic from pkg/dwarf/frame as malformed-input, not a caller bug","Recover at the outermost frame-parsing boundary and skip affected frames","Report reproducible panics upstream — these should be error returns","Test with fuzzed ELF inputs if you embed the parser in your tooling"],"tags":["dwarf","panic","frame-parsing"],"backgroundTag":"malformed-dwarf-data","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}