gcovr分支覆盖率统计异常求助:模板代码分支未被正确识别
我正尝试使用gcovr(版本5.0)收集分支覆盖率指标,但碰到了异常情况:明明已确认代码分支的两条路径都执行过,覆盖率却显示为0/2而非2/2。该问题多出现于模板代码中,但未找到gcovr针对模板的已知问题记录,且其他模板代码可正常统计。由于仅在大型项目中出现,我难以构建最小复现示例,但项目要求100%覆盖率,必须用指标证明而非口头确认。
对应代码片段的XML输出显示统计环节存在问题,但我无从排查:
<line number="194" hits="655482" branch="true" condition-coverage="0% (0/2)"> <conditions> <condition number="0" type="jump" coverage="0%"/> </conditions> </line>
我们使用的gcovr参数为:--exclude-unreachable-branches --exclude-throw-branches
更新:问题场景定位
发现该问题仅出现于以下场景:模板代码是文件中最后被实例化的模板,且测试用例覆盖了该模板的不同类型实例。测试示例显示,仅需添加一个引用后续模板的函数,即可让之前的模板正常显示分支覆盖率;若仅测试一种类型,分支覆盖率也会恢复正常。
测试环境为g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0,编译命令:g++ test.cpp -o test -ftest-coverage -fprofile-arcs -O0,gcovr命令:gcovr --gcov-executable=/usr/bin/gcov --print-summary --exclude-unreachable-branches --exclude-throw-branches --html-details coverage.html。当前示例使用的是gcovr 4.2而非5.0,这可能是示例未完全复现主流水线问题的原因(主流水线明确使用5.0,因使用了5.0才引入的排除过滤器),我将尝试用5.0复现并观察差异。
示例代码
example.hpp
#pragma once #include <cstdint> #include <cstdio> class Example { public: template <typename T> static T* firstProcedure(int32_t n) { if (n <= 0) return nullptr; if (n < sizeof(T)) { printf("uh oh\n"); } else { printf("ok\n"); } return nullptr; } template <typename T> static T* secondProcedure(int32_t n) { if (n <= 0) return nullptr; if (n < sizeof(T)) { printf("uh oh\n"); } else { printf("ok\n"); } return nullptr; } template <typename T> static T* lastProcedure(int32_t n) { if (n <= 0) return nullptr; if (n < sizeof(T)) { printf("uh oh\n"); } else { printf("ok\n"); } return nullptr; } };
test.cpp
#include "example.hpp" #include <cstdio> void Test1() { uint32_t* a = Example::firstProcedure<uint32_t>(1); uint8_t* b = Example::firstProcedure<uint8_t>(1); } void Test2() { uint32_t* a = Example::secondProcedure<uint32_t>(1); #if 1 // 注释掉这行就能看到分支覆盖率 uint8_t* b = Example::secondProcedure<uint8_t>(1); #endif } void LastTest() { #if 0 // 打开这行就能看到secondProcedure的分支覆盖率 uint32_t* a = Example::lastProcedure<uint32_t>(1); #endif } int main() noexcept { Test1(); Test2(); //LastTest(); // 不用运行也能生效 return 0; }
内容的提问来源于stack exchange,提问作者Richard Fabian

