简体   繁体   English

LCOV在函数末尾分支

[英]LCOV branches at the end of a function

在此输入图像描述

What are the branches at the end of this function. 这个函数末尾的分支是什么。 How could I cover them? 我怎么能掩盖他们?

You are observing the gcc generated code for the destruction of static storage duration (global) variables. 您正在观察gcc生成的代码,用于销毁静态存储持续时间(全局)变量。

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. 您的报道显示函数foo已输入三次,但是示波器末尾附近的计数器显示代码已执行八次,包括您查询的分支。

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. 现在你必须考虑编译器将头文件放在转换单元中,并且gcov没有完全看到你的代码,而是作为汇编指令的控制流图,其中分支作为图的边缘。

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. 因此,lcov html输出中的“ foo范围的结尾”实际上并不是foo方法范围的结束,而是foo之后包含在整个翻译单元中的所有内容,包括已经在foo中声明的全局变量的破坏。头文件。

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. 标题本身没有包含在问题中,但即使是gcc生成的最基本的__static_initialization_and_destruction程序集也包含了许多分支。

Note that you may have included global variables or you may have not - gcc still might generate this code for every translation unit. 请注意,您可能已包含全局变量,或者您可能没有 - gcc仍可能为每个翻译单元生成此代码。


Look at the underlying output of gcov: 看看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

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 首先将endbracket添加到最后一个functioncall行,这样它们就不会显示为单独的行

  • 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 . 作为一个超级简单的答案 ,分支表示IF / ELSE分支 So for every if/else there's two new branches (that should be covered); 所以对于每个if / else都有两个新的分支(应该被覆盖); 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 •第一个函数twoNewBranches创建了两个需要覆盖的新分支

• The second function twoNewBranchesNotAparent also creates two new branches, since you still have to cover the test that doesn't satisfy the if statement •第二个函数twoNewBranchesNotAparent也创建了两个新分支,因为您仍然必须覆盖不满足if语句的测试

• The third function fourNewBranches creates four (2^2=4) new branches to cover. •第三个函数fourNewBranches创建了四个(2 ^ 2 = 4)个新分支来覆盖。 Two nested, the parent of the nested, and the hidden else. 两个嵌套,嵌套的父级和隐藏的else。

Overall keep in mind covering branches, is about covering the conditional statements. 总体上要记住覆盖分支,是关于覆盖条件语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM