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.