Skip to content

proc: fuzz eval stack machine and harden call-injection paths - #4420

Open
derekparker wants to merge 9 commits into
go-delve:masterfrom
derekparker:design/eval-fuzz-improvements
Open

proc: fuzz eval stack machine and harden call-injection paths#4420
derekparker wants to merge 9 commits into
go-delve:masterfrom
derekparker:design/eval-fuzz-improvements

Conversation

@derekparker

Copy link
Copy Markdown
Member

Follow-up to #4412. Adds two in-process fuzzers for paths FuzzEvalExpression
never sees, and uses them to close real eval / call-injection bugs.

  • FuzzEvalStackOps feeds opcode programs to evalStack. The decoder is
    total (tag % N), jump targets are remapped to the actual program length,
    and the filter is DepthCheck(ops, -1) (underflow / joins only — not
    Compile's end-depth 0/1, so Roll actually runs).
  • FuzzCallInjectionProtocol drives real funcCallStep /
    funcCallFinish / evalStack.run with a mock protocol register, covering
    premature RestoreRegisters without a live debugCallV2 target.
  • FuzzEvalExpression takes a second string input and seeds a sample of
    real and invalid expressions.

Production fixes found along the way:

[Disclaimer: fuzz tests added via AI assistance]

Improve FuzzEvalExpression with expression-string mutation and a shared
internal-error helper. Add FuzzEvalStackOps (opcode programs) and
FuzzCallInjectionProtocol (mock debugCall register sequences). Guard
empty fncalls before CallInjectionSetTarget (go-delve#4085/go-delve#4363), bound
evalStack.run against infinite JumpAlways cycles, and smoke the new
fuzzers from the CI fuzz script.
Move the stack-depth validation used by Compile out of compileCtx so
tests can call the same implementation. FuzzEvalStackOps primary mode
now filters via evalop.DepthCheck instead of a parallel reimplementation.
Replace manual slice indexing with bytes.Reader and small read
helpers so truncated fuzz inputs stay easy to follow.
Collapse Test*_Foo top-level tests into shared suites so related
cases share structure and setup more cleanly.
Roll.depthCheck reported (1,1) but executeOp indexes N+1 stack
slots, so the shared DepthCheck filter admitted programs that
panicked. Align the check with the real access and drop decoder
ops that fail as type mismatches rather than depth errors.
Move the two jump cases Compile never emits into TestDepthCheck and
delete TestEvalStackOpsDepthOK, which only retested the one-line
fuzz filter.
Drop the compileCtx.depthCheck trampoline; CompileAST and CompileSet
already have the ops slice.
Drop export_test.go's trampoline; proc_test can use the capitalized
helper from fuzz_helpers_test.go directly.
Make the opcode decoder total, skip Compile end-depth in the fuzz
filter, and run 5s smokes only in fuzz mode so TeamCity seed stays a
corpus check. Guard remaining empty-fncall peeks, bound JumpAlways
cycles with a length-relative step limit, and gitignore setup dumps.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant