Skip to content

Commit 03da31a

Browse files
committed
Split fuzz runners by hash mode
Move shared fuzz logic into the root fuzz crate and generate fake-hashes and real-hashes runner crates. Keep `chanmon_consistency_target` on the real-hashes side, remove the fuzz-local Cargo config, and update scripts, CI, coverage, and docs to use explicit flags for each runner. Generate the hash-mode compile checks in the wrapper bins without a synthetic Cargo feature, while keeping the wrapper template close to its original shape. AI tools were used in preparing this commit.
1 parent ebf698e commit 03da31a

89 files changed

Lines changed: 490 additions & 383 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,8 @@ jobs:
218218
- name: Sanity check fuzz targets on Rust ${{ env.TOOLCHAIN }}
219219
run: |
220220
cd fuzz
221-
cargo test --quiet --color always --lib --bins -j8
221+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" cargo test --manifest-path fuzz-fake-hashes/Cargo.toml --quiet --color always --bins -j8
222+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz" cargo test --manifest-path fuzz-real-hashes/Cargo.toml --quiet --color always --bins -j8
222223
223224
fuzz:
224225
runs-on: self-hosted

ci/check-compiles.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ echo "Testing $(git log -1 --oneline)"
55
cargo check
66
cargo doc
77
cargo doc --document-private-items
8-
cd fuzz && RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" cargo check --features=stdin_fuzz
8+
cd fuzz
9+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
10+
cargo check --manifest-path fuzz-fake-hashes/Cargo.toml --features=stdin_fuzz
11+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz" \
12+
cargo check --manifest-path fuzz-real-hashes/Cargo.toml --features=stdin_fuzz
913
cd ../lightning && cargo check --no-default-features
1014
cd .. && RUSTC_BOOTSTRAP=1 RUSTFLAGS="--cfg=c_bindings" cargo check -Z avoid-dev-deps

contrib/generate_fuzz_coverage.sh

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ mkdir -p "$OUTPUT_DIR"
5757

5858
# dont run this command when running in CI
5959
if [ "$OUTPUT_CODECOV_JSON" = "0" ]; then
60-
cargo llvm-cov --html \
60+
cargo llvm-cov clean --workspace
61+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
62+
cargo llvm-cov --manifest-path fuzz-fake-hashes/Cargo.toml --no-report --tests
63+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz" \
64+
cargo llvm-cov --manifest-path fuzz-real-hashes/Cargo.toml --no-report --tests
65+
cargo llvm-cov report --manifest-path Cargo.toml --html \
6166
--dep-coverage lightning,lightning-invoice,lightning-liquidity,lightning-rapid-gossip-sync,lightning-persister \
6267
--no-default-ignore-filename-regex \
6368
--ignore-filename-regex "(\.cargo/registry|\.rustup/toolchains|/fuzz/)" \
@@ -82,11 +87,15 @@ else
8287
fi
8388

8489
echo "Replaying imported corpus (if found) via tests to generate coverage..."
85-
cargo llvm-cov -j8 --codecov \
90+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
91+
cargo llvm-cov --manifest-path fuzz-fake-hashes/Cargo.toml --no-report --tests
92+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz" \
93+
cargo llvm-cov --manifest-path fuzz-real-hashes/Cargo.toml --no-report --tests
94+
cargo llvm-cov report --manifest-path Cargo.toml --codecov \
8695
--dep-coverage lightning,lightning-invoice,lightning-liquidity,lightning-rapid-gossip-sync,lightning-persister \
8796
--no-default-ignore-filename-regex \
8897
--ignore-filename-regex "(\.cargo/registry|\.rustup/toolchains|/fuzz/)" \
89-
--output-path "$OUTPUT_DIR/fuzz-codecov.json" --tests
98+
--output-path "$OUTPUT_DIR/fuzz-codecov.json"
9099

91100
echo "Fuzz codecov report available at $OUTPUT_DIR/fuzz-codecov.json"
92101
fi

fuzz/.cargo/config.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

fuzz/Cargo.toml

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,6 @@ version = "0.0.1"
44
authors = ["Automatically generated"]
55
publish = false
66
edition = "2021"
7-
# Because the function is unused it gets dropped before we link lightning, so
8-
# we have to duplicate build.rs here. Note that this is only required for
9-
# fuzzing mode.
10-
11-
[package.metadata]
12-
cargo-fuzz = true
13-
14-
[features]
15-
afl_fuzz = ["afl"]
16-
honggfuzz_fuzz = ["honggfuzz"]
17-
libfuzzer_fuzz = ["libfuzzer-sys"]
18-
stdin_fuzz = []
197

208
[dependencies]
219
lightning = { path = "../lightning", features = ["regex", "_test_utils"] }
@@ -27,16 +15,9 @@ bech32 = "0.11.0"
2715
bitcoin = { version = "0.32.4", features = ["secp-lowmemory"] }
2816
tokio = { version = "~1.35", default-features = false, features = ["rt-multi-thread"] }
2917

30-
afl = { version = "0.12", optional = true }
31-
honggfuzz = { version = "0.5", optional = true, default-features = false }
32-
libfuzzer-sys = { version = "0.4", optional = true }
33-
34-
[build-dependencies]
35-
cc = "1.0"
36-
3718
# Prevent this from interfering with workspaces
3819
[workspace]
39-
members = ["."]
20+
members = [".", "fuzz-fake-hashes", "fuzz-real-hashes", "write-seeds"]
4021

4122
[profile.release]
4223
panic = "abort"

fuzz/README.md

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ configured for. Fuzzing is further only effective with a lot of CPU time, indica
1010
scenarios are discovered on CI with its low runtime constraints, the crash is caused relatively
1111
easily.
1212

13+
The `fuzz/` directory now contains three crates:
14+
- `fuzz/`, the shared fuzz target logic and corpus directories
15+
- `fuzz/fuzz-fake-hashes`, the fuzz targets that require `--cfg=hashes_fuzz`
16+
- `fuzz/fuzz-real-hashes`, the real-hashes fuzz targets, currently `chanmon_consistency_target`
17+
1318
## How do I run fuzz tests locally?
1419

1520
We support multiple fuzzing engines such as `honggfuzz`, `libFuzzer` and `AFL`. You typically won't
@@ -47,34 +52,46 @@ cargo install --force cargo-fuzz
4752
To run fuzzing using `honggfuzz`, do
4853

4954
```shell
55+
cd fuzz
5056
export CPU_COUNT=1 # replace as needed
5157
export HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz"
5258
export HFUZZ_RUN_ARGS="-n $CPU_COUNT --exit_upon_crash"
59+
export HFUZZ_WORKSPACE="./hfuzz_workspace"
5360

5461
export TARGET="msg_ping_target" # replace with the target to be fuzzed
55-
cargo hfuzz run $TARGET
62+
export RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz"
63+
cargo hfuzz run --manifest-path fuzz-fake-hashes/Cargo.toml $TARGET
5664
```
5765

58-
(Or, for a prettier output, replace the last line with `cargo --color always hfuzz run $TARGET`.)
66+
(For `fuzz-real-hashes`, use
67+
`RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz" cargo hfuzz run --manifest-path fuzz-real-hashes/Cargo.toml chanmon_consistency_target`.)
68+
For a prettier output, replace the last line with
69+
`cargo --color always hfuzz run --manifest-path fuzz-fake-hashes/Cargo.toml $TARGET`.
5970

6071
#### cargo-fuzz / libFuzzer
6172
To run fuzzing using `cargo-fuzz / libFuzzer`, run
6273

6374
```shell
6475
rustup install nightly # Note: libFuzzer requires a nightly version of rust.
76+
cd fuzz
6577
export RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz"
66-
cargo +nightly fuzz run --features "libfuzzer_fuzz" msg_ping_target
78+
cargo +nightly fuzz run --manifest-path fuzz-fake-hashes/Cargo.toml --features "libfuzzer_fuzz" msg_ping_target
6779
```
6880
Note: If you encounter a `SIGKILL` during run/build check for OOM in kernel logs and consider
6981
increasing RAM size for VM.
7082

83+
For `fuzz-real-hashes`, use
84+
`RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz" cargo +nightly fuzz run --manifest-path fuzz-real-hashes/Cargo.toml --features "libfuzzer_fuzz" chanmon_consistency_target`.
85+
7186
##### Fast builds for development
7287

7388
The default build uses LTO and single codegen unit, which is slow. For faster iteration during
7489
development, use the `-D` (dev) flag:
7590

7691
```shell
77-
cargo +nightly fuzz run --features "libfuzzer_fuzz" -D msg_ping_target
92+
cd fuzz
93+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
94+
cargo +nightly fuzz run --manifest-path fuzz-fake-hashes/Cargo.toml --features "libfuzzer_fuzz" -D msg_ping_target
7895
```
7996

8097
The `-D` flag builds in development mode with faster compilation (still has optimizations via
@@ -83,7 +100,9 @@ sanitizer instrumentation, but subsequent builds will be fast.
83100

84101
If you wish to just generate fuzzing binary executables for `libFuzzer` and not run them:
85102
```shell
86-
cargo +nightly fuzz build --features "libfuzzer_fuzz" msg_ping_target
103+
cd fuzz
104+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
105+
cargo +nightly fuzz build --manifest-path fuzz-fake-hashes/Cargo.toml --features "libfuzzer_fuzz" msg_ping_target
87106
# Generates binary artifact in path ./target/aarch64-unknown-linux-gnu/release/msg_ping_target
88107
# Exact path depends on your system architecture.
89108
```
@@ -93,7 +112,8 @@ You can upload the build artifact generated above to `ClusterFuzz` for distribut
93112
To see a list of available fuzzing targets, run:
94113

95114
```shell
96-
ls ./src/bin/
115+
ls ./fuzz-fake-hashes/src/bin/
116+
ls ./fuzz-real-hashes/src/bin/
97117
```
98118

99119
## A fuzz test failed, what do I do?
@@ -134,7 +154,8 @@ mkdir -p ./test_cases/$TARGET
134154
echo $HEX | xxd -r -p > ./test_cases/$TARGET/any_filename_works
135155

136156
export RUST_BACKTRACE=1
137-
cargo test
157+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
158+
cargo test --manifest-path fuzz-fake-hashes/Cargo.toml --bin "${TARGET}_target"
138159
```
139160

140161
Note that if the fuzz test failed locally, moving the offending run's trace
@@ -151,7 +172,10 @@ Alternatively, you can use the `stdin_fuzz` feature to pipe the crash input dire
151172
creating test case files on disk:
152173

153174
```shell
154-
echo -ne '\x2d\x31\x36\x38\x37\x34\x09\x01...' | cargo run --features stdin_fuzz --bin full_stack_target
175+
cd fuzz
176+
echo -ne '\x2d\x31\x36\x38\x37\x34\x09\x01...' | \
177+
RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz" \
178+
cargo run --manifest-path fuzz-fake-hashes/Cargo.toml --features stdin_fuzz --bin full_stack_target
155179
```
156180

157181
Panics will abort the process directly (the crate uses `panic = "abort"`), resulting in a
@@ -171,10 +195,13 @@ file are `do_test`, `my_fuzzy_experiment_test`, and `my_fuzzy_experiment_run`.
171195

172196
3. Adjust the body (not the signature!) of `do_test` as necessary for the new fuzz test.
173197

174-
4. In `fuzz/src/bin/gen_target.sh`, add a line reading `GEN_TEST my_fuzzy_experiment` to the
175-
first group of `GEN_TEST` lines (starting in line 9).
198+
4. In `fuzz/src/bin/gen_target.sh`, add a line reading `GEN_FAKE_HASHES_TEST my_fuzzy_experiment`
199+
to the appropriate target list. Use `GEN_REAL_HASHES_TEST` only for targets that must run without
200+
`hashes_fuzz`.
176201

177202
5. If your test relies on a new local crate, add that crate as a dependency to `fuzz/Cargo.toml`.
203+
If the dependency is only needed by a specific runner crate or fuzz engine setup, add it to the
204+
matching target crate under `fuzz/fuzz-fake-hashes/Cargo.toml` or `fuzz/fuzz-real-hashes/Cargo.toml` instead.
178205

179206
6. In `fuzz/src/lib.rs`, add the line `pub mod my_fuzzy_experiment`. Additionally, if
180207
you added a new crate dependency, add the `extern crate […]` import line.

fuzz/ci-fuzz.sh

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ rm msg_*.rs
88
[ "$(git diff)" != "" ] && exit 1
99
popd
1010
pushd src/bin
11-
rm *_target.rs
11+
rm -f ../../fuzz-fake-hashes/src/bin/*_target.rs ../../fuzz-real-hashes/src/bin/*_target.rs
1212
./gen_target.sh
1313
[ "$(git diff)" != "" ] && exit 1
1414
popd
1515

16-
export RUSTFLAGS="--cfg=secp256k1_fuzz --cfg=hashes_fuzz"
16+
export RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz"
1717

1818
mkdir -p hfuzz_workspace/full_stack_target/input
1919
pushd write-seeds
20-
RUSTFLAGS="$RUSTFLAGS --cfg=fuzzing" cargo run ../hfuzz_workspace/full_stack_target/input
20+
cargo run ../hfuzz_workspace/full_stack_target/input
2121
cargo clean
2222
popd
2323

@@ -27,57 +27,70 @@ cargo install --color always --force honggfuzz --no-default-features
2727
# compiler optimizations aren't necessary, so we turn off LTO
2828
sed -i 's/lto = true//' Cargo.toml
2929

30-
export HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz"
31-
32-
cargo --color always hfuzz build -j8
33-
3430
SUMMARY=""
3531

3632
check_crash() {
37-
local FILE=$1
38-
if [ -f "hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT" ]; then
39-
cat "hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT"
40-
for CASE in "hfuzz_workspace/$FILE"/SIG*; do
33+
local WORKSPACE_DIR=$1
34+
local FILE=$2
35+
if [ -f "$WORKSPACE_DIR/$FILE/HONGGFUZZ.REPORT.TXT" ]; then
36+
cat "$WORKSPACE_DIR/$FILE/HONGGFUZZ.REPORT.TXT"
37+
for CASE in "$WORKSPACE_DIR/$FILE"/SIG*; do
4138
cat "$CASE" | xxd -p
4239
done
4340
exit 1
4441
fi
4542
}
4643

47-
for TARGET in src/bin/*.rs; do
48-
FILENAME=$(basename $TARGET)
49-
FILE="${FILENAME%.*}"
50-
CORPUS_DIR="hfuzz_workspace/$FILE/input"
51-
CORPUS_COUNT=$(find "$CORPUS_DIR" -type f 2>/dev/null | wc -l)
52-
# Run 8x the corpus size plus a baseline, ensuring full corpus replay
53-
# with room for new mutations. The 10-minute hard cap (--run_time 600)
54-
# prevents slow-per-iteration targets from running too long.
55-
ITERATIONS=$((CORPUS_COUNT * 8 + 1000))
56-
HFUZZ_RUN_ARGS="--exit_upon_crash -q -n8 -t 3 -N $ITERATIONS --run_time 600"
57-
if [ "$FILE" = "chanmon_consistency_target" -o "$FILE" = "fs_store_target" ]; then
58-
HFUZZ_RUN_ARGS="$HFUZZ_RUN_ARGS -F 64"
59-
fi
60-
export HFUZZ_RUN_ARGS
61-
FUZZ_START=$(date +%s)
62-
cargo --color always hfuzz run $FILE
63-
FUZZ_END=$(date +%s)
64-
FUZZ_TIME=$((FUZZ_END - FUZZ_START))
65-
FUZZ_CORPUS_COUNT=$(find "$CORPUS_DIR" -type f 2>/dev/null | wc -l)
66-
check_crash "$FILE"
67-
if [ "$GITHUB_REF" = "refs/heads/main" ] || [ "$FUZZ_MINIMIZE" = "true" ]; then
68-
HFUZZ_RUN_ARGS="-M -q -n8 -t 3"
44+
run_targets() {
45+
local CRATE_DIR=$1
46+
local TARGET_RUSTFLAGS=$2
47+
48+
pushd "$CRATE_DIR"
49+
export HFUZZ_WORKSPACE="../hfuzz_workspace"
50+
export HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz"
51+
export RUSTFLAGS="$TARGET_RUSTFLAGS"
52+
cargo --color always hfuzz build -j8
53+
54+
for TARGET in src/bin/*.rs; do
55+
FILENAME=$(basename "$TARGET")
56+
FILE="${FILENAME%.*}"
57+
CORPUS_DIR="$HFUZZ_WORKSPACE/$FILE/input"
58+
CORPUS_COUNT=$(find "$CORPUS_DIR" -type f 2>/dev/null | wc -l)
59+
# Run 8x the corpus size plus a baseline, ensuring full corpus replay
60+
# with room for new mutations. The 10-minute hard cap (--run_time 600)
61+
# prevents slow-per-iteration targets from running too long.
62+
ITERATIONS=$((CORPUS_COUNT * 8 + 1000))
63+
HFUZZ_RUN_ARGS="--exit_upon_crash -q -n8 -t 3 -N $ITERATIONS --run_time 600"
64+
if [ "$FILE" = "chanmon_consistency_target" -o "$FILE" = "fs_store_target" ]; then
65+
HFUZZ_RUN_ARGS="$HFUZZ_RUN_ARGS -F 64"
66+
fi
6967
export HFUZZ_RUN_ARGS
70-
MIN_START=$(date +%s)
71-
cargo --color always hfuzz run $FILE
72-
MIN_END=$(date +%s)
73-
MIN_TIME=$((MIN_END - MIN_START))
74-
MIN_CORPUS_COUNT=$(find "$CORPUS_DIR" -type f 2>/dev/null | wc -l)
75-
check_crash "$FILE"
76-
SUMMARY="${SUMMARY}${FILE}|${ITERATIONS}|${CORPUS_COUNT}|${FUZZ_CORPUS_COUNT}|${FUZZ_TIME}|${MIN_CORPUS_COUNT}|${MIN_TIME}\n"
77-
else
78-
SUMMARY="${SUMMARY}${FILE}|${ITERATIONS}|${CORPUS_COUNT}|${FUZZ_CORPUS_COUNT}|${FUZZ_TIME}|-|-\n"
79-
fi
80-
done
68+
FUZZ_START=$(date +%s)
69+
cargo --color always hfuzz run "$FILE"
70+
FUZZ_END=$(date +%s)
71+
FUZZ_TIME=$((FUZZ_END - FUZZ_START))
72+
FUZZ_CORPUS_COUNT=$(find "$CORPUS_DIR" -type f 2>/dev/null | wc -l)
73+
check_crash "$HFUZZ_WORKSPACE" "$FILE"
74+
if [ "$GITHUB_REF" = "refs/heads/main" ] || [ "$FUZZ_MINIMIZE" = "true" ]; then
75+
HFUZZ_RUN_ARGS="-M -q -n8 -t 3"
76+
export HFUZZ_RUN_ARGS
77+
MIN_START=$(date +%s)
78+
cargo --color always hfuzz run "$FILE"
79+
MIN_END=$(date +%s)
80+
MIN_TIME=$((MIN_END - MIN_START))
81+
MIN_CORPUS_COUNT=$(find "$CORPUS_DIR" -type f 2>/dev/null | wc -l)
82+
check_crash "$HFUZZ_WORKSPACE" "$FILE"
83+
SUMMARY="${SUMMARY}${FILE}|${ITERATIONS}|${CORPUS_COUNT}|${FUZZ_CORPUS_COUNT}|${FUZZ_TIME}|${MIN_CORPUS_COUNT}|${MIN_TIME}\n"
84+
else
85+
SUMMARY="${SUMMARY}${FILE}|${ITERATIONS}|${CORPUS_COUNT}|${FUZZ_CORPUS_COUNT}|${FUZZ_TIME}|-|-\n"
86+
fi
87+
done
88+
89+
popd
90+
}
91+
92+
run_targets fuzz-fake-hashes "--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz"
93+
run_targets fuzz-real-hashes "--cfg=fuzzing --cfg=secp256k1_fuzz"
8194

8295
fmt_time() {
8396
local secs=$1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"coverage":{"/rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/core/src/panic.rs":{"86":"0/1","87":"0/1","88":"0/1"}}}

fuzz/fuzz-fake-hashes/Cargo.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[package]
2+
name = "lightning-fuzz-fake-hashes"
3+
version = "0.0.1"
4+
authors = ["Automatically generated"]
5+
publish = false
6+
edition = "2021"
7+
8+
[package.metadata]
9+
cargo-fuzz = true
10+
11+
[features]
12+
afl_fuzz = ["afl"]
13+
honggfuzz_fuzz = ["honggfuzz"]
14+
libfuzzer_fuzz = ["libfuzzer-sys"]
15+
stdin_fuzz = []
16+
17+
[dependencies]
18+
lightning-fuzz = { path = ".." }
19+
20+
afl = { version = "0.12", optional = true }
21+
honggfuzz = { version = "0.5", optional = true, default-features = false }
22+
libfuzzer-sys = { version = "0.4", optional = true }
23+
24+
[lints.rust.unexpected_cfgs]
25+
level = "forbid"
26+
# When adding a new cfg attribute, ensure that it is added to this list.
27+
check-cfg = [
28+
"cfg(fuzzing)",
29+
"cfg(secp256k1_fuzz)",
30+
"cfg(hashes_fuzz)",
31+
]

0 commit comments

Comments
 (0)