{"id":1612,"date":"2012-02-12T10:00:46","date_gmt":"2012-02-12T09:00:46","guid":{"rendered":"http:\/\/www.blaess.fr\/christophe\/?p=1612"},"modified":"2012-02-12T10:00:46","modified_gmt":"2012-02-12T09:00:46","slug":"mise-au-point-de-bibliotheque-dynamique-33","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2012\/02\/12\/mise-au-point-de-bibliotheque-dynamique-33\/","title":{"rendered":"Mise au point de biblioth\u00e8que dynamique (3\/3)"},"content":{"rendered":"<p style=\"text-align: justify;\">(english translation <a title=\"Development of a dynamic library (3\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/02\/12\/development-of-a-dynamic-library-33\/\">here<\/a>)<\/p>\n<p style=\"text-align: justify;\">Nous avons commenc\u00e9 la mise au point d&rsquo;une biblioth\u00e8que dynamique sous Linux dans les deux articles pr\u00e9c\u00e9dents&nbsp;: dans <a title=\"Mise au point de biblioth\u00e8que dynamique (1\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/01\/28\/mise-au-point-de-bibliotheque-dynamique-1-compilation-versions-et-liens-symboliques\/\" target=\"_blank\">le premier<\/a> nous avons vu comment compiler la biblioth\u00e8que et g\u00e9rer les num\u00e9ros de versions \u00e0 l&rsquo;aide de liens symboliques, dans <a title=\"Mise au point de biblioth\u00e8que dynamique (2\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/02\/04\/mise-au-point-de-bibliotheque-dynamique-23\/\" target=\"_blank\">le second<\/a> nous avons effectu\u00e9 du suivi d&rsquo;appel et du d\u00e9bogage pas-\u00e0-pas. Nous allons d\u00e9sormais nous int\u00e9resser \u00e0 la v\u00e9rification de la couverture de la biblioth\u00e8que.<\/p>\n<p>\n<!--more-->\n<\/p>\n<p style=\"padding-left: 60px; text-align: justify;\">La <em><strong>couverture de code<\/strong><\/em> est une mesure indiquant le pourcentage de lignes de code qui ont \u00e9t\u00e9 effectivement parcourues pendant une ex\u00e9cution d&rsquo;un programme. On \u00e9largit peu \u00e0 peu le jeu de tests afin d&rsquo;obtenir une couverture de 100% (et s&rsquo;assurer que le code a \u00e9t\u00e9 int\u00e9gralement v\u00e9rifi\u00e9).<\/p>\n<p style=\"text-align: justify;\">\u00a0L&rsquo;outil par excellence sous Linux est <code>gcov<\/code>, qui instrumente le code source et nous fournit des statistiques d\u00e9taill\u00e9es apr\u00e8s ex\u00e9cution. Il est facile de l&rsquo;utiliser pour v\u00e9rifier la couverture d&rsquo;un fichier source compil\u00e9 directement dans un ex\u00e9cutable&nbsp;; nous allons l&#8217;employer pour le code d&rsquo;une biblioth\u00e8que ce qui n\u00e9cessite quelques suppl\u00e9ments d&rsquo;attention.<\/p>\n<h1>\u00a0Compilation<\/h1>\n<p style=\"text-align: justify;\">Reprenons les m\u00eames fichiers et r\u00e9pertoires (regroup\u00e9s <a title=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-02-12\/factorielle-3.tar.bz2\" href=\"http:\/\/www.blaess.fr\/christophe\/files\/article-2012-02-12\/factorielle-3.tar.bz2\" target=\"_blank\">dans cette archive<\/a>) que pour les articles pr\u00e9c\u00e9dents. Un r\u00e9pertoire\u00a0 principal nomm\u00e9 \u00ab\u00a0<code>factorielle<\/code>\u00a0\u00bb contient quatre sous-r\u00e9pertoires&nbsp;: <code>src<\/code>, <code>include<\/code> et <code>lib<\/code> o\u00f9 se trouvent respectivement les fichiers sources, les fichiers d&rsquo;en-t\u00eate et les fichiers compil\u00e9s de la biblioth\u00e8que. Le quatri\u00e8me sous-r\u00e9pertoire \u00ab\u00a0<code>test<\/code>\u00a0\u00bb contient les fichiers source et ex\u00e9cutable d&rsquo;un programme utilisant notre biblioth\u00e8que <code>libfact<\/code>.<\/p>\n<pre>[~]$ <strong>cd factorielle\/<\/strong>\n[factorielle]$ <strong>ls<\/strong>\ninclude  lib  src  test\n[factorielle]$ <strong>ls include\/<\/strong>\nfact.h\n[factorielle]$ <strong>ls lib\/<\/strong>\nlibfact.so  libfact.so.2  libfact.so.2.0\n[factorielle]$ <strong>ls src\/<\/strong>\nfact.c\n[factorielle]$ <strong>ls test\/<\/strong>\ncalcule-factorielle.c\n[factorielle]$<\/pre>\n<p style=\"padding-left: 60px; text-align: justify;\">NB: la biblioth\u00e8que \u00e9tait d\u00e9j\u00e0 compil\u00e9e ci-dessus, mais nous allons la r\u00e9g\u00e9n\u00e9rer.<\/p>\n<p style=\"text-align: justify;\">La premi\u00e8re \u00e9tape consiste \u00e0 compiler le code de la biblioth\u00e8que. Nous allons proc\u00e9der comme dans le <a title=\"Mise au point de biblioth\u00e8que dynamique (1\/3)\" href=\"http:\/\/www.blaess.fr\/christophe\/2012\/01\/28\/mise-au-point-de-bibliotheque-dynamique-1-compilation-versions-et-liens-symboliques\/\" target=\"_blank\">premier article<\/a>, mais cette fois en ajoutant l&rsquo;option <code>--coverage<\/code> de <code>gcc<\/code>. Cette option a deux r\u00f4les diff\u00e9rents .<\/p>\n<ul>\n<li style=\"text-align: justify;\">Lors de la phase de compilation elle a la m\u00eame signification que <code>-fprofile-arcs<\/code> et <code>-ftest-coverage<\/code> (que l&rsquo;on utilisaient avec les versions pr\u00e9c\u00e9dentes de <code>gcc<\/code>)&nbsp;: la premi\u00e8re ajoute dans le code ex\u00e9cutable des informations d&rsquo;instrumentation (compteurs de passage), la seconde cr\u00e9e une table de correspondance entre ces \u00e9l\u00e9ments et les lignes de code source (un fichier nomm\u00e9 \u00e0 partir du fichier source avec l&rsquo;extension <code>.gcno<\/code>)<\/li>\n<li style=\"text-align: justify;\">Pendant la phase d&rsquo;\u00e9dition des liens, elle est \u00e9quivalente \u00e0 <code>-lgcov<\/code> (qui \u00e9tait ajout\u00e9e automatiquement par <code>-ftest-coverage<\/code>) qui incorpore les points d&rsquo;entr\u00e9e n\u00e9cessaire pour l&#8217;emploi ult\u00e9rieur de <code>gcov<\/code>.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Voici la compilation de notre biblioth\u00e8que.<\/p>\n<pre>[factorielle]$ <strong>gcc -c --coverage -fPIC -I include\/ -o .\/src\/fact.o .\/src\/fact.c <\/strong>\n[factorielle]$ <strong>ls src\/<\/strong>\nfact.c  fact.gcno  fact.o\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Nous voyons qu&rsquo;avec l&rsquo;option <code>--coverage<\/code> la compilation a g\u00e9n\u00e9r\u00e9, outre le fichier objet <code>fact.o<\/code>, un fichier <code>fact.gcno<\/code> contenant les relations entre les blocs de code et les num\u00e9ros de lignes. Continuons.<\/p>\n<pre>[factorielle]$ <strong>gcc -shared -I include\/ -Wl,-soname,libfact.so.2 -o lib\/libfact.so.2.0 .\/src\/fact.o --coverage <\/strong>\n[factorielle]$ <strong><code>ls -l lib\/<\/code><\/strong>\ntotal 20\nlrwxrwxrwx 1 cpb cpb    12 2012-02-11 13:39 libfact.so -&gt; libfact.so.2\nlrwxrwxrwx 1 cpb cpb    14 2012-02-11 13:39 libfact.so.2 -&gt; libfact.so.2.0\n-rwxrwxr-x 1 cpb cpb 16866 2012-02-11 17:10 libfact.so.2.0\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Nous avons re-cr\u00e9\u00e9 la biblioth\u00e8que <code>libfact.so.2.0<\/code>. Les liens symboliques permettent de g\u00e9rer les num\u00e9ros de version majeurs et mineurs, comme nous l&rsquo;avons vu dans le premier article. Compilons \u00e0 pr\u00e9sent un fichier ex\u00e9cutable, sans l&rsquo;option <code>--coverage<\/code> (ou conservons le fichier ex\u00e9cutable des articles pr\u00e9c\u00e9dents).<\/p>\n<pre>[factorielle]$ <strong>gcc -I include\/ -L lib\/ -o test\/calcule-factorielle test\/calcule-factorielle.c -lfact<\/strong>\n[factorielle]$ <strong>ls test\/<\/strong>\ncalcule-factorielle  calcule-factorielle.c\n[factorielle]$<\/pre>\n<h1>Ex\u00e9cution<\/h1>\n<p style=\"text-align: justify;\">L&rsquo;ex\u00e9cution du programme se d\u00e9roule tout \u00e0 fait normalement (bien qu&rsquo;en pratique il soit l\u00e9g\u00e8rement ralenti). Il faut, bien s\u00fbr, penser \u00e0 renseigner la variable d&rsquo;environnement <code>LD_LIBRARY_PATH<\/code> pour indiquer o\u00f9 l&rsquo;\u00e9diteur de lien dynamique trouvera la biblioth\u00e8que n\u00e9cessaire au fonctionnement de l&rsquo;application.<\/p>\n<pre>[factorielle]$ <strong>export LD_LIBRARY_PATH=lib\/<\/strong>\n[factorielle]$ <strong>test\/calcule-factorielle 4 5 6<\/strong>\n4! = 24\n5! = 120\n6! = 720\n[factorielle]$ <strong>ls src\/<\/strong>\nfact.c  fact.gcda  fact.gcno  fact.o\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Un nouveau fichier <code>fact.gcda<\/code> est apparu, qui contient les statistiques d&rsquo;ex\u00e9cution des blocs de <code>fact.gcno<\/code> (et des transitions entre blocs).<\/p>\n<h1>Exploitation des r\u00e9sultats<\/h1>\n<p style=\"text-align: justify;\">Pour obtenir des informations sur la couverture du code d&rsquo;un fichier source, nous invoquons <code>gcov<\/code> en indiquant le nom du fichier source. Les donn\u00e9es sont en effet valable ind\u00e9pendamment pour chaque fichier source de l&rsquo;application (ou de la biblioth\u00e8que).<\/p>\n<p style=\"text-align: justify;\">Nous allons utiliser l&rsquo;option <code>-o<\/code> de <code>gcov<\/code> pour pr\u00e9ciser le nom du r\u00e9pertoire o\u00f9 se trouvent les fichiers <code>.c<\/code>, <code>.gcno<\/code> et <code>.gcda<\/code>.<\/p>\n<pre>[factorielle]$ <strong>gcov -o src\/ fact.c<\/strong>\nFile '.\/src\/fact.c'\nLignes ex\u00e9cut\u00e9es: 87.50% de 8\n.\/src\/fact.c:creating 'fact.c.gcov'\n\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\"><code>gcov<\/code> nous indique que nous n&rsquo;avons ex\u00e9cut\u00e9 que 87.5% des huit lignes de code de notre fonction. Comment savoir ce qui s&rsquo;est pass\u00e9&nbsp;? Nous voyons que <code>gcov<\/code> a aussi cr\u00e9\u00e9 un fichier <code>fact.c.gcov<\/code> dans lequel il reprend notre code source, num\u00e9rote les lignes, ajoute un en-t\u00eate et une colonne de statistiques en d\u00e9but de ligne.<\/p>\n<pre>[factorielle]$ <strong>ls<\/strong>\nfact.c.gcov  include  lib  src  test\n[factorielle]$ <strong>cat fact.c.gcov <\/strong>\n        -:    0:Source:.\/src\/fact.c\n        -:    0:Graph:src\/fact.gcno\n        -:    0:Data:src\/fact.gcda\n        -:    0:Runs:1\n        -:    0:Programs:1\n        -:    1:#include\n        -:    2:\n        3:    3:int factorielle(long int n, long long int * result)\n        -:    4:{\n        3:    5:\t* result = 1;\n        3:    6:\tif (n &lt; 0)\n    #####:    7:\t\treturn -1;\n        -:    8:\tdo {\n       12:    9:\t\t(*result) = (*result) * n;\n       12:   10:\t\tn = n - 1;\n       12:   11:\t} while (n &gt; 1);\n        3:   12:\treturn 0;\n        -:   13:}\n        -:   14:\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">L&rsquo;en-t\u00eate d\u00e9crit les fichiers concern\u00e9s et le nombre d&rsquo;ex\u00e9cutions (ici une seule pour le moment). La colonne de gauche indique le nombre de passages sur chaque ligne. Les lignes contenant un tiret \u00ab\u00a0<code>-<\/code>\u00a0\u00bb ne correspondent \u00e0 aucun code compil\u00e9. Nous voyons que les lignes 3, 5, 6 et 12 ont \u00e9t\u00e9 parcourues \u00e0 trois reprises (une invocation pour chaque argument de la ligne de commande), et les lignes 9, 10, et 11 ont ex\u00e9cut\u00e9es 12 fois (les it\u00e9rations pour calculer les factorielles).<\/p>\n<p style=\"text-align: justify;\">Si nous r\u00e9it\u00e9rons l&rsquo;op\u00e9ration, les compteurs se cumulent.<\/p>\n<pre>$ <strong>test\/calcule-factorielle 3 8<\/strong>\n3! = 6\n8! = 40320\n[factorielle]$ <strong>gcov -o src\/ fact.c<\/strong>\nFile '.\/src\/fact.c'\nLignes ex\u00e9cut\u00e9es: 87.50% de 8\n.\/src\/fact.c:creating 'fact.c.gcov'\n\n[factorielle]$ <strong>test\/calcule-factorielle 3 8<\/strong>\n3! = 6\n8! = 40320\n[factorielle]$ <strong>cat fact.c.gcov <\/strong>\n        -:    0:Source:.\/src\/fact.c\n        -:    0:Graph:src\/fact.gcno\n        -:    0:Data:src\/fact.gcda\n        -:    0:Runs:2\n        -:    0:Programs:1\n        -:    1:#include\n        -:    2:\n        5:    3:int factorielle(long int n, long long int * result)\n        -:    4:{\n        5:    5:\t* result = 1;\n        5:    6:\tif (n &lt; 0)\n    #####:    7:\t\treturn -1;\n        -:    8:\tdo {\n       21:    9:\t\t(*result) = (*result) * n;\n       21:   10:\t\tn = n - 1;\n       21:   11:\t} while (n &gt; 1);\n        5:   12:\treturn 0;\n        -:   13:}\n        -:   14:\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Et la ligne 7&nbsp;? Pourquoi ces \u00ab\u00a0<code>#####<\/code>\u00a0\u00bb ?<\/p>\n<p style=\"text-align: justify;\">Contrairement aux tableurs courants, ce symbole ne signifie pas que le nombre est trop grand pour tenir dans la colonne, mais que la ligne (qui correspond bien \u00e0 du code compil\u00e9) n&rsquo;a jamais \u00e9t\u00e9 ex\u00e9cut\u00e9e. Deux int\u00e9r\u00eats \u00e0 cette notation&nbsp;:<\/p>\n<ul>\n<li style=\"text-align: justify;\">attirer l&rsquo;oeil lors du parcours du listing plut\u00f4t qu&rsquo;un simple \u00ab\u00a0<code>0<\/code>\u00a0\u00bb ;<\/li>\n<li style=\"text-align: justify;\">permettre une recherche automatis\u00e9e des lignes non ex\u00e9cut\u00e9es \u00e0 l&rsquo;aide de <code>grep<\/code>.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Voyons&nbsp;:<\/p>\n<pre>[factorielle]$ <strong>gcov -o src\/ fact.c<\/strong>\nFile '.\/src\/fact.c'\nLignes ex\u00e9cut\u00e9es: 87.50% de 8\n.\/src\/fact.c:creating 'fact.c.gcov'\n\n[factorielle]$ <strong>grep \"#####\" fact.c.gcov<\/strong>\n    #####:    7:\t\treturn -1;\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Le num\u00e9ro de ligne (7) \u00e9tant affich\u00e9 ainsi que son contenu, cela permet un aper\u00e7u rapide du code non parcouru.<\/p>\n<h1>Correction<\/h1>\n<p style=\"text-align: justify;\">Nous avons d\u00e9tect\u00e9 un probl\u00e8me de test de notre biblioth\u00e8que, puisqu&rsquo;une branche n&rsquo;a jamais \u00e9t\u00e9 ex\u00e9cut\u00e9e. Ceci peut \u00eatre d\u00fb \u00e0 plusieurs raisons.<\/p>\n<ul>\n<li style=\"text-align: justify;\">Un jeu de test incomplet. C&rsquo;est le cas ici et nous allons y rem\u00e9dier facilement ci-dessous.<\/li>\n<li style=\"text-align: justify;\">Du code ancien qui n&rsquo;est plus jamais appel\u00e9 (code mort). Il est important de le faire dispara\u00eetre car il perturbe la maintenance du programme.<\/li>\n<li style=\"text-align: justify;\">Des lignes de code qui servent \u00e0 g\u00e9rer des cas d&rsquo;erreur rares, difficiles \u00e0 tester. Nous y reviendrons dans le prochain paragraphe.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Ici la solution est simple, la ligne non test\u00e9e correspond \u00e0 une invocation de la fonction avec un argument n\u00e9gatif. C&rsquo;est facile \u00e0 produire.<\/p>\n<pre>[factorielle]$ <strong>test\/calcule-factorielle -1<\/strong>\n-1! n'existe pas\n[factorielle]$ <strong>gcov -o src\/ fact.c<\/strong>\nFile '.\/src\/fact.c'\nLignes ex\u00e9cut\u00e9es: 100.00% de 8\n.\/src\/fact.c:creating 'fact.c.gcov'\n\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">A pr\u00e9sent, <code>gcov<\/code> nous indique que toutes les lignes de notre programme ont \u00e9t\u00e9 couvertes par notre jeu de test. Cela r\u00e9duit la probabilit\u00e9 de bug restant.<\/p>\n<h1>Traitement d&rsquo;erreur<\/h1>\n<p style=\"text-align: justify;\">Une grosse difficult\u00e9 pour assurer une couverture de code \u00e0 100% lors des tests d&rsquo;un logiciel est de valider les comportements en cas d&rsquo;erreur syst\u00e8me.<\/p>\n<p style=\"text-align: justify;\">Prenons le cas d&rsquo;un appel-syst\u00e8me classique&nbsp;: <code>malloc()<\/code>. On lui demande de nous allouer une zone m\u00e9moire d&rsquo;une certaine taille (pr\u00e9cis\u00e9e en octets) et il nous renvoie un pointeur. Toutes les documentations pr\u00e9cisent qu&rsquo;en cas de manque de m\u00e9moire, <code>malloc()<\/code> renvoie un pointeur <code>NULL<\/code>. (Bien qu&rsquo;en pratique sous Linux ce soit particuli\u00e8rement difficile \u00e0 produire, nous en reparlerons dans un futur article).<br \/>\nAussi, le programmeur consciencieux \u00e9crira-t-il quelque chose comme.<\/p>\n<pre>    char * buffer;\n    buffer = malloc(TAILLE_BUFFER);\n    if (buffer == NULL) {\n        signaler_erreur(\"Manque de memoire\");\n        enregistrer_code_d_erreur(-ENOMEM);\n        return -1;\n    }\n    \/\/ ...<\/pre>\n<p style=\"text-align: justify;\">Malheureusement les lignes de la portion entre accolades sont difficiles \u00e0 tester car on ne peut pas \u00ab\u00a0forcer\u00a0\u00bb <code>malloc()<\/code> \u00e0 \u00e9chouer&nbsp;; les circonstances reposent sur trop de param\u00e8tres externes \u00e0 l&rsquo;application pour \u00eatre r\u00e9ellement reproductible.<\/p>\n<p style=\"padding-left: 60px; text-align: justify;\">Dans le cas pr\u00e9cis de <code>malloc()<\/code>, la GlibC nous offre des points d&rsquo;entr\u00e9es que l&rsquo;on peut utiliser pour remplacer la fonction &#8211; voir <code>malloc_hook(3)<\/code> &#8211; mais \u00e7a n&rsquo;est pas souvent le cas avec les appels-syst\u00e8me.<\/p>\n<p style=\"text-align: justify;\">Il existe n\u00e9anmoins plusieurs solutions. L&rsquo;une d&rsquo;elle, que j&rsquo;ai utilis\u00e9e plusieurs fois, consiste \u00e0 employer une couche logicielle minimale qui reproduit les appels-syst\u00e8me dont nous avons besoin en simulant un \u00e9chec si certains crit\u00e8res sont remplis. Par exemple la routine suivante reproduit <code>malloc()<\/code> mais \u00e9choue au bout d&rsquo;un nombre d&rsquo;invocations contenu dans la variable d&rsquo;environnement <code>MALLOC_FAIL<\/code>.<\/p>\n<pre><strong>src\/my_malloc.c:<\/strong>\n\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n\nvoid * my_malloc(size_t length)\n{\n\tchar * string;\n\tchar buffer[32];\n\tint count;\n\tstring = getenv (\"MALLOC_FAIL\");\n\tif (string != NULL) {\n\t\tif (sscanf(string, \"%d\", &amp; count)  == 1) {\n\t\t\tcount --;\n\t\t\tif (count == 0)\n\t\t\t\treturn NULL;\n\t\t\tsnprintf(buffer, 80, \"%d\", count);\n\t\t\tsetenv(\"MALLOC_FAIL\", buffer, 1 );\n\t\t}\n\t}\n\treturn malloc(length);\n}<\/pre>\n<p style=\"text-align: justify;\">On peut la d\u00e9clarer dans un fichier d&rsquo;en-t\u00eate ainsi:<\/p>\n<pre><strong>include\/my_malloc.h:<\/strong>\n\n#ifndef MY_MALLOC_H\n#define MY_MALLOC_H\n\n#ifndef NDEBUG\n        extern void * my_malloc(size_t);\n#else\n#define my_malloc(L) malloc(L)\n#endif\n\n#endif<\/pre>\n<p style=\"text-align: justify;\">De cette mani\u00e8re, suivant la pr\u00e9sence ou non de la constante <code>NDEBUG<\/code>, qui repr\u00e9sente traditionnellement la compilation en version \u00ab\u00a0production\u00a0\u00bb pour la biblioth\u00e8que C, notre routine sera compil\u00e9e comme le <code>malloc()<\/code> habituel ou avec notre gestion de la variable d&rsquo;environnement.<\/p>\n<p style=\"text-align: justify;\">Compilons une biblioth\u00e8que dynamique avec notre couche d&rsquo;abstraction minimale.<\/p>\n<pre>[factorielle]$ <strong>gcc -c -fPIC -Wall -I include\/ -o src\/my_malloc.o src\/my_malloc.c <\/strong>\n[factorielle]$ <strong>gcc -shared -Wl,-soname,libmytest.so.1 -o lib\/libmytest.so.1.0 src\/my_malloc.o<\/strong>\n[factorielle]$ <strong>ldconfig -n lib\/<\/strong>\n[factorielle]$ <strong>ln -sf libmytest.so.1 lib\/libmytest.so<\/strong>\n[factorielle]$ <strong>ls -l lib\/libmy*<\/strong>\nlrwxrwxrwx 1 cpb cpb   14 2012-02-12 04:12 lib\/libmytest.so -&gt; libmytest.so.1\nlrwxrwxrwx 1 cpb cpb   16 2012-02-12 04:11 lib\/libmytest.so.1 -&gt; libmytest.so.1.0\n-rwxrwxr-x 1 cpb cpb 7014 2012-02-12 04:11 lib\/libmytest.so.1.0\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Cr\u00e9ons un petit executable qui utilise notre biblioth\u00e8que de test en bouclant autour du <code>my_malloc()<\/code><\/p>\n<pre><strong>test\/test-mymalloc.c:<\/strong>\n\n#include &lt;stdio.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;my_malloc.h&gt;\n\nint main(void)\n{\n        int i = 1;\n        while(1) {\n                fprintf(stderr, \"i = %2d...\", i);\n                if (<strong>my_malloc<\/strong>(10) == NULL) {\n                        fprintf(stderr, \"echec !n\");\n                        break;\n                }\n                fprintf(stderr, \"okn\");\n                i ++;\n        }\n        return 0;\n}<\/pre>\n<p style=\"text-align: justify;\">Compilation&#8230;<\/p>\n<pre>[factorielle]$ <strong>gcc -I include\/ -L lib\/ -Wall -o test\/test-mymalloc test\/test-mymalloc.c -lmytest<\/strong>\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Et premier test, sans d\u00e9finir la variable d&rsquo;environnement.<\/p>\n<pre>[factorielle]$ <strong>unset MALLOC_FAIL<\/strong>\n[factorielle]$ <strong>.\/test\/test-mymalloc <\/strong>\ni =  1...ok\ni =  2...ok\ni =  3...ok\ni =  4...ok\ni =  5...ok\n[...]\ni = 21928...ok\ni = 21929...ok\ni = 21930...ok\ni = 21931...ok\ni = 21932...\n  (<strong><em>Contr\u00f4le-C<\/em><\/strong>)\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Bien entendu, notre programme ne s&rsquo;arr\u00eate pas. Ou plut\u00f4t il s&rsquo;arr\u00eatera au bout d&rsquo;un long moment apr\u00e8s avoir \u00e9puis\u00e9 ses 3Go d&rsquo;espace d&rsquo;adressage (sur une machine 32 bits).<\/p>\n<p style=\"text-align: justify;\">R\u00e9-essayons en for\u00e7ant un \u00e9chec au quatri\u00e8me appel de <code>malloc()<\/code>.<\/p>\n<pre>[factorielle]$ <strong>export MALLOC_FAIL=4<\/strong>\n[factorielle]$ <strong>.\/test\/test-mymalloc<\/strong>\ni =  1...ok\ni =  2...ok\ni =  3...ok\ni =  4...echec !\n[factorielle]$<\/pre>\n<p style=\"text-align: justify;\">Naturellement, ce principe consistant \u00e0 faire \u00e9chouer les appels aux fonctions syst\u00e8me sous le contr\u00f4le d&rsquo;une variable d&rsquo;environnement &#8211; ou d&rsquo;autres param\u00e8tres (variable globale, fichier, zone de m\u00e9moire partag\u00e9e, etc.) &#8211; peut s&rsquo;appliquer autant au contenu d&rsquo;une biblioth\u00e8que qu&rsquo;\u00e0 celui d&rsquo;un ex\u00e9cutable lorsqu&rsquo;on a besoin d&rsquo;assurer une couverture de code de 100% sur l&rsquo;ensemble du jeu de tests d&rsquo;une application.<\/p>\n<h1>Conclusion<\/h1>\n<p style=\"text-align: justify;\">Nous avons observ\u00e9 dans cette petite s\u00e9rie d&rsquo;articles, comment cr\u00e9er, d\u00e9boguer et tester une biblioth\u00e8que dynamique. Je vous encourage \u00e0 faire vos propres essais, en vous reportant \u00e0 la documentation de <code>gcc<\/code>, <code>gdb<\/code>, <code>gcov<\/code>, mais \u00e9galement d&rsquo;autres outils compl\u00e9mentaires comme <code>gprof<\/code>, <code>ldconfig<\/code>, <code>valgrind<\/code>, etc.<\/p>\n<p style=\"text-align: center;\">Tous les commentaires, remarques, corrections, etc. sont les bienvenus.<\/p>","protected":false},"excerpt":{"rendered":"<p>(english translation here) Nous avons commenc&eacute; la mise au point d&rsquo;une biblioth&egrave;que dynamique sous Linux dans les deux articles pr&eacute;c&eacute;dents&nbsp;: dans le premier nous avons vu comment compiler la biblioth&egrave;que et g&eacute;rer les num&eacute;ros de versions &agrave; l&rsquo;aide de liens symboliques, dans le second nous avons effectu&eacute; du suivi d&rsquo;appel et du d&eacute;bogage pas-&agrave;-pas. Nous [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-1612","post","type-post","status-publish","format-standard","hentry","category-linux-2"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1612","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=1612"}],"version-history":[{"count":0,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/1612\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=1612"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=1612"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=1612"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}