我的gcc的人手页面声称有关--coverage
选项的:
还可以检测并正确处理“fork”调用(不会发生重复计数)。
我注意到我的/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$
我发现“child 1”进程似乎从未将其覆盖结果写入文件,因为特别是执行了“在 child 1 中”但未显示为已覆盖。并且第二个“fork”之前的所有行似乎报告了加倍的覆盖率,因此似乎在调用“fork”时未重置覆盖率结果,正如手册所述。
是否还需要做其他事情才能启用那些libgcov hooks?我不应该在编译覆盖模式时实际替换syscalls为实际hook名称,对吗?
__gcov_fork
不是内置函数,exec*
和fork
是。 - Mikhail Maltsev-std=c11
模式下,GCC 不会假设它知道 POSIX 函数的工作方式。 - Tavian Barnes