其他分享
首页 > 其他分享> > libgcov fork和exec hooks

libgcov fork和exec hooks

作者:互联网

我的gcc的手册页声称–coverage选项:

Also “fork” calls are detected and correctly handled (double counting will not happen).

我注意到我的/usr/lib/gcc/x86_64-linux-gnu/5.4.0/libgcov.a包含符号__gcov_fork,__ gcov_execl和其他__gcov_exec *变体.在线查看这些函数的定义,看起来它们会转储并清除覆盖输出以避免重复或丢失数据.

但这对我来说似乎不起作用:

gcov_test$rm *.gcno *.gcda
gcov_test$cat gcov_test.c
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void) {
    puts("Before loop");
    for (int i=0; i<5; ++i)
        printf("i=%d\n", i);
    puts("After loop");
    pid_t child1 = fork();
    if (child1<0) {
        perror("fork 1");
        exit(1);
    } else if (child1==0) {
        printf("In child 1: %d\n", (int)getpid());
        execl("/bin/true", "/bin/true", (char*)NULL);
        perror("execl");
        exit(1);
    }
    printf("Parent spawned child 1: %d\n", (int)child1);
    pid_t child2 = fork();
    if (child2<0)
    {
        perror("fork 2");
        exit(1);
    } else if (child2==0) {
        printf("In child 2: %d\n", (int)getpid());
    } else {
        printf("Parent spawned child 2: %d\n", (int)child2);
        if (waitpid(child1, NULL, 0)<0)
            perror("waitpid 1");
        if (waitpid(child2, NULL, 0)<0)
            perror("waitpid 2");
        puts("Parent done");
    }
    return 0;
}

gcov_test$gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

gcov_test$gcc -c -std=c11 -Wall --coverage gcov_test.c 
gcov_test$gcc --coverage gcov_test.o -o gcov_test
gcov_test$./gcov_test
Before loop
i=0
i=1
i=2
i=3
i=4
After loop
Parent spawned child 1: 31569
Parent spawned child 2: 31570
In child 2: 31570
In child 1: 31569
Parent done
gcov_test$gcov gcov_test.c
File 'gcov_test.c'
Lines executed:64.29% of 28
Creating 'gcov_test.c.gcov'

gcov_test$cat gcov_test.c.gcov
        -:    0:Source:gcov_test.c
        -:    0:Graph:gcov_test.gcno
        -:    0:Data:gcov_test.gcda
        -:    0:Runs:2
        -:    0:Programs:1
        -:    1:#include <stdlib.h>
        -:    2:#include <stdio.h>
        -:    3:#include <unistd.h>
        -:    4:#include <sys/types.h>
        -:    5:#include <sys/wait.h>
        -:    6:
        2:    7:int main(void) {
        2:    8:    puts("Before loop");
       12:    9:    for (int i=0; i<5; ++i)
       10:   10:        printf("i=%d\n", i);
        2:   11:    puts("After loop");
        2:   12:    pid_t child1 = fork();
        2:   13:    if (child1<0) {
    #####:   14:        perror("fork 1");
    #####:   15:        exit(1);
        2:   16:    } else if (child1==0) {
    #####:   17:        printf("In child 1: %d\n", (int)getpid());
    #####:   18:        execl("/bin/true", "/bin/true", (char*)NULL);
    #####:   19:        perror("execl");
    #####:   20:        exit(1);
        -:   21:    }
        2:   22:    printf("Parent spawned child 1: %d\n", (int)child1);
        2:   23:    pid_t child2 = fork();
        2:   24:    if (child2<0)
        -:   25:    {
    #####:   26:        perror("fork 2");
    #####:   27:        exit(1);
        2:   28:    } else if (child2==0) {
        1:   29:        printf("In child 2: %d\n", (int)getpid());
        -:   30:    } else {
        1:   31:        printf("Parent spawned child 2: %d\n", (int)child2);
        1:   32:        if (waitpid(child1, NULL, 0)<0)
    #####:   33:            perror("waitpid 1");
        1:   34:        if (waitpid(child2, NULL, 0)<0)
    #####:   35:            perror("waitpid 2");
        1:   36:        puts("Parent done");
        -:   37:    }
        2:   38:    return 0;
        -:   39:}
        -:   40:
gcov_test$

在我看来,“子1”进程从未将其覆盖结果写入文件,因为特别是“在子1中”执行但未显示为覆盖.并且第二个分支之前的所有行似乎报告了双倍的覆盖率,因此看起来覆盖结果没有在调用fork时重置,因为man页面声称.

我还需要做些什么来启用那些libgcov挂钩吗?在编译覆盖模式时,我不应该用实际的挂钩名称替换系统调用,是吗?

解决方法:

解决方案:用gnu11替换c11.

-std = c11表示纯C11(没有GNU扩展名). -std = gnu11也启用GNU扩展.我无法解释-std =和–coverage之间的联系(可能-std =影响内置函数的使用情况,而__gcov_fork就是其中之一),但只是将标准改为gnu11似乎解决了这个问题,即,第17行和第29行的执行计数现在都等于1.(我在GCC 5.4.0和最近的主干版本上都试过了).

附:我建议你提交bug报告.即使出于这种行为,编译器也应该至少警告我们潜在的问题.

标签:c-3,linux,gcc,gcov
来源: https://codeday.me/bug/20190701/1348876.html