Code C : repérez et corrigez des particularités avec Coccinelle

Introduction au Code C avec Coccinelle

Lors de la vie d’une API écrite en code C (ou tout autre langage d’ailleurs), il arrive que cette dernière subisse des changements dans sa partie publique, imposant alors la modification de tous les codes l’appelant. C’est le cas notamment dans le noyau Linux où tous les drivers USB font appel à une API USB. Une modification dans la dite API peut entrainer la modification de plusieurs milliers de lignes de code C. Les contributeurs de chaque driver se retroussaient alors les manches, mais ca c’était avant… Avant Coccinelle.

Coccinelle est le nom donné à un ensemble d’outils dont l’outil de patch sémantique décrit ici.

Le patch sémantique

De la même manière que la commande UNIX patch permet de modifier du texte brut à l’aide d’une syntaxe standard. Coccinelle à travers son outil spatch permet de modifier du code C.

Avec son approche spath peut modifier plusieurs milliers de fichiers C là où un simple patch UNIX aurait été trop spécifique. Pour ce faire, spatch fait abstraction :

  • Des différences entre les espaces, indentations, retour chariots …
  • Du nom donné aux variables (spatch utilise des méta-variables)
  • Du code non pertinent (utilisation du mot clef “…”)
  • Des différentes manières d’écrire un code (isomorphysme) par exemple : if !y  équivaut à if (y == NULL) équivaut à if (NULL == y)

 

SPatch sur un exemple

Le code suivant contient une erreur:

#define SUCCES 8

int main(void)
{
  int res;

  res = call_my_func();
  if (!res & SUCCESS)
    return -1;
  else
    return 0;
}

L’idée étant ici de vérifier que le 8e bit de la valeur res est positionné à 1. En effet, la priorité est donnée à l’opérateur ! par rapport à l’opérateur &. Ce qui est l’effet inverse de ce que nous voudrions. Il faudrait parenthéser l’expression après le !.

Nous allons réaliser cela grâce au patch sémantique suivant:

@@
expression E;
constant C;
@@
- !E & C
+ !(E & C)

Ce patch se lit de la manière suivante : Pour toute expression E et constante C (tous deux au sens C du terme) pour toutes les lignes où l’on trouve non E & C, rajouter des parenthèses si elles n’y sont pas.

 

L’exécution de ce patch sémantique sur notre fichier c se fait:

spatch -sp_file myspatch.cocci main.c

Le résultat de cette commande sur la sortie standard sera le patch standard à effecter sur main.c:

HANDLING: main.c
diff =
--- main.c
+++ /tmp/cocci-output-14090-82e48f-main.c
@@ -7,7 +7,7 @@ int main(void)
   int res;

   res = call_my_func();
-  if (!res & SUCCESS)
+  if (!(res & SUCCESS))
     return -1;
   else
     return 0;

Bien entendu il est possible d’utiliser spatch avec des options permettant de traiter tout un répertoire, sans passer par un patch.

 

Installation et disponibilité

Coccinelle est porté en standard sur la majorité des distributions Linux mais n’est pas à proprement parler disponible sous Windows.

 

Pour en savoir plus :