2017-09-23 59 views
4

我的男人页,了解--coverage选项GCC声称:libgcov fork和exec钩

而且“叉”通话被检测到并正确处理(重复计算不会发生)。

而且我注意到我的/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”的过程从来没有写过其覆盖成果文件,因为特别是"In child 1"线执行,但没有显示为覆盖。在第二个fork之前的所有行似乎报告覆盖率增加了一倍,所以看起来覆盖率结果没有被重置在呼叫fork作为手册页声称。

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

回答

2

解决方法:用gnu11代替c11

-std=c11表示纯粹的C11(没有GNU扩展)。 -std=gnu11也支持GNU扩展。我无法解释-std=和之间的关系(可能-std=一般会影响内置函数的使用,而__gcov_fork就是其中之一),但只是简单地将标准更改为gnu11似乎可以解决问题,即第17行和29现在执行计数等于1.(我在GCC 5.4.0和最近的一个中继版本上都试过)。

P.S.我建议你提交一份错误报告。即使这种行为是有意的,编译器至少应该警告我们潜在的问题。

+0

修复:'__gcov_fork'不是内置函数。 'exec *'和'fork'是。 –