Skip to content

Commit 41c2a30

Browse files
committed
add fuzz coverage script
Signed-off-by: Prabhat Verma <[email protected]>
1 parent 7b45811 commit 41c2a30

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

contrib/generate_fuzz_coverage.sh

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/bin/bash
2+
set -e
3+
set -x
4+
5+
# Define the fuzz directory relative to the project root
6+
FUZZ_DIR="fuzz"
7+
8+
TOOLCHAIN="nightly"
9+
FEATURES="libfuzzer_fuzz"
10+
11+
# --- Dependencies ---
12+
echo "Checking/installing dependencies..."
13+
# cargo-llvm-cov implicitly uses/installs necessary LLVM tools
14+
rustup +${TOOLCHAIN} component add llvm-tools-preview
15+
# Check if cargo-llvm-cov is installed, install if not
16+
if ! cargo +${TOOLCHAIN} --list | grep -q "llvm-cov"; then
17+
echo "Installing cargo-llvm-cov..."
18+
cargo +${TOOLCHAIN} install cargo-llvm-cov
19+
fi
20+
21+
# Clean previous builds and coverage artifacts relative to project root
22+
echo "Cleaning previous build and coverage artifacts..."
23+
cargo +${TOOLCHAIN} clean
24+
rm -rf target/llvm-cov-target
25+
rm -rf target/coverage
26+
27+
echo "Running fuzz targets with cargo-llvm-cov to collect coverage..."
28+
export RUSTFLAGS="--cfg=fuzzing --cfg=secp256k1_fuzz --cfg=hashes_fuzz"
29+
30+
# Determine host triple dynamically for the --target flag
31+
HOST_TRIPLE=$(rustc +${TOOLCHAIN} --version --verbose | grep host | cut -d' ' -f2)
32+
if [ -z "$HOST_TRIPLE" ]; then
33+
echo "Error: Could not determine host triple."
34+
exit 1
35+
fi
36+
echo "Detected host triple: $HOST_TRIPLE"
37+
38+
COMBINED_FEATURES="$FEATURES,lightning/_test_utils,lightning/std,lightning-invoice/std"
39+
40+
# Iterate over target binaries located within the FUZZ_DIR
41+
for TARGET_PATH in "$FUZZ_DIR"/src/bin/*_target.rs; do
42+
FILENAME=$(basename "$TARGET_PATH")
43+
TARGET_NAME="${FILENAME%.*}" # Remove .rs extension
44+
TARGET_CORPUS_DIR="$FUZZ_DIR/corpus/$TARGET_NAME"
45+
46+
if [ -d "$TARGET_CORPUS_DIR" ]; then
47+
echo "Running cargo llvm-cov for target: $TARGET_NAME with corpus $TARGET_CORPUS_DIR"
48+
if ! CARGO_TARGET_DIR=./target cargo +${TOOLCHAIN} llvm-cov run --no-report --manifest-path "$FUZZ_DIR/Cargo.toml" --target "$HOST_TRIPLE" --features "$COMBINED_FEATURES" --bin "$TARGET_NAME" -- "$TARGET_CORPUS_DIR" -runs=1; then
49+
echo "Warning: Execution of $TARGET_NAME with cargo-llvm-cov finished with non-zero status."
50+
fi
51+
else
52+
echo "Warning: Corpus directory ($TARGET_CORPUS_DIR) not found for target $TARGET_NAME. Skipping."
53+
fi
54+
done
55+
56+
unset RUSTFLAGS
57+
58+
# Define paths relative to project root
59+
MERGED_PROFDATA_PATH="target/llvm-cov-target/fuzz.profdata"
60+
HTML_REPORT_DIR="target/coverage/html"
61+
mkdir -p "$HTML_REPORT_DIR"
62+
63+
# Find all .profraw files generated by the runs in target/ relative to root
64+
PROFRAW_FILES=$(find target/llvm-cov-target -name "*.profraw")
65+
66+
if [ -z "$PROFRAW_FILES" ]; then
67+
echo "Error: No .profraw files found in target/llvm-cov-target. Cannot generate coverage report."
68+
exit 1
69+
fi
70+
71+
# Merge .profraw files into a single .profdata file
72+
echo "Merging profraw files..."
73+
if ! llvm-profdata merge $PROFRAW_FILES -o "$MERGED_PROFDATA_PATH"; then
74+
echo "Error: llvm-profdata merge failed."
75+
exit 1
76+
fi
77+
echo "Merged profile data created at $MERGED_PROFDATA_PATH"
78+
79+
# Identify the instrumented binary files
80+
echo "Identifying instrumented binaries..."
81+
declare -a OBJECT_FLAGS
82+
BINARY_DIR="target/llvm-cov-target/$HOST_TRIPLE/debug"
83+
84+
# Re-iterate over target sources to get names
85+
for TARGET_PATH in "$FUZZ_DIR"/src/bin/*_target.rs; do
86+
FILENAME=$(basename "$TARGET_PATH")
87+
TARGET_NAME="${FILENAME%.*}"
88+
TARGET_CORPUS_DIR="$FUZZ_DIR/corpus/$TARGET_NAME"
89+
BINARY_PATH="$BINARY_DIR/$TARGET_NAME"
90+
91+
# Check if the corresponding corpus dir existed (meaning the target was likely run)
92+
# and if the binary file actually exists
93+
if [ -d "$TARGET_CORPUS_DIR" ] && [ -f "$BINARY_PATH" ]; then
94+
echo "Found binary for target $TARGET_NAME at $BINARY_PATH"
95+
OBJECT_FLAGS+=("-object" "$BINARY_PATH")
96+
else
97+
echo "Warning: Skipping binary for $TARGET_NAME (corpus dir existed: $([ -d "$TARGET_CORPUS_DIR" ] && echo true || echo false), binary exists: $([ -f "$BINARY_PATH" ] && echo true || echo false))"
98+
fi
99+
done
100+
101+
if [ ${#OBJECT_FLAGS[@]} -eq 0 ]; then
102+
echo "Error: No instrumented binaries found in $BINARY_DIR. Cannot generate report."
103+
exit 1
104+
fi
105+
106+
# Generate the HTML report using llvm-cov show
107+
echo "Generating HTML report using llvm-cov show..."
108+
IGNORE_REGEX="(/.cargo/|/${FUZZ_DIR}/|/target/|/contrib/|/tests/|/benches/|lightning-invoice/src/convert\.rs|lightning-block-sync/src/lib\.rs|lightning-net-tokio/src/lib\.rs|lightning-persister/src/lib\.rs|lightning-rapid-gossip-sync/src/lib\.rs|lightning-transaction-sync/src/lib\.rs|lightning/src/util/ser\.rs)"
109+
110+
# generate html report
111+
if ! llvm-cov show \
112+
"${OBJECT_FLAGS[@]}" \
113+
-instr-profile="$MERGED_PROFDATA_PATH" \
114+
-format=html \
115+
-output-dir="$HTML_REPORT_DIR" \
116+
-ignore-filename-regex="$IGNORE_REGEX" \
117+
-show-line-counts-or-regions \
118+
-show-instantiations=false; then
119+
echo "Error: llvm-cov show command failed."
120+
exit 1
121+
fi
122+
123+
# --- Done ---
124+
echo "--------------------------------------------------"
125+
echo "Combined coverage report generation finished."
126+
echo "Report available at: $HTML_REPORT_DIR/index.html"
127+
echo "--------------------------------------------------"

0 commit comments

Comments
 (0)