Fuzz Testing
HSD-Fortran includes infrastructure for coverage-guided fuzz testing using AFL++. Fuzz testing automatically generates thousands of malformed inputs to find edge cases, crashes, and bugs that manual testing might miss.
Prerequisites
Install AFL++ on Ubuntu/Debian:
sudo apt-get install afl++
For QEMU mode (binary-level instrumentation), you’ll need to build QEMU support:
cd /tmp
git clone --depth 1 https://github.com/AFLplusplus/AFLplusplus.git
cd AFLplusplus && make source-only
cd qemu_mode && ./build_qemu_support.sh
sudo cp ../afl-qemu-trace /usr/bin/
Building the Fuzz Target
The fuzz testing infrastructure is in the utils/fuzz/ directory:
cd hsd-fortran
# Build with regular gfortran
cmake -B build-fuzz -S utils/fuzz
cmake --build build-fuzz
This creates build-fuzz/hsd_fuzz_stdin, a standalone driver that reads HSD input from stdin.
Running the Fuzzer
Basic Usage
cd build-fuzz
# Copy seed corpus and dictionary
cp -r ../utils/fuzz/corpus .
cp ../utils/fuzz/hsd.dict .
# Create output directory
mkdir -p findings
# Run AFL++ with QEMU mode (coverage-guided)
afl-fuzz -Q -i corpus -o findings -x hsd.dict -- ./hsd_fuzz_stdin
AFL++ will display a status screen showing:
Execution speed (execs/sec)
Code coverage (map density)
Crashes and hangs found
Corpus growth over time
Press Ctrl+C to stop.
Using the Dictionary
The hsd.dict file contains HSD-specific tokens ({, }, <<<, Yes, etc.) that help AFL++ generate syntactically meaningful inputs:
afl-fuzz -Q -i corpus -o findings -x hsd.dict -- ./hsd_fuzz_stdin
Parallel Fuzzing
To utilize multiple CPU cores:
# Terminal 1 - Main fuzzer
afl-fuzz -Q -i corpus -o findings -M main -- ./hsd_fuzz_stdin
# Terminal 2+ - Secondary fuzzers
afl-fuzz -Q -i corpus -o findings -S fuzzer2 -- ./hsd_fuzz_stdin
afl-fuzz -Q -i corpus -o findings -S fuzzer3 -- ./hsd_fuzz_stdin
Understanding Output
AFL++ creates these directories in findings/:
Directory |
Contents |
|---|---|
|
Inputs that discovered new code paths |
|
Inputs that caused crashes |
|
Inputs that caused timeouts |
Reproducing Issues
To reproduce a crash:
./hsd_fuzz_stdin < findings/crashes/id:000000*
# With a debugger
gdb -ex run -ex bt --args ./hsd_fuzz_stdin < findings/crashes/id:000000*
Corpus Management
Minimizing the Corpus
After fuzzing, minimize the corpus to remove redundant inputs:
afl-cmin -Q -i findings/queue -o corpus_min -- ./hsd_fuzz_stdin
Minimizing a Crash
Reduce a crashing input to its minimal form:
afl-tmin -Q -i findings/crashes/id:000000 -o crash_min -- ./hsd_fuzz_stdin
Seed Corpus
The utils/fuzz/corpus/ directory contains seed inputs covering various HSD features:
minimal.hsd- Simple key-valuesection.hsd- Nested sectionsarray.hsd- Array valuesattrib.hsd- Attributes with unitsbool.hsd- Boolean valuesstring.hsd- Quoted stringsnested.hsd- Deeply nested structurecomment.hsd- Commentsempty.hsd- Empty inputfloat.hsd- Floating-point numbers
Add more seeds relevant to your use case for better coverage.
Troubleshooting
“afl-qemu-trace not found”
QEMU mode isn’t installed. See Prerequisites above to build it.
“Hmm, your system is configured to send core dump notifications”
sudo sh -c 'echo core > /proc/sys/kernel/core_pattern'
Low Execution Speed
Use a RAM disk:
mount -t tmpfs -o size=1G tmpfs /tmp/fuzzQEMU mode is 2-5x slower than native instrumentation; this is expected
Typical speed for HSD parsing: 100-300 exec/s in QEMU mode
AFL++ Shows 0 Paths
Ensure you’re using QEMU mode (
-Qflag) for Fortran codeCheck that
afl-qemu-traceis installed correctly