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