Reputation: 3141
I have a C project at hand with cmocka tests and it is built using CMake. Now I try to use gcov to determine the test coverage and use this CMake module: https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake That module provides a make target which runs the test target executable (which is to run gcov) and then runs lcov and genhtml to generate a report.
Now, the problem is, when the test target is executed, it creates the .gcda files with only the owner's executable bit set, i. e. the read bit is missing. Subsequently, lcov cannot read these files and produces a report with a coverage of 0%. When I chmod u+r
the gcda files manually afterwards and run the post-test lcov commands by hand, the report is successfully generated (displays something is actually covered). So the gcda files are created and valid, but they have unsuitable permissions set.
The problem seems to stem from wrapping (with ld --wrap) the open
function for capturing the returned file descriptor in a test case. Here a minimum compiling example:
/* wrapped_open.c */
int main(void)
{
return 0;
}
int __wrap_open(const char *filename, int flags)
{
return __real_open(filename, flags);
}
# CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(gcov-mvce C)
add_executable(wrapped_open wrapped_open.c)
target_link_libraries(wrapped_open
-Wl,--wrap=open
)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_SOURCE_DIR}/cmake")
include(CodeCoverage)
set_target_properties(wrapped_open PROPERTIES
COMPILE_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
LINK_FLAGS "-lgcov --coverage")
setup_target_for_coverage(wrapped_open_coverage wrapped_open "coverage")
# build like this:
cmake . -DCMAKE_BUILD_TYPE=Debug # in-source build
make
# receive coverage report like this
make wrapped_open_coverage
# simple gcc command line for compiling (no cmake required)
gcc -g -O0 --coverage -fprofile-arcs -ftest-coverage -lgcov -Wl,--wrap=open -o wrapped_open wrapped_open.c
When the wrapping of open and the wrap function definition are removed from the linker flags and the code, respectively, it works. But with the files above, the file wrapped_open.c.gcda
is created with the access mask 0100 and the following is reported by lcov:
(bulid-directory)/CMakeFiles/wrapped_open.dir/wrapped_open.c.gcda:cannot open data file, assuming not executed
...resulting in a coverage of 0/4 lines and 0/2 functions.
Why are the access bits wrong when the open function is wrapped like above, even though each path still calls the original function with unmodified parameters (at least that is what it is intended to do)? An obvious workaround would be to modify the cmake module to do the chmod for me, but I would rather like to understand what is going wrong when open is wrapped.
Please tell me in the comments if and which additional information might be required to answer this.
Upvotes: 1
Views: 1690
Reputation: 3141
As pointed out in the comments, open()
is a function with variable arguments. If a file is created, the third argument is the file's mode. In my __wrap_open
implementation I omitted that third parameter because I did not think of that other code than the code under test would call open()
as well. Of course, gcov eventually does it to create its gcda files and since I did not specify the third argument to __real_open
, something undefined went in there for the mode.
So, the solution is to always include all possible arguments in wrapper functions.
Upvotes: 1