Fuzzing infrastructure for the Solidity compiler: AFL++ harnesses, fuzzers, and debug runners to reproduce findings.
Everything builds natively on the host — no Docker, no libc++.
build/— host gcc/clang:solc, the*_debug_runnercrash-repro tools, and the AFL toolchain (afl-clang-fast, afl-ts, grammar).build_afl/—afl-clang-fast++: the AFL fuzzers — protobuf harnesses (*_proto_ossfuzz_*) and the differential.solfuzzer (sol_afl_diff_runner).
They never share object files; rebuild one without touching the other.
git clone --recurse-submodules \
https://github.com/argotorg/solidity-fuzzing.git
cd solidity-fuzzing # or: git submodule update --init --recursiveNeeds: gcc/g++ (C++20), clang/clang++, llvm-dev, cmake (>=3.13), make, ninja, boost (incl. static libs), protobuf + abseil, protoc, ccache, gdb.
Apply the local solidity patches (idempotent):
for p in patches/*.patch; do
echo "Applying patch $p"
git apply --reverse --check "$p" 2>/dev/null || git apply "$p"
done# 1. solc + debug runners (build/)
mkdir -p build && cd build && cmake .. && make -j$(nproc) && cd ..
# 2. AFL toolchain — afl-clang-fast, afl-ts, grammar (needs llvm-dev)
make -C build -j$(nproc) aflplusplus afl_ts tree_sitter_solidity
# 3. AFL fuzzers (build_afl/)
tools/ossfuzz/build_ossfuzz.sh # protobuf fuzzers + LPM mutators
tools/afl/build_instrumented.sh # differential .sol fuzzertools/ossfuzz/build_ossfuzz.sh builds libprotobuf-mutator into deps_afl/
(against the system protobuf), one LPM custom mutator per grammar, and the
fuzzers into build_afl/. See tools/ossfuzz.
echo core | sudo tee /proc/sys/kernel/core_pattern # one-time, AFL needs it
# Protobuf fuzzers — afl-fuzz + the matching LPM grammar mutator:
tools/ossfuzz/run_ossfuzz_afl.sh sol_proto_ossfuzz_evmone corpus_sol
tools/ossfuzz/run_ossfuzz_afl.sh yul_proto_ossfuzz_evmone corpus_yul
tools/ossfuzz/run_ossfuzz_afl.sh sol_ice_ossfuzz seeds_sol_ice
# Differential .sol fuzzer (afl-ts AST mutator):
tools/afl/run_afl.sh # or run_afl_parallel.sh -j 8The LPM grammar mutator runs inside afl-fuzz. If it (or protobuf) corrupts the
heap, the worker dies with a bare malloc(): invalid next size and no stack.
This variant rebuilds just the mutator .so with AddressSanitizer and preloads
the runtime into afl-fuzz, so the faulting write aborts with a full trace.
tools/ossfuzz/run_ossfuzz_afl_asan.sh yul_proto_ossfuzz_evmone_ssacfg corpus_yul
JOBS=8 tools/ossfuzz/run_ossfuzz_afl_asan.sh yul_proto_ossfuzz_evmone_ssacfg corpus_yul
# reports land in <findings>/asan.<pid> (raw offsets — afl forces symbolize=0):
tools/ossfuzz/symbolize_asan.sh findings_asan_*/asan.*See tools/ossfuzz and tools/afl for the fuzzer lists, reproduction, and triage.
make -C build -j$(nproc) sol_afl_diff_runner
tools/afl/tests/run.sh # every inputs/*.sol must exit 0