Domanda

enter image description here

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

È stato utile?

Soluzione

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

Altri suggerimenti

I had the same problem with end brackets which were not covered in a void function;

I found two workarounds:

  • first add the endbracket to the last functioncall line so they dont show up as individual line

  • second and better: add random "return;" at the end of the function to force the code to be executed

As a super simplistic answer, branches signify the IF/ELSE branch. So for every if/else there's two new branches (that should be covered); and if nested the grow exponentially.

function twoNewBranches() {
  if () {
    // code
  } else {
    // code
  }
}

function twoNewBranchesNotAparent() {
  if () {
    // code
  }
}

function fourNewBranches() {
  if () {
    if () {
      // code
    } else {
      // code
    }
  }
}

• The first function twoNewBranches creates two new branches that would need to be covered

• The second function twoNewBranchesNotAparent also creates two new branches, since you still have to cover the test that doesn’t satisfy the if statement

• The third function fourNewBranches creates four (2^2=4) new branches to cover. Two nested, the parent of the nested, and the hidden else.

Overall keep in mind covering branches, is about covering the conditional statements.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top