c++ - Different branch coverage generated by GCC/GCOV for function using throw() / noexcept -
i understand branches generated gcc compiler when using noexcept
or throw()
marking non-throwing function. know differences between noexcept
, throw()
, cannot figure out additional branches defined when using throw()
instead of noexcept
, how improve coverage have 100% of branch coverage?
code snippet of tested example class:
class myclass { public: myclass() noexcept : ithrowflag(false) {} void non_throwing_method() noexcept { try { throwing_method(); } catch (...) { } } void throwing_method() { if (ithrowflag) { throw std::exception(); } } public: bool ithrowflag; };
there 2 test cases defined, both passing:
- verification if
non_throwing_method
completes when underlyingthrowing_method
not throwing, - verification if
non_throwing_method
completes when underlyingthrowing_method
throwing exception.
below coverage report generated gcc/gcov above code, lines , branches covered (4/4 branches covered):
-: 0:source:myclass.hh -: 0:graph:main.gcno -: 0:data:main.gcda -: 0:runs:1 -: 0:programs:1 -: 1:#include <iostream> -: 2:#include <string> -: 3: -: 4:using namespace std; -: 5: -: 6:class myclass -: 7:{ -: 8:public: function _zn7myclassc2ev called 2 returned 100% blocks executed 100% 2: 9: myclass() noexcept : 2: 10: ithrowflag(false) 2: 11: {} -: 12: function _zn7myclass19non_throwing_methodev called 2 returned 100% blocks executed 100% 2: 13: void non_throwing_method() noexcept -: 14: { -: 15: try -: 16: { 2: 17: throwing_method(); call 0 returned 100% branch 1 taken 50% (fallthrough) branch 2 taken 50% (throw) -: 18: } 1: 19: catch (...) call 0 returned 100% -: 20: { -: 21: } 2: 22: } -: 23: function _zn7myclass15throwing_methodev called 2 returned 50% blocks executed 100% 2: 24: void throwing_method() -: 25: { 2: 26: if (ithrowflag) branch 0 taken 50% (fallthrough) branch 1 taken 50% -: 27: { 1: 28: throw std::exception(); call 0 returned 100% call 1 returned 100% call 2 returned 0% -: 29: } 1: 30: } -: 31: -: 32:public: -: 33: bool ithrowflag; -: 34:};
as target platform not support c++11 , noexcept
, exchanged throw()
specifier below:
class myclass { public: myclass() throw() : ithrowflag(false) {} void non_throwing_method() throw() { try { throwing_method(); } catch (...) { } } void throwing_method() { if (ithrowflag) { throw std::exception(); } } public: bool ithrowflag; };
below gcov output examined branches (5/8). code throw()
generates additional 4 branches, quite hard understand , cover testing:
-: 0:source:myclass.hh -: 0:graph:main.gcno -: 0:data:main.gcda -: 0:runs:1 -: 0:programs:1 -: 1:#include <iostream> -: 2:#include <string> -: 3: -: 4:using namespace std; -: 5: -: 6:class myclass -: 7:{ -: 8:public: function _zn7myclassc2ev called 2 returned 100% blocks executed 100% 2: 9: myclass() throw() : 2: 10: ithrowflag(false) 2: 11: {} -: 12: function _zn7myclass19non_throwing_methodev called 2 returned 100% blocks executed 75% 2: 13: void non_throwing_method() throw() -: 14: { -: 15: try -: 16: { 2: 17: throwing_method(); call 0 returned 100% branch 1 taken 50% (fallthrough) branch 2 taken 50% (throw) -: 18: } 1: 19: catch (...) call 0 returned 100% call 1 returned 100% branch 2 taken 100% (fallthrough) branch 3 taken 0% (throw) branch 4 never executed branch 5 never executed call 6 never executed -: 20: { -: 21: } 2: 22: } -: 23: function _zn7myclass15throwing_methodev called 2 returned 50% blocks executed 100% 2: 24: void throwing_method() -: 25: { 2: 26: if (ithrowflag) branch 0 taken 50% (fallthrough) branch 1 taken 50% -: 27: { 1: 28: throw std::exception(); call 0 returned 100% call 1 returned 100% call 2 returned 0% -: 29: } 1: 30: } -: 31: -: 32:public: -: 33: bool ithrowflag; -: 34:};
test cases below (to have full details case):
void test1() { myclass lobj; lobj.non_throwing_method(); } void test2() { myclass lobj; lobj.ithrowflag = true; lobj.non_throwing_method(); lobj.ithrowflag = false; }
i appreciate if have answer/explanation described behavior.
edit: additionally attached assembly code (only code of function: `non_throwing_method1 compare).
with noexcept:
_zn7myclass19non_throwing_methodev: .lfb1253: .loc 2 13 0 .cfi_startproc .cfi_personality 0x3,__gxx_personality_v0 .cfi_lsda 0x3,.llsda1253 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movq %rdi, -8(%rbp) movq __gcov0._zn7myclass19non_throwing_methodev(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev(%rip) .loc 2 17 0 movq -8(%rbp), %rax movq %rax, %rdi .lehb0: call _zn7myclass15throwing_methodev .lehe0: movq __gcov0._zn7myclass19non_throwing_methodev+8(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+8(%rip) .loc 2 22 0 jmp .l7 .l6: movq %rax, %rdx movq __gcov0._zn7myclass19non_throwing_methodev+16(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+16(%rip) .loc 2 19 0 movq %rdx, %rax movq %rax, %rdi call __cxa_begin_catch movq __gcov0._zn7myclass19non_throwing_methodev+24(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+24(%rip) call __cxa_end_catch movq __gcov0._zn7myclass19non_throwing_methodev+32(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+32(%rip) .l7: .loc 2 22 0 nop leave .cfi_def_cfa 7, 8 ret .cfi_endproc .lfe1253: .globl __gxx_personality_v0 .section .gcc_except_table._zn7myclass19non_throwing_methodev,"ag",@progbits,_zn7myclass19non_throwing_methodev,comdat .align 4 .llsda1253: .byte 0xff .byte 0x3 .uleb128 .llsdatt1253-.llsdattd1253 .llsdattd1253: .byte 0x1 .uleb128 .llsdacse1253-.llsdacsb1253 .llsdacsb1253: .uleb128 .lehb0-.lfb1253 .uleb128 .lehe0-.lehb0 .uleb128 .l6-.lfb1253 .uleb128 0x1 .llsdacse1253: .byte 0x1 .byte 0 .align 4 .long 0 .llsdatt1253: .section .text._zn7myclass19non_throwing_methodev,"axg",@progbits,_zn7myclass19non_throwing_methodev,comdat .size _zn7myclass19non_throwing_methodev, .-_zn7myclass19non_throwing_methodev .section .text._zn7myclass15throwing_methodev,"axg",@progbits,_zn7myclass15throwing_methodev,comdat .align 2 .weak _zn7myclass15throwing_methodev .type _zn7myclass15throwing_methodev, @function
with throw():
_zn7myclass19non_throwing_methodev: .lfb1253: .loc 2 13 0 .cfi_startproc .cfi_personality 0x3,__gxx_personality_v0 .cfi_lsda 0x3,.llsda1253 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movq %rdi, -8(%rbp) movq __gcov0._zn7myclass19non_throwing_methodev(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev(%rip) .loc 2 17 0 movq -8(%rbp), %rax movq %rax, %rdi .lehb0: call _zn7myclass15throwing_methodev .lehe0: movq __gcov0._zn7myclass19non_throwing_methodev+8(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+8(%rip) .loc 2 22 0 jmp .l3 .l8: movq %rax, %rdx movq __gcov0._zn7myclass19non_throwing_methodev+16(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+16(%rip) .loc 2 19 0 movq %rdx, %rax movq %rax, %rdi call __cxa_begin_catch movq __gcov0._zn7myclass19non_throwing_methodev+24(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+24(%rip) .lehb1: call __cxa_end_catch .lehe1: movq __gcov0._zn7myclass19non_throwing_methodev+32(%rip), %rax addq $1, %rax movq %rax, __gcov0._zn7myclass19non_throwing_methodev+32(%rip) .loc 2 22 0 jmp .l3 .l9: cmpq $-1, %rdx je .l7 movq __gcov0._zn7myclass19non_throwing_methodev+48(%rip), %rdx addq $1, %rdx movq %rdx, __gcov0._zn7myclass19non_throwing_methodev+48(%rip) movq %rax, %rdi .lehb2: call _unwind_resume .l7: movq __gcov0._zn7myclass19non_throwing_methodev+40(%rip), %rdx addq $1, %rdx movq %rdx, __gcov0._zn7myclass19non_throwing_methodev+40(%rip) .loc 2 13 0 movq %rax, %rdi call __cxa_call_unexpected .lehe2: .l3: .loc 2 22 0 leave .cfi_def_cfa 7, 8 ret .cfi_endproc .lfe1253: .globl __gxx_personality_v0 .section .gcc_except_table._zn7myclass19non_throwing_methodev,"ag",@progbits,_zn7myclass19non_throwing_methodev,comdat .align 4 .llsda1253: .byte 0xff .byte 0x3 .uleb128 .llsdatt1253-.llsdattd1253 .llsdattd1253: .byte 0x1 .uleb128 .llsdacse1253-.llsdacsb1253 .llsdacsb1253: .uleb128 .lehb0-.lfb1253 .uleb128 .lehe0-.lehb0 .uleb128 .l8-.lfb1253 .uleb128 0x1 .uleb128 .lehb1-.lfb1253 .uleb128 .lehe1-.lehb1 .uleb128 .l9-.lfb1253 .uleb128 0x3 .uleb128 .lehb2-.lfb1253 .uleb128 .lehe2-.lehb2 .uleb128 0 .uleb128 0 .llsdacse1253: .byte 0x1 .byte 0 .byte 0x7f .byte 0 .align 4 .long 0 .llsdatt1253: .byte 0 .section .text._zn7myclass19non_throwing_methodev,"axg",@progbits,_zn7myclass19non_throwing_methodev,comdat .size _zn7myclass19non_throwing_methodev, .-_zn7myclass19non_throwing_methodev .section .text._zn7myclass15throwing_methodev,"axg",@progbits,_zn7myclass15throwing_methodev,comdat .align 2 .weak _zn7myclass15throwing_methodev .type _zn7myclass15throwing_methodev, @function
Comments
Post a Comment