Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LCOV branches at the end of a function

Tags:

c++

lcov

gcov

enter image description here

What are the branches at the end of this function. How could I cover them?

like image 786
jsj Avatar asked Jan 01 '14 07:01

jsj


People also ask

How do I get branch coverage in LCOV?

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.

What is branch in gcov?

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.


1 Answers

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
like image 95
mockinterface Avatar answered Oct 23 '22 14:10

mockinterface