http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52416

             Bug #: 52416
           Summary: Branch coverage differences between 4.4 and 4.5
    Classification: Unclassified
           Product: gcc
           Version: 4.5.4
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: gcov-profile
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: chateau.frede...@gmail.com


Hello,
I am using g++ versions coming with Ubuntu 11.10 and I am trying to use g++ and
lcov to analyse the line and branch coverage of my unit tests.

I discovered some significant differences in the number of branches reported
between version 4.4 (4.4.6) and 4.5 (4.5.4) (or 4.6 (4.6.1)).

I was trying to figure out which compilation flags were best in order to have
branch coverage information match more closely what I see in the source code
and avoid hidden branches (triggered by under the hood code) or suppressed
branches (because of optimizations).
Finally, it seems that -O0 -fno-inline -fno-default-inline
-fno-elide-constructors works best, at least with g++-4.4

Because, when I use g++-4.5 or g++-4.6, there are many additionnal branches
that do not directly come from the control flow in the source.
In the project I was analysis, the number of branches jumped from ~1950 to
~6600 !
In my point of view, the output of 4.4 is more meaningful than the output of
4.5/4.6.

I tried to make a little example program and tried to figure out if there was a
flags that could disable the generetion of these branches.
And indeed, with -fno-exceptions, I get the same exact result in 4.5/4.6 than
in 4.4. At least with my example program, because my whole project requires
exception handling to be activated.

Here is the example code:
#include <iostream>

int main(int argc, char* argv[])
{
    std::string val;
    if(argc > 1)
    {
        val = argv[1];
    }
    if(argc == 2)
    {
        std::cout << val << std::endl;
    }
    else
    {
        std::cout << "Need one argument!" << std::endl;
    }
}


With g++ 4.4, there are 8 branches.
With g++ 4.5, there are 16 branches !

Here is gcov output:
g++-4.5:
        -:    0:Source:myprog.cpp
        -:    0:Graph:myprog.gcno
        -:    0:Data:myprog.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include <iostream>
        -:    2:
function main called 1 returned 100% blocks executed 58%
        1:    3:int main(int argc, char* argv[])
        -:    4:{
        2:    5:        std::string val;
call    0 returned 100%
call    1 returned 100%
call    2 never executed
call    3 never executed
        1:    6:        if(argc > 1)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
        -:    7:        {
    #####:    8:                val = argv[1];
branch  0 never executed
branch  1 never executed
call    2 never executed
        -:    9:        }
        1:   10:        if(argc == 2)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
        -:   11:        {
    #####:   12:                std::cout << val << std::endl;
branch  0 never executed
branch  1 never executed
call    2 never executed
branch  3 never executed
branch  4 never executed
call    5 never executed
        -:   13:        }
        -:   14:        else
        -:   15:        {
        1:   16:                std::cout << "Need one argument!" << std::endl;
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
call    2 returned 100%
branch  3 taken 100% (fallthrough)
branch  4 taken 0%
call    5 returned 100%
        -:   17:        }
function _Z41__static_initialization_and_destruction_0ii called 1 returned 100%
blocks executed 100%
function _GLOBAL__I_main called 1 returned 100% blocks executed 100%
        3:   18:}
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
call    4 returned 100%
        -:   19:




With g++-4.4:
        -:    0:Source:myprog.cpp
        -:    0:Graph:myprog.gcno
        -:    0:Data:myprog.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:#include <iostream>
        -:    2:
function main called 1 returned 100% blocks executed 54%
        1:    3:int main(int argc, char* argv[])
        -:    4:{
        1:    5:        std::string val;
call    0 returned 100%
        1:    6:        if(argc > 1)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
        -:    7:        {
    #####:    8:                val = argv[1];
call    0 never executed
        -:    9:        }
        1:   10:        if(argc == 2)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
        -:   11:        {
    #####:   12:                std::cout << val << std::endl;
call    0 never executed
call    1 never executed
        -:   13:        }
        -:   14:        else
        -:   15:        {
        1:   16:                std::cout << "Need one argument!" << std::endl;
call    0 returned 100%
call    1 returned 100%
    #####:   17:        }
call    0 never executed
call    1 returned 100%
function _Z41__static_initialization_and_destruction_0ii called 1 returned 100%
blocks executed 100%
function _GLOBAL__I_main called 1 returned 100% blocks executed 100%
        3:   18:}
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
call    4 returned 100%
        -:   19:



I couldn't find any information about what could have triggered such an
important change. It seems like exception handling has changed between 4.4 and
4.5.
Can somebody explain me why is it behaving like that, if it is a
bug/regression, or if there is a workaround (flags ?).

Otherwise, I will have to stick to g++ 4.4 for coverage analysis because it is
far more relevant in my opinion.

Reply via email to