What are the branches at the end of this function. How could I cover them?
You need to re-enable it by either: editing your ~/. lcovrc file (copied from /etc/lcovrc) to change lcov_branch_coverage setting to 1. adding --rc lcov_branch_coverage=1 to your lcov command lines.
The "Branch" column shows the branches that have been executed (✔) or skipped (x). This corresponds to the entries in the GCOV file. The "Exec" column shows how often a certain line has been executed. The "Source" column shows the actual source code.
You are observing the gcc generated code for the destruction of static storage duration (global) variables.
Your coverage shows that the function foo
has been entered three times, however the counter near the end of the scope shows that the code was executed eight times, including branches that you enquire about.
Now you must consider that the compiler puts the header file in the translation unit and that gcov doesn't see your code exactly as it is, but rather as a control flow graph of assembly instruction with branching as the edges of the graph.
Thus the "end of foo
scope" in the lcov html output is not really the end of the foo
method scope but rather everything that's included after foo
as well in the entire translation unit, including the destruction of global variables that have been declared in the header file.
The header itself hasn't been included in the question, but even the most basic __static_initialization_and_destruction
assembly that gcc generates has a number of branches included.
Note that you may have included global variables or you may have not - gcc still might generate this code for every translation unit.
Look at the underlying output of gcov:
function _Z3fooi called 1 returned 100% blocks executed 50%
1: 4:int foo(int x) {
1: 5: if (x==1) {
branch 0 taken 0% (fallthrough)
branch 1 taken 100%
#####: 6: std::cout << "foo" << std::endl;
call 0 never executed
call 1 never executed
#####: 7: return 0;
-: 8: }
1: 9: return 1;
function _GLOBAL__sub_D__Z3fooi called 1 returned 100% blocks executed 100%
function _GLOBAL__sub_I__Z3fooi called 1 returned 100% blocks executed 100%
function _Z41__static_initialization_and_destruction_0ii called 2 returned 100% blocks executed 100%
6: 10:}
call 0 returned 100%
call 1 returned 100%
branch 2 taken 50% (fallthrough)
branch 3 taken 50%
branch 4 taken 100% (fallthrough)
branch 5 taken 0%
-: 11:
And look at the generated assembly, trimmed to clarify the point:
...
ret
.seh_endproc
.def _Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef
.seh_proc _Z41__static_initialization_and_destruction_0ii
_Z41__static_initialization_and_destruction_0ii:
.LFB978:
...
mov QWORD PTR __gcov0._Z41__static_initialization_and_destruction_0ii[rip], rax
cmp DWORD PTR 16[rbp], 1
jne .L5 <-- BRANCH
mov rax, QWORD PTR __gcov0._Z41__static_initialization_and_destruction_0ii[rip+8]
add rax, 1
mov QWORD PTR __gcov0._Z41__static_initialization_and_destruction_0ii[rip+8], rax
cmp DWORD PTR 24[rbp], 65535
jne .L5 <-- BRANCH
...
.L5:
cmp DWORD PTR 16[rbp], 0
je .L6 <-- BRANCH
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With