Closed maflcko closed 4 days ago
What are the OS and the lcov version?
Either Ubuntu 24.04 or 24.10 should reproduce:
git checkout fa680ac6c016533ac512857647555c688c071b63 && mkdir -p empty_temp && cmake -B bld -DBUILD_FOR_FUZZING=ON -DSANITIZERS=fuzzer -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Coverage && cmake --build ./bld -j$( nproc ) && cmake -DJOBS=$( nproc ) -DFUZZ_SEED_CORPUS_DIR=$PWD/empty_temp -DLCOV_OPTS='--rc branch_coverage=1 --ignore-errors mismatch,inconsistent' -P bld/CoverageFuzz.cmake
The error for 24.04 is slightly different:
Processing src/util/CMakeFiles/bitcoin_util.dir/fs_helpers.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/strencodings.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/signalinterrupt.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/fs.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/exception.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/bip32.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/serfloat.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/time.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/feefrac.cpp.gcda
Processing src/util/CMakeFiles/bitcoin_util.dir/check.cpp.gcda
geninfo: ERROR: unable to open /b-c/bld/src/src/httpserver.cpp: No such file or directory
(use "geninfo --ignore-errors source ..." to bypass this error)
Deleting all .da files in src and subdirectories
Done.
lcov: ERROR: trace file 'fuzz_filtered.info' is empty
(use "lcov --ignore-errors empty ..." to bypass this error)
Combining tracefiles.
.. found 1 files to aggregate.
Merging fuzz_filtered.info..0 remaining
lcov: ERROR: trace file 'baseline_filtered.info' is empty
(use "lcov --ignore-errors empty ..." to bypass this error)
genhtml: ERROR: cannot read file fuzz_coverage.info!
Also, the exit code may not be passed up, which could be improved as well?
# echo $?
0
Normal coverage also fails.
What is the commit and the exact commands where it last worked?
Normal coverage also fails.
What is the commit and the exact commands where it last worked?
Working on it.
Normal coverage also fails.
What is the commit and the exact commands where it last worked?
Tested https://github.com/bitcoin/bitcoin/pull/30454 @ 41051290ab3b6c36312cec26a27f787cea9961b4 on Ubuntu 24.04 with the default gcc
and lcov
packages:
$ cmake -B build -DCMAKE_BUILD_TYPE=Coverage -DCMAKE_C_FLAGS="-fprofile-update=atomic" -DCMAKE_CXX_FLAGS="-fprofile-update=atomic"
$ cmake --build build
$ cmake -DLCOV_OPTS="--ignore-errors mismatch" -P build/Coverage.cmake
$ firefox ./build/test_bitcoin.coverage/index.html
$ firefox ./build/total.coverage/index.html
However, on my machine, I had to add --timeout-factor=4
.
Additional -DCMAKE_C_FLAGS="-fprofile-update=atomic"
became required after https://github.com/hebasto/bitcoin/pull/192.
Ah, so normal coverage may work with gcc. However, it would be nice if clang was supported as well (like it does with autotools).
cc @vasild
Ah, so normal coverage may work with gcc. However, it would be nice if clang was supported as well (like it does with autotools).
Tested https://github.com/bitcoin/bitcoin/pull/30454 @ 41051290ab3b6c36312cec26a27f787cea9961b4 on Ubuntu 24.10 with the default clang
and lcov
packages:
$ cmake -B build -DCMAKE_BUILD_TYPE=Coverage -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
$ cmake --build build
$ cmake -DLCOV_OPTS="--rc branch_coverage=1 --ignore-errors mismatch,inconsistent" -P build/Coverage.cmake
On Ubuntu 24.04 lcov
still randomly fails.
Did you pass -DJOBS=$( nproc )
?
Did you pass
-DJOBS=$( nproc )
?
I did. Why?
Because I couldn't find it in your commands to reproduce the failure, and it seems to be required locally to reproduce it.
I'll try to create a full testing matrix to see what works and what needs fixing.
Clang has its own coverage workflow, which produces superior results. It also supports gcc/gcov/lcov like workflow but I think it is a waste of time* to try to fix that (if it is broken) to force Clang through the gcc way, provided it has a better native way.
https://github.com/hebasto/bitcoin/pull/233 implements the Clang native workflow.
* my time, of course; ymmv
https://github.com/hebasto/bitcoin/issues/341#issuecomment-2310803071 claims that clang is working.
However, I can not get it to work with the same commands (there is no html generated). Can you double check or otherwise upload your html, or an excerpt from it?
https://github.com/hebasto/bitcoin/issues/341#issuecomment-2312165659 claims that the clang workflow is fixed in a pull request. However, the pull request looks outdated and probably needs rebase?
#341 (comment) claims that clang is working.
However, I can not get it to work with the same commands (there is no html generated). Can you double check or otherwise upload your html, or an excerpt from it?
https://github.com/hebasto/bitcoin/issues/341#issuecomment-2312165659 claims that the clang workflow is fixed in a pull request. However, the pull request looks outdated and probably needs rebase?
s/fixed/implemented/, Clang workflow is implemented in https://github.com/hebasto/bitcoin/pull/233, but it was NACKed by @fanquake. Having the native Clang workflow is not a blocker for the CMake switch, so I stopped working on it. Maybe I will find some motivation to come back to it after https://github.com/bitcoin/bitcoin/pull/30454 is merged.
#341 (comment) claims that clang is working. However, I can not get it to work with the same commands (there is no html generated). Can you double check or otherwise upload your html, or an excerpt from it?
Interesting. I guess it is flaky and this happened to pass for some reason.
I'll try to switch everything to G++, for now, as a workaround.
I tried to use GCC (on the autotools branch), but it had many problems:
__gcov_reset
(from https://github.com/bitcoin/bitcoin/pull/30156/files) doesn't seem to be doing anything. See for example https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/44cf2cd0ca789852/65ac5a6b0b3f11ad/fuzz.coverage/src/test/fuzz/banman.cpp.gcov.html vs https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/c81c6bf65b34eb91/f50cf5ad0fce12d3/fuzz.coverage/src/test/fuzz/banman.cpp.gcov.htmlI can try GCC on the cmake branch, but I'd be surprised if cmake magically fixed those issues.
This means that after cmake is merged as-is, it likely won't be possible to generate a useful coverage report.
I didn't try GCC, but Clang works quite smooth with autotools or cmake (as per #233), a downside is that it is not integrated into either build system so it requires manual fiddling with compiler flags.
@maflcko, from what you say it follows that you can't generate a useful coverage report with GCC on the autotools branch as well, right?
I tried to use GCC (on the autotools branch), but it had many problems:
__gcov_reset
(from https://github.com/bitcoin/bitcoin/pull/30156/files) doesn't seem to be doing anything. See for example https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/44cf2cd0ca789852/65ac5a6b0b3f11ad/fuzz.coverage/src/test/fuzz/banman.cpp.gcov.html vs https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/c81c6bf65b34eb91/f50cf5ad0fce12d3/fuzz.coverage/src/test/fuzz/banman.cpp.gcov.html
Last time I tested https://github.com/bitcoin/bitcoin/pull/30075, which also uses __gcov_reset
, it worked for me.
I can try GCC on the cmake branch, but I'd be surprised if cmake magically fixed those issues.
Of course, CMake won't fix other tools' bugs :)
This means that after cmake is merged as-is, it likely won't be possible to generate a useful coverage report.
A proper support for coverage report generation using clang should be a priority follow up, right?
Last time I tested bitcoin#30075, which also uses
__gcov_reset
, it worked for me.
Ok, I'll try a bit more.
A proper support for coverage report generation using clang should be a priority follow up, right?
Yeah, I'd say some kind of solution should happen before the autotools removal.
In theory a complete re-work can be considered, maybe along https://github.com/bitcoin/bitcoin/pull/28772 , but personally I don't care too much, as long as I have a single, reasonable good way to get coverage reports.
Last time I tested bitcoin#30075, which also uses
__gcov_reset
, it worked for me.Ok, I'll try a bit more.
I tried commit 6f1d9064381d834b, which is one before the pull request and it did not work for me: https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/6f1d9064381d834b/65ac5a6b0b3f11ad/fuzz.coverage/src/test/fuzz/banman.cpp.gcov.html
Does anyone want to summarize the state of this, and migrate it to https://github.com/bitcoin/bitcoin/issues ?
reasonable good way to get coverage reports
Consider this, using Clang's source-based code coverage feature:
It’s called “source-based” because it operates on AST and preprocessor information directly. This allows it to generate very precise coverage data.
# Compile
cmake \
-G "Ninja" \
-DCMAKE_BUILD_TYPE=Debug \
-DAPPEND_CXXFLAGS="-fprofile-instr-generate -fcoverage-mapping -fPIE" \
-DAPPEND_LDFLAGS="-fprofile-instr-generate -fcoverage-mapping" \
-S /tmp/source -B /tmp/build
cmake --build /tmp/build -j32
# Run tests
mkdir /tmp/coverage
export LLVM_PROFILE_FILE=/tmp/coverage/%m_%p.profraw
/tmp/build/src/test/test_bitcoin
/tmp/build/test/functional/test_runner.py
# Collect coverage and create a HTML report
llvm-profdata-devel merge /tmp/coverage/*.profraw --output=/tmp/coverage/all.profdata
llvm-cov-devel show -format=html -output-dir=/tmp/coverage/result \
-Xdemangler=/usr/local/llvm-devel/bin/llvm-cxxfilt -instr-profile=/tmp/coverage/all.profdata \
-object=/tmp/build/src/test/test_bitcoin \
-object=/tmp/build/src/bitcoind
Works like a charm and creates better reports than GCC's (e.g. it expands templates, which GCC coverage does not, at least last time I played with it). I tried to integrate this in the build system in https://github.com/hebasto/bitcoin/pull/233 to reduce the above commands to just a few cmake
invocations, maybe there are better ways to integrate it, but even if not integrated it is not too difficult to run the above commands.
-DAPPEND_CXXFLAGS="-fprofile-instr-generate -fcoverage-mapping -fPIE"
Why do you need to add -fPIE here? CMake should be doing this automatically?
@maflcko
Can you re-confirm please that you cannot generate a coverage report on Ubuntu 24.10 using clang 18.0 and lcov 2.1?
Yes, the error remains. I see that you claim to be able to generate them in https://github.com/hebasto/bitcoin/issues/341#issuecomment-2310803071, but it would be good to have steps to reproduce from a fresh install of the distro:
export DEBIAN_FRONTEND=noninteractive && apt update && apt install llvm lcov git vim ccache clang build-essential cmake pkg-config python3 libevent-dev libboost-dev cmake -y && git clone https://github.com/bitcoin/bitcoin.git --depth=1 ./b-c && cd b-c && cmake -B ./bld-cmake -DBUILD_FOR_FUZZING=ON -DSANITIZERS=fuzzer -DCMAKE_BUILD_TYPE=Coverage -DCMAKE_C_COMPILER='clang' -DCMAKE_CXX_COMPILER='clang++' -DENABLE_WALLET=OFF && cmake --build ./bld-cmake --parallel $( nproc ) && mkdir empty_dir && cmake -DJOBS=$( nproc ) -DFUZZ_SEED_CORPUS_DIR=$PWD/empty_dir -DLCOV_OPTS='--rc branch_coverage=1 --ignore-errors mismatch,inconsistent' -P ./bld-cmake/CoverageFuzz.cmake
versionbits #2 DONE cov: 30 ft: 31 corp: 1/1b lim: 4 exec/s: 0 rss: 64Mb
Capturing coverage data from src
geninfo cmd: '/usr/bin/geninfo src --output-filename fuzz.info --test-name fuzz-tests --gcov-tool /b-c/bld-cmake/cov_tool_wrapper.sh --ignore-errors mismatch --ignore-errors inconsistent --rc branch_coverage=1 --branch-coverage'
Found LLVM gcov version 18.1.8, which emulates gcov version 4.2.0
Using intermediate gcov format
Recording 'internal' directories:
/b-c/bld-cmake/src
Writing temporary data to /tmp/geninfo_datQ3gO
Scanning src for .gcda files ...
geninfo: WARNING: (format) invalid characters removed from testname
(use "geninfo --ignore-errors format,format ..." to suppress this warning)
Found 336 data files in src
using: chunkSize: 1, nchunks:336, intervalLength:16
geninfo: WARNING: (gcov) GCOV did not produce any data for /b-c/bld-cmake/src/secp256k1/src/CMakeFiles/secp256k1_precomputed.dir/precomputed_ecmult.c.gcda
(use "geninfo --ignore-errors gcov,gcov ..." to suppress this warning)
geninfo: WARNING: (gcov) GCOV did not produce any data for /b-c/bld-cmake/src/secp256k1/src/CMakeFiles/secp256k1_precomputed.dir/precomputed_ecmult_gen.c.gcda
geninfo: WARNING: (gcov) GCOV did not produce any data for /b-c/bld-cmake/src/CMakeFiles/bitcoin_node.dir/policy/settings.cpp.gcda
Finished processing 336 GCDA files
Apply filtering..
Message summary:
1 error message:
source: 1
4 warning messages:
format: 1
gcov: 3
geninfo: ERROR: (source) unable to open /b-c/bld-cmake/src/src/index/blockfilterindex.cpp: No such file or directory
(use "geninfo --ignore-errors source ..." to bypass this error)
Deleting all .da files in src and subdirectories
Done.
Message summary:
no messages were reported
Traceback (most recent call last):
File "/b-c/bld-cmake/./filter-lcov.py", line 19, in <module>
with open(tracefile, 'r', encoding="utf8") as f:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'fuzz.info'
lcov: ERROR: (missing) 'fuzz_filtered.info' found from pattern 'fuzz_filtered.info' is not a readable file
(use "lcov --ignore-errors missing ..." to bypass this error)
Combining tracefiles.
lcov: ERROR: (missing) 'baseline_filtered.info' found from pattern 'baseline_filtered.info' is not a readable file
(use "lcov --ignore-errors missing ..." to bypass this error)
genhtml: ERROR: (missing) 'fuzz_coverage.info' found from pattern 'fuzz_coverage.info' is not a readable file
(use "genhtml --ignore-errors missing ..." to bypass this error)
From Professional CMake: A Practical Guide 19th Edition:
In practice, using gcov-based coverage data with clang can be challenging. Due to the way paths are written to the coverage files, and the way those paths are handled between
gcovr
andllvm-cov
, the processing will often fail.
-DAPPEND_CXXFLAGS="-fprofile-instr-generate -fcoverage-mapping -fPIE"
Why do you need to add -fPIE here? CMake should be doing this automatically?
Aha! Sharp eyes, I was wondering if somebody is going to note this. It is a bit off-topic wrt the coverage, but I will elaborate since you ask. So, at least in my environment, compiling without pie and linking with pie sometimes works and sometimes does not work:
main() return 0
, compile without pie, link with -fPIE -pie
worksld: error: relocation R_X86_64_32S cannot be used against local symbol; recompile with -fPIC
and the solution is to compile with -fPIE
-fprofile-instr-generate -fcoverage-mapping
is used for compiling and linkingNow, we use include(CheckPIESupported)
to ask CMake to check for PIE
for us. What it does is to create some simple program, compile it without pie and try to link with -fPIE -pie
. That succeeds normally (1. from above). However if I add -fprofile-instr-generate -fcoverage-mapping
to compile and link flags, then CMake's check for PIE
fails due to 3.
I am not sure if this is something we should address or if it is a deficiency in CMake (maybe it should use -fPIE
when compiling the test program which it will try to link with -fPIE -pie
?). In anyway, a simple solution is to force -fPIE
to the compile flags like I did above.
In practice, using gcov-based coverage data with clang can be challenging. Due to the way paths are written to the coverage files, and the way those paths are handled between
gcovr
andllvm-cov
, the processing will often fail.
Hm, interesting. Just odd that it worked with autotools for years and for some reason cmake surfaced those errors.
So, at least in my environment,
What is your environment?
I am not sure if this is something we should address or if it is a deficiency in CMake
Did you need to pass -fPIE
previously with autotools? If no, then this is a regression that we should fix regardless of if it's a bug in CMake.
Outside of that, it sounds like it could be a bug in CMake, which we should report upstream, or, is it's PIE check only meant to work sometimes?
Hm, interesting. Just odd that it worked with autotools for years and for some reason cmake surfaced those errors.
Yea, seems odd that something wouldn't work with CMake. Especially since the book quoted seems to claim that the issue is contained between "gcov-based coverage data with clang " (i.e even if there may be issues between the tools, this isn't some fundamental CMake limitation).
What is your environment?
FreeBSD with Clang 20. It is easy to test how widespread this is:
echo 'int main(int, char**) { return 0; }' > a.cc
c++ -fprofile-instr-generate -fcoverage-mapping -c a.cc -o a.o
c++ -fprofile-instr-generate -fcoverage-mapping a.o -o a -fPIE -pie
ld: error: relocation R_X86_64_32S cannot be used against local symbol; recompile with -fPIC
>>> defined in a.o
>>> referenced by a.cc
>>> a.o:(main)
# then remove -fprofile-instr-generate -fcoverage-mapping from the above commands and see that it works
Did you need to pass
-fPIE
previously with autotools?
No, for autotools I used F="-fprofile-instr-generate -fcoverage-mapping" CXXFLAGS=${F} LDFLAGS=${F} autogen configure make
.
It is easy to test how widespread this is:
Do you mean this happens on lots of other systems? I tried your steps from above (swapped c++
for clang++
):
echo 'int main(int, char**) { return 0; }' > a.cc
clang++ -fprofile-instr-generate -fcoverage-mapping -c a.cc -o a.o
clang++ -fprofile-instr-generate -fcoverage-mapping a.o -o a -fPIE -pie
on two different systems (Ubuntu & Fedora), on two different architectures (x86_64 & aarch64), with Clang 18 (Ubuntu clang version 18.1.3 (1ubuntu1)
, clang version 18.1.8 (Fedora 18.1.8-3.fc41)
) and it compiled both times.
No, for autotools I used
Ok, so this is a regression we should track/fix, and possibly report upstream. I'll open an issue in the main repo.
Also, the exit code may not be passed up, which could be improved as well?
# echo $? 0
Addressed in https://github.com/bitcoin/bitcoin/pull/30772.
I retested these steps (using trixie), and it still seems broken? Will port this issue to bitcoin/bitcoin:
geninfo: WARNING: (gcov) GCOV did not produce any data for /b-c/bld-cmake/src/secp256k1/src/CMakeFiles/secp256k1_precomputed.dir/precomputed_ecmult.c.gcno
geninfo: WARNING: (gcov) GCOV did not produce any data for /b-c/bld-cmake/src/util/CMakeFiles/bitcoin_util.dir/__/sync.cpp.gcno
Finished processing 351 GCNO files
Apply filtering..
Message summary:
1 error message:
source: 1
7 warning messages:
gcov: 6
inconsistent: 1
geninfo: WARNING: (inconsistent) "/b-c/bld-cmake/src/test/fuzz/src/test/fuzz/deserialize.cpp":0: function __cxx_global_var_init found on line but no corresponding 'line' coverage data point. Cannot derive function end line. See lcovrc man entry for 'derive_function_end_line'.
(use "geninfo --ignore-errors inconsistent,inconsistent ..." to suppress this warning)
geninfo: ERROR: (source) unable to open /b-c/bld-cmake/src/test/fuzz/src/test/fuzz/deserialize.cpp: No such file or directory
(use "geninfo --ignore-errors source ..." to bypass this error)
CMake Error at bld-cmake/CoverageInclude.cmake:45 (execute_process):
execute_process failed command indexes:
1: "Child return code: 1"
Call Stack (most recent call first):
bld-cmake/CoverageFuzz.cmake:5 (include)
I think I'll try GCC again. Was https://github.com/bitcoin/bitcoin/pull/30772 meant to fix the missing coverage (https://github.com/hebasto/bitcoin/issues/341#issuecomment-2314339110)?
I think I'll try GCC again. Was bitcoin#30772 meant to fix the missing coverage (#341 (comment))?
Yeah, looks like it is working now for some reason: https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/e569eb8d91739bf1/84cea7068728bc2c/fuzz.coverage/src/test/fuzz/buffered_file.cpp.gcov.html
However, the gcov_reset is still ignored, it seems: https://drahtbot.space/host_reports/DrahtBot/reports/coverage_fuzz/monotree/e569eb8d91739bf1/84cea7068728bc2c/fuzz.coverage/src/test/fuzz/addrman.cpp.gcov.html
I get:
I used https://github.com/maflcko/DrahtBot/commit/1b699e8268970e552634029c4093c82327895df6
I can try to add easier steps to reproduce tomorrow.