2017-09-23 68 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'是。 –