-
Notifications
You must be signed in to change notification settings - Fork 77
Open
Description
Hello, developers.
I’m trying to use Fuzz Introspector’s RuntimeCoverageAnalysis on an lcms target built with the FI-provided LLVM toolchain and llvm-cov show -show-branches=count. The HTML report is generated correctly and other analyses work (OptimalTargets, AnnotatedCFG, etc.), but branch blockers are never found:
- The log shows:
overlay_calltree_with_coverage: [+] found 0 branch blockers. - The generated
branch-blockers.jsoncontains an empty list:
{"cms_transform_fuzzer": []}This happens even though the cms_transform_fuzzer.covreport file clearly contains many Branch (line:col): [True: X, False: Y] entries from llvm-cov.
Environment
- Fuzz Introspector: built from
main - FI checkout path:
/home/fa1c4/Desktop/fuzz-introspector - FI layout:
pwd && ls
/home/fa1c4/Desktop/fuzz-introspector
api_test.sh build_all.sh ci_checks.sh CODE_OF_CONDUCT.md Dockerfile LICENSE README.md scripts src tools
build CHARTER.pdf code_checks.sh doc frontends oss_fuzz_integration requirements.txt SECURITY.md tests- LLVM/clang: using the toolchain built by FI (from
build/llvm-build/bin):
FI_ROOT=/home/fa1c4/Desktop/fuzz-introspector
CLANG_BASE="$FI_ROOT/build/llvm-build/bin"
export PATH="$CLANG_BASE:$PATH"
export AR="$CLANG_BASE/llvm-ar"
export RANLIB="$CLANG_BASE/llvm-ranlib"
export CC="$CLANG_BASE/clang"
export CXX="$CLANG_BASE/clang++"
❯ $FI_ROOT/build/llvm-build/bin/clang --version
clang version 21.1.0-rc3 (https://github.com/llvm/llvm-project/ 6096d35ea93c75f648a253a00775b4d74915c819)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/fa1c4/Desktop/fuzz-introspector/build/llvm-build/bin
❯ $FI_ROOT/build/llvm-build/bin/llvm-cov --version
LLVM (http://llvm.org/):
LLVM version 21.1.0-rc3
Optimized build.Target: lcms (Little CMS) + FI
Build script
This is the script I use to build lcms with FI instrumentation and coverage:
#!/usr/bin/env bash
# FI_build_lcms.sh: build lcms target with Fuzz Introspector + coverage
set -euo pipefail
set -x
ROOT=$(pwd)
# Path to Fuzz Introspector checkout (adjust if different)
FI_ROOT=/home/fa1c4/Desktop/fuzz-introspector
CLANG_BASE="$FI_ROOT/build/llvm-build/bin"
export PATH="$CLANG_BASE:$PATH"
export AR="$CLANG_BASE/llvm-ar"
export RANLIB="$CLANG_BASE/llvm-ranlib"
export CC="$CLANG_BASE/clang"
export CXX="$CLANG_BASE/clang++"
# Common compile flags: hardening + coverage + FI instrumentation
common_cflags="-O2 -Wall -Wextra -D_FORTIFY_SOURCE=2 \
-fstack-protector-strong -fstack-clash-protection \
-fPIE -pie -fPIC -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,separate-code \
-fprofile-instr-generate -fcoverage-mapping \
-fsanitize=fuzzer-no-link -g -flto"
export CFLAGS="$common_cflags"
export CXXFLAGS="$common_cflags -std=c++11"
# Link with libFuzzer (FI uses this)
export LIB_FUZZING_ENGINE="-fsanitize=fuzzer"
# Enable Fuzz Introspector instrumentation in clang
export FUZZ_INTROSPECTOR=1
# Clean previous build
[ -d ./lcms ] && rm -rf lcms
[ -d ./out ] && rm -rf out
mkdir ./out
# Get lcms + fuzzer harness
git clone https://github.com/mm2/Little-CMS.git lcms
cp /home/fa1c4/Desktop/lcms_cov/ext1_cms_transform_fuzzer.cc ./lcms/cms_transform_fuzzer.cc
export SRC="$ROOT/lcms"
export OUT="$ROOT/out"
cd "$SRC"
./autogen.sh
./configure
# Optional: use gold for faster LTO, like jsoncpp FI example
export LDFLAGS="-fuse-ld=gold"
# Keep bear so you still get compile_commands.json if you need it
bear -- make -j"$(nproc)" clean
bear -- make -j"$(nproc)" all
# Build FI-instrumented libFuzzer target
$CXX $CXXFLAGS cms_transform_fuzzer.cc -I include/ src/.libs/liblcms2.a \
$LIB_FUZZING_ENGINE -o "$OUT/cms_transform_fuzzer"
echo "[+] Done Building (FI): $OUT/cms_transform_fuzzer"
Steps to reproduce
1. Build lcms target with FI
cd /home/fa1c4/Desktop/fuzz-introspector
# (Build FI + LLVM toolchain via repo scripts, then:)
cd /home/fa1c4/Desktop
./FI_build_lcms.sh
Relevant build log (tail):
[Log level 1] : 09:37:14 : Fuzz introspector is running
[Log level 2] : 09:37:14 : Using default configuration
[Log level 1] : 09:37:14 : Running introspector on ld-temp.o
[Log level 1] : 09:37:14 : This is a fuzzer, performing analysis
[Log level 1] : 09:37:14 : Logging next yaml tile to fuzzerLogFile-0-1rgEopXyfV.data.yaml
[Log level 1] : 09:37:14 : Wrapping all functions
[Log level 1] : 09:37:15 : Ended wrapping all functions
[Log level 1] : 09:37:15 : Finished introspector module
[+] Done Building (FI): /home/fa1c4/Desktop/lcms_cov/out/cms_transform_fuzzer
2. Run the fuzzer once to collect coverage
cd /home/fa1c4/Desktop/lcms_cov/out
LLVM_PROFILE_FILE=cms_transform_fuzzer.profraw \
./cms_transform_fuzzer ../corpus -runs=0
Example output:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1129346469
INFO: Loaded 1 modules (7552 inline 8-bit counters): 7552 [0x..., 0x...),
INFO: Loaded 1 PC tables (7552 PCs): 7552 [0x...,0x...),
INFO: 1058 files found in ../corpus
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 34798 bytes
INFO: seed corpus: files: 1058 min: 2b max: 34798b total: 1768529b rss: 29Mb
#512 pulse cov: 1284 ft: 2874 corp: 344/252Kb exec/s: 170 rss: 211Mb
#1024 pulse cov: 1433 ft: 3359 corp: 593/639Kb exec/s: 170 rss: 211Mb
#1059 INITED cov: 1436 ft: 3377 corp: 607/811Kb exec/s: 176 rss: 211Mb
#1059 DONE cov: 1436 ft: 3377 corp: 607/811Kb lim: 32548 exec/s: 176 rss: 211Mb
Done 1059 runs in 6 second(s)
3. Generate coverage report with llvm-cov
LLVM_BIN=/home/fa1c4/Desktop/fuzz-introspector/build/llvm-build/bin
$LLVM_BIN/llvm-profdata merge -sparse cms_transform_fuzzer.profraw \
-o cms_transform_fuzzer.profdata
$LLVM_BIN/llvm-cov show \
-instr-profile=cms_transform_fuzzer.profdata \
-object=./cms_transform_fuzzer \
-show-branches=count \
-line-coverage-gt=0 \
> cms_transform_fuzzer.covreport
At this point cms_transform_fuzzer.covreport contains many Branch (line:col): [True: X, False: Y] lines (and of course line coverage entries).
4. Copy FI raw data
cp ../lcms/fuzzerLogFile-0-*.data* .
ls
cms_transform_fuzzer cms_transform_fuzzer.profraw fuzzerLogFile-0-1rgEopXyfV.data.debug_all_globals fuzzerLogFile-0-1rgEopXyfV.data.yaml
cms_transform_fuzzer.covreport fuzzerLogFile-0-1rgEopXyfV.data fuzzerLogFile-0-1rgEopXyfV.data.debug_all_types
cms_transform_fuzzer.profdata fuzzerLogFile-0-1rgEopXyfV.data.debug_all_functions fuzzerLogFile-0-1rgEopXyfV.data.debug_info5. Correlate binaries to FI logs
python /home/fa1c4/Desktop/fuzz-introspector/src/main.py \
correlate --binaries-dir=.
2025-12-09 09:41:09.143 INFO cli - main: Running fuzz introspector post-processing
2025-12-09 09:41:09.144 INFO utils - scan_executables_for_fuzz_introspector_logs: File: ./cms_transform_fuzzer is executable
2025-12-09 09:41:09.304 INFO utils - scan_executables_for_fuzz_introspector_logs: Found match fuzzerLogFile-0-1rgEopXyfV
2025-12-09 09:41:09.306 INFO commands - correlate_binaries_to_logs: Pairings: [{'executable_path': './cms_transform_fuzzer', 'fuzzer_log_file': 'fuzzerLogFile-0-1rgEopXyfV'}]
2025-12-09 09:41:09.308 INFO cli - main: Ending fuzz introspector post-processing
SRC="/home/fa1c4/Desktop/lcms_cov/lcms" QT_QPA_PLATFORM=offscreen \
python /home/fa1c4/Desktop/fuzz-introspector/src/main.py report \
--target-dir=. \
--correlation-file=./exe_to_fuzz_introspector_logs.yaml \
--analyses OptimalTargets RuntimeCoverageAnalysis \
FuzzEngineInputAnalysis AnnotatedCFG \
--output-json OptimalTargets RuntimeCoverageAnalysis \
FuzzEngineInputAnalysis AnnotatedCFG
...
2025-12-09 09:41:17.689 INFO fuzzer_profile - accummulate_profile: cms_transform_fuzzer: loading coverage
2025-12-09 09:41:17.690 INFO fuzzer_profile - _load_coverage: Loading coverage of type c-cpp
2025-12-09 09:41:17.690 INFO code_coverage - load_llvm_coverage: Loading LLVM coverage for target cms_transform_fuzzer
2025-12-09 09:41:17.691 INFO code_coverage - load_llvm_coverage: Found 1 coverage reports
2025-12-09 09:41:17.691 INFO code_coverage - load_llvm_coverage: Using the following coverages ['./cms_transform_fuzzer.covreport']
2025-12-09 09:41:17.691 INFO code_coverage - load_llvm_coverage: Reading coverage report: ./cms_transform_fuzzer.covreport
...
2025-12-09 09:41:18.057 INFO utils - get_target_coverage_url: Extracting coverage for /covreport/linux -- cms_transform_fuzzer
2025-12-09 09:41:18.057 INFO analysis - overlay_calltree_with_coverage: Using coverage url: /covreport/linux
...
2025-12-09 09:41:18.111 INFO analysis - overlay_calltree_with_coverage: Updating branch complexities
2025-12-09 09:41:18.115 INFO analysis - overlay_calltree_with_coverage: [+] found 0 branch blockers.
7. branch-blockers.json content
cat branch-blockers.json
{"cms_transform_fuzzer": []}Observed behavior
- FI clearly loads the
.covreportand uses it (the HTML report shows line coverage; OptimalTargets etc. work). - However,
RuntimeCoverageAnalysis/ branch blocker discovery always finds zero branch blockers:
2025-12-09 09:41:18.115 INFO analysis - overlay_calltree_with_coverage: [+] found 0 branch blockers.- This is surprising because the
cms_transform_fuzzer.covreportfile fromllvm-cov show -show-branches=countdoes include manyBranch (line:col): [True: X, False: Y]entries for the lcms code (e.g.,Branch (7:7): [True: 2, False: 1.05k], etc.).
Expected behavior
Given that:
- The coverage report includes branch coverage (
Branch (line:col)), - FI successfully sees the coverage file and uses it,
- And
RuntimeCoverageAnalysisruns without errors,
…I expected:
overlay_calltree_with_coverageto detect some branch blockers in the lcms call tree, andbranch-blockers.jsonto contain a non-empty list of blocker locations forcms_transform_fuzzer(or at least to reflect branches present in the coverage report).
Questions / help requested
- Is there a known incompatibility between the current
llvm-cov showoutput (with-show-branches=count) and the branch coverage parsing incode_coverage.load_llvm_coverage? - Is my
llvm-cov showinvocation missing flags that FI expects for branch blocker analysis? - Could
branch_cov_mapbe staying empty due to assumptions about the text format that have changed in newer LLVM versions?
Metadata
Metadata
Assignees
Labels
No labels