dustmite un outil qui vous fait gagner du temps
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
-
$ ulimit -c unlimited
Dans un premier temps il faut autoriser la création de fichier core lorsqu'un programme segfault
Espace de travail
-
$ mkdir workdir
Ensuite on créer un répertoire dans le quel dustmite travaillera
Très originale comme nom de dossier
Sources
Ensuite on va mettre les fichiers app.d et utild.d dans le dossier workdir. C'est le programme qui va planter
-
import std.string;
-
import std.stdio;
-
-
import util;
-
-
void main( ){
-
A* a = null;
-
*a = A( [2uL, 3uL, 4uL] );
-
(*a).append( 5u );
-
writeln( (*a).length );
-
if( (*a).length > 3 )
-
a = null;
-
writeln( (*a).length );
-
(*a).append( 0u );
-
writeln( (*a).length );
-
}
app.d
-
module util;
-
-
struct A{
-
size_t[] items;
-
size_t length;
-
-
this( size_t[] items ){
-
this.items = items;
-
this.length = items.length;
-
}
-
-
void append( size_t item ){
-
this.items ~= item;
-
}
-
}
utild.d
Compilation
-
$ (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
-
$ (cd workdir && ./app )
Éxécutons le programme, il va générer un fichier core:
DustMite
-
$ 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:
- spécifier a dustmite le dossier de travail
- il faut donner la commande de construction a dustmite =>
ldc2 app.d util.d -ofapp
- lui dire comment lancer l'appilcation =>
./app
- ne pas oublier les parenthèses ()
- fusionner la sortie d'erreur sur la sortie standard =>2>&1
- 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
-
$ ls workdir.reduced
-
app.d util.d
Contenu des fichiers:
-
import util;
-
-
void main( ){
-
A* a = null;
-
*a = A( );
-
}
app.d
-
struct A{
-
}
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 .