Automated program repair with an LLM
Gives an LLM the crashing input and stack trace along with the code. It fixed 11 of 13 programs.
The question
LLMs read code well, but they can't see what a program does when it runs. For bugs like buffer overflows, it matters a lot which input crashes the program and where it crashes. I wanted to know how much that runtime evidence helps a model fix the crash.
The idea: use fuzzing to find crashes and GDB to locate them, then hand the model that evidence along with the code.
The pipeline
Six steps, then a loop
- Strip the comments from the source so the model can't lean on human hints. In later rounds the model's own comments stay in, as its memory of what it tried.
- Have the LLM write a script that generates valid starting inputs for the fuzzer, and note whether the program reads stdin or a file.
- Run AFL or AFL++ to find crashing inputs, then shrink each one to a minimal input with afl-tmin.
- Collect a stack trace for each crash with GDB. Deduplicate them with an FNV-1a hash and keep the five most representative.
- Give the model the code, the minimized crashing inputs and the traces, and ask for a patch.
- Compile and test each patch and score it: does it compile, does the crash go away, do the tests pass, and how much did it change. Loop, with the model remembering earlier attempts.
Results
Three ways of prompting, same 13 programs
I tested on 13 crashing C programs: 10 that I wrote and 3 from AFL's demos. I compared giving the model the code only, the code plus stack traces, and the code plus stack traces and crashing inputs.
- fixed, code only
- 38%
- fixed, with stack traces
- 69%
- fixed, with traces and crashing inputs
- 85%
- Code only: 5 of 13 fixed (38%), median 4 attempts.
- Code plus stack traces: 9 of 13 (69%), median 3 attempts.
- Code plus stack traces and crashing inputs: 11 of 13 (85%), median 2 attempts.
Runtime evidence roughly doubled the fix rate and halved the attempts needed.
Next
- Programs that span several files.
- Symbolic execution for better fault localization.
- The SARD and Juliet benchmarks.
- Parallel fuzzing, to find crashes faster.