Cher lecteur,

Cette article concerne les développeurs. En effet combien de fois on s'est arraché les cheveux à essayé de comprendre pourquoi son application segfault.Ceci c'est terminé avec dustmite!

Cet outil va réduire le code jusqu’à généré un code minimaliste provoquant l'erreur. Cet outil fonctionne pour le langage D et il peut être étendu à d'autres langages. Le projet à juste besoin de vous :-) . dustmite sera fourni à partir de fedora 17 dans les dépôts officiels.

Fichier core


  1. $ ulimit -c unlimited

Dans un premier temps il faut autoriser la création de fichier core lorsqu'un programme segfault

Espace de travail


  1. $ mkdir workdir

Ensuite on créer un répertoire dans le quel dustmite travaillera

Très originale comme nom de dossier :-D

Sources

Ensuite on va mettre les fichiers app.d et utild.d dans le dossier workdir. C'est le programme qui va planter :-D


  1. import std.string;
  2. import std.stdio;
  3.  
  4. import util;
  5.  
  6. void main( ){
  7. A* a = null;
  8. *a = A( [2uL, 3uL, 4uL] );
  9. (*a).append( 5u );
  10. writeln( (*a).length );
  11. if( (*a).length > 3 )
  12. a = null;
  13. writeln( (*a).length );
  14. (*a).append( 0u );
  15. writeln( (*a).length );
  16. }

app.d


  1. module util;
  2.  
  3. struct A{
  4. size_t[] items;
  5. size_t length;
  6.  
  7. this( size_t[] items ){
  8. this.items = items;
  9. this.length = items.length;
  10. }
  11.  
  12. void append( size_t item ){
  13. this.items ~= item;
  14. }
  15. }

utild.d

Compilation


  1. $ (cd workdir && ldc2 app.d util.d -of=app && rm *.o)

Compilation du programme.

Note: j'ai supprimé les fichier .o généré cat ceux ci peuvent géner plus loin dustmite

Génération du fichier core


  1. $ (cd workdir && ./app )

Éxécutons le programme, il va générer un fichier core:

DustMite


  1. $ DustMite workdir/ "(ldc2 app.d util.d -ofapp && ./app) 2>&1| grep -qF 'Segmentation fault'"

Maintenant il reste plus qu’a dustmite de nous dire pourquoi le programme segfault

Ici plusieurs chose importante:

  1. spécifier a dustmite le dossier de travail
  2. il faut donner la commande de construction a dustmite => ldc2 app.d util.d -ofapp
  3. lui dire comment lancer l'appilcation => ./app
  4. ne pas oublier les parenthèses ()
  5. fusionner la sortie d'erreur sur la sortie standard =>2>&1
  6. dustmite récupère la sortie par conséquent il faut filtrer via grep sur notre segfault. (attention ici la locale utilisé est C donc penser a mettre le bon motif dans votre commande grep

Ainsi dustmite peut faire son travail

$ DustMite workdir/ "(ldc2 app.d util.d -ofapp  && ./app)  2>&1| grep -qF 'Segmentation fault'"
None => Yes
############### ITERATION 0 ################
============= Depth 0 =============
Remove [1/4] => Yes
Remove [1/3] => No
Remove [2/3] => Yes
Remove [2/2] => No
############### ITERATION 1 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/2] => Yes
Remove [1/2, 1/1] => No
Remove [2/2, 1/4] => Yes
Remove [2/2, 1/3] => No
Remove [2/2, 2/3] => No
Remove [2/2, 3/3] => No
############### ITERATION 2 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/3] => No (cached)
Remove [2/2, 2/3] => No (cached)
Remove [2/2, 3/3] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/3, 1/1] => No
Remove [2/2, 2/3, 1/1] => No
Remove [2/2, 3/3, 1/2] => No
Remove [2/2, 3/3, 2/2] => No
Unwrap [2/2, 3/3, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/4] => No
Remove [1/2, 1/1, 2/2, 2/4] => No
Remove [1/2, 1/1, 2/2, 3/4] => Yes
Remove [1/2, 1/1, 2/2, 3/3] => No
Remove [2/2, 3/3, 1/2, 1/2] => No
Remove [2/2, 3/3, 1/2, 2/2] => No
Unwrap [2/2, 3/3, 1/2, 2/2] => No (cached)
Remove [2/2, 3/3, 2/2, 1/8] => No
Remove [2/2, 3/3, 2/2, 2/8] => No
Remove [2/2, 3/3, 2/2, 3/8] => Yes
Remove [2/2, 3/3, 2/2, 3/7] => Yes
Remove [2/2, 3/3, 2/2, 3/6] => Yes
Remove [2/2, 3/3, 2/2, 3/5] => Yes
Remove [2/2, 3/3, 2/2, 3/4] => Yes
Remove [2/2, 3/3, 2/2, 3/3] => Yes
############### ITERATION 3 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/3] => Yes
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
############### ITERATION 4 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/2] => No (cached)
Remove [2/2, 2/2] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/3] => No
Remove [1/2, 1/1, 2/2, 2/3] => Yes
Remove [1/2, 1/1, 2/2, 2/2] => Yes
Remove [2/2, 2/2, 1/2, 1/2] => No
Remove [2/2, 2/2, 1/2, 2/2] => No
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2] => No
############### ITERATION 5 ################
============= Depth 0 =============
Remove [1/2] => No (cached)
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No (cached)
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No (cached)
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/1] => No
Remove [2/2, 2/2, 1/2, 1/2] => No (cached)
Remove [2/2, 2/2, 1/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2] => No (cached)
============= Depth 4 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1] => No
Remove [2/2, 2/2, 2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1] => No
============= Depth 5 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 2/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
Unwrap [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
============= Depth 6 =============
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 1/2] => No
Remove [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 2/2] => No
Unwrap [1/2, 1/1, 2/2, 1/1, 1/1, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2, 1/1] => Yes
############### ITERATION 6 ################
============= Depth 0 =============
Remove [1/2] => No
Remove [2/2] => No (cached)
============= Depth 1 =============
Remove [1/2, 1/1] => No
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No (cached)
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No
Unwrap [1/2, 1/1, 2/2] => No
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [1/2, 1/1, 2/2, 1/1] => Yes
Remove [2/2, 2/2, 1/2, 1/2] => No
Remove [2/2, 2/2, 1/2, 2/2] => No
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2] => No
############### ITERATION 7 ################
============= Depth 0 =============
Remove [1/2] => No (cached)
Remove [2/2] => No
============= Depth 1 =============
Remove [1/2, 1/1] => No (cached)
Remove [2/2, 1/2] => No
Remove [2/2, 2/2] => No
============= Depth 2 =============
Remove [1/2, 1/1, 1/2] => No
Remove [1/2, 1/1, 2/2] => No (cached)
Unwrap [1/2, 1/1, 2/2] => No (cached)
Remove [2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 1/2] => No
Remove [2/2, 2/2, 2/2] => No
Unwrap [2/2, 2/2, 2/2] => No
============= Depth 3 =============
Remove [2/2, 2/2, 1/2, 1/2] => No (cached)
Remove [2/2, 2/2, 1/2, 2/2] => No (cached)
Unwrap [2/2, 2/2, 1/2, 2/2] => No (cached)
Remove [2/2, 2/2, 2/2, 1/2] => No (cached)
Remove [2/2, 2/2, 2/2, 2/2] => No (cached)
============= Depth 4 =============
Remove [2/2, 2/2, 2/2, 1/2, 1/1] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1] => No
============= Depth 5 =============
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 1/2] => No
Remove [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No
Unwrap [2/2, 2/2, 2/2, 2/2, 1/1, 2/2] => No (cached)
============= Depth 6 =============
Done in 7 secs and 18 ms; reduced version is in workdir.reduced

Le résultat du code minimaliste provoquant l'erreur est dans le dossier workdir.reduced


  1. $ ls workdir.reduced
  2. app.d util.d

Contenu des fichiers:


  1. import util;
  2.  
  3. void main( ){
  4. A* a = null;
  5. *a = A( );
  6. }

app.d


  1. struct A{
  2. }

util.d

dustmite nous montre que le segfault provient de l'utilisation d'un pointeur nulle. Le code ici est écrit à la façon C (avec des pointeurs) pour provoquer un segfault. La plupart du temps en D vous n'avez pas besoin des pointeurs mais utiliserez les références (simple et transparent). En effet, le code présenté se veut pédagogique pour l'utilisation de dustmite ;-) .