Gcovr - 6 possible branches in if-statement

646 views Asked by At

I am using Gcovr to measure code coverage in C++. In a simple if-statement, I am getting weird results.

Below I add a picture of a code coverage. Can anyone help and can explain, why there are six possible branches? When I seperate the functions a() and b() in their own if-statement, I am getting two possible branches, which is ok.

enter image description here

enter image description here

1

There are 1 answers

0
amon On

GCC-gcov code coverage does not consider the branches in your source code, it considers the branches emitted by the compiler. Approximately, it works on an assembly level. If I look at the assembly for your initial func(), I see three branching points associated with that line:

func():
        push    rbp
        mov     rbp, rsp
        call    a()
        test    eax, eax
        jne     .L6
        call    b()
        test    eax, eax
        je      .L7
.L6:
        mov     eax, 1
        jmp     .L8
.L7:
        mov     eax, 0
.L8:
        test    al, al
        je      .L9
        mov     eax, 1
        jmp     .L10
.L9:
        mov     eax, 0
.L10:
        pop     rbp
        ret

https://godbolt.org/z/6q691r3fj gcc 12.2 with -O0

The entire .L8 and .L9 block look pretty pointless to me, but it seems to me that the compiler is actually translating the conditional via an intermediate variable. Roughly, your code

if (a() || b()) {
  return 1;
} else {
  return 0;
}

seems to be translated as

int cond;
if (a() || b()) {
  cond = 1;
} else {
  cond = 0;
}

int retval;
if (cond) {
  retval = 1;
} else {
  retval = 0;
}

return retval;

This is just the kind of code that gets emitted when disabling all optimizations. It is not always a literal translation of the source code, sometimes compilers do stuff that appears really dumb. As discussed in the gcovr FAQ entry “Why does C++ have so many uncovered branches?”, it is not generally possible to get rid of all the compiler-generated branches. As a consequence, chasing a concrete branch coverage metric is not overly useful for GCC-gcov based coverage data.