2

I generate coverage data and use an online service for visualization and CI. However I have strange "partials" (if-branches that are not fully covered). Looking at the gcov data it seems like an excessive amount of branches is detected.

An example:

function _ZNK5World8AdjustBQE5PointItEh15BuildingQuality called 415 returned 100% blocks executed 76%
      415:  377:BuildingQuality World::AdjustBQ(const MapPoint pt, unsigned char player, BuildingQuality nodeBQ) const
        -:  378:{
      415:  379:    if(nodeBQ == BQ_NOTHING || GetNode(pt).owner != player + 1 || !IsPlayerTerritory(pt))
branch  0 taken 95% (fallthrough)
branch  1 taken 5%
call    2 returned 100%
call    3 returned 100%
branch  4 taken 100% (fallthrough)
branch  5 taken 0% (throw)
branch  6 taken 85% (fallthrough)
branch  7 taken 15%
call    8 returned 100%
call    9 returned 100%
branch 10 taken 100% (fallthrough)
branch 11 taken 0% (throw)
branch 12 taken 17% (fallthrough)
branch 13 taken 83%
branch 14 taken 80% (fallthrough)
branch 15 taken 20%
branch 16 taken 95% (fallthrough)
branch 17 taken 5%
branch 18 taken 33% (fallthrough)
branch 19 taken 67%
branch 20 never executed
branch 21 never executed
branch 22 never executed
branch 23 never executed
call   24 never executed

It seems like the functions still get inlined and counted, although I'm already compiling with -g -O0 --coverage -fno-default-inline -fno-inline. What can I do, so I only get the "meaningfull" data and inline-functions are attributed correctly at their definition?

I'm using g++-4.8 and gcov-4.8

Edit: If I split the if into its calls I get this:

      415:  379:    unsigned char owner = GetNode(pt).owner;
call    0 returned 100%
call    1 returned 100%
branch  2 taken 100% (fallthrough)
branch  3 taken 0% (throw)
call    4 never executed
      415:  380:    bool isPlayerTer = IsPlayerTerritory(pt);
call    0 returned 100%
call    1 returned 100%
branch  2 taken 100% (fallthrough)
branch  3 taken 0% (throw)
call    4 never executed
      415:  381:    if(nodeBQ == BQ_NOTHING || owner != player + 1 || !isPlayerTer)
branch  0 taken 95% (fallthrough)
branch  1 taken 5%
branch  2 taken 85% (fallthrough)
branch  3 taken 15%
branch  4 taken 17% (fallthrough)
branch  5 taken 83%

So the problem is really the calls. What can I do so those calls (and their branches(???)) don't get added to the coverage data?

Just found an artificial branch in the asm code that just checks a register and does a nop (besides a gcov counter increment) WTF?

   0x0000000000d967de <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+340>:   test   %bl,%bl
   0x0000000000d967e0 <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+342>:   je     0xd967f5 <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+363>
   0x0000000000d967e2 <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+344>:   nop
   0x0000000000d967e3 <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+345>:   mov    0x1206c9e(%rip),%rax        # 0x1f9d488 <__gcov0._ZNK5World8AdjustBQE5PointItEh15BuildingQuality+72>
   0x0000000000d967ea <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+352>:   add    $0x1,%rax
   0x0000000000d967ee <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+356>:   mov    %rax,0x1206c93(%rip)        # 0x1f9d488 <__gcov0._ZNK5World8AdjustBQE5PointItEh15BuildingQuality+72>
   0x0000000000d967f5 <World::AdjustBQ(Point<unsigned short>, unsigned char, BuildingQuality) const+363>:   test   %dl,%dl

I switched to clang++ and llvm-cov gcov and got the correct results for this case (only 6 branches). However I also got some false positives at other places. One of the most disturbing ones seems to be a "function __cxx_global_array_dtor call" in the middle of a function on a line where similar lines (only integer parameters are changed) do not have this. So my current solution is to use gcov-4.8 without branch data as it is completely unreliable.

Flamefire
  • 5,313
  • 3
  • 35
  • 70

1 Answers1

0

It is possible that there are additional branches at points, where exceptions could possibly occure, e.g. at function call points.

For example we observed a branch with gcov in our (not noexcept) empty virtual destructor, which we cannot Cover by our tests.

koraxkorakos
  • 369
  • 1
  • 10
  • This one: http://stackoverflow.com/questions/7199360/what-is-the-branch-in-the-destructor-reported-by-gcov?rq=1 ? However this is the call site. There should not be any branches at the call site, should there? – Flamefire Jul 20 '16 at 11:22
  • Interesting comment. It seems that the branch we observed is from the dynamic/nondynamic distintiction, not from an exception branch. We could then cover this by tests. I will try it on Monday. – koraxkorakos Jul 24 '16 at 08:40