2017-09-23 5 views
4

Ma page de manuel pour les demandes de gcc sur l'option --coverage:fourche libgcov et crochets exec

sont détectées et traitées correctement également les appels « fourchette » (double comptage ne se produira pas).

Et je remarque que mon /usr/lib/gcc/x86_64-linux-gnu/5.4.0/libgcov.a contient des symboles __gcov_fork, __gcov_execl et autres __gcov_exec* variantes. En regardant les définitions de ces fonctions en ligne, il semble qu'ils videraient et effaceraient la sortie de la couverture pour éviter la duplication ou la perte des données.

Mais cela ne semble pas fonctionner pour moi:

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$ 

Il semble à moi comme le processus « enfant 1 » n'a jamais écrit ses résultats de couverture à déposer, puisque notamment la ligne "In child 1" exécutée mais n'est pas montré comme couvert. Et toutes les lignes avant la seconde fork semblent signaler une couverture doublée, il semble donc que les résultats de la couverture n'ont pas été réinitialisés à l'appel fork comme la page de manuel revendiquée.

Y at-il quelque chose d'autre que je dois faire pour activer ces crochets de libgcov? Je ne suis pas censé remplacer les syscalls avec les noms réels de crochet juste en compilant en mode de couverture, suis-je?

Répondre

2

Solution: remplacez c11 par gnu11.

-std=c11 signifie C11 pur (sans extensions GNU). -std=gnu11 permet également les extensions GNU. Je ne peux pas expliquer la connexion entre -std= et --coverage (probablement -std= affecte l'utilisation de la fonction intégrée en général, et __gcov_fork est l'un d'eux), mais il suffit de changer la norme à gnu11 semble résoudre le problème, à savoir, à la fois la ligne 17 et 29 ont maintenant un nombre d'exécution égal à 1. (Je l'ai essayé à la fois sur GCC 5.4.0 et une révision de tronc récente).

P.S. Je vous suggère de déposer un rapport de bug. Même si ce comportement est prévu, le compilateur devrait au moins nous avertir des problèmes potentiels.

+0

Correction: '__gcov_fork' n'est pas une fonction intégrée. 'exec *' et 'fork' sont. –