[FAQ] Nouvelle section ou sous-section sur le débogage sous Perl et sur le debugger Perl
Bonjour,
je voulais ajouter une question/réponse sur une utilisation un peu avancée du debugger Perl, mais je m'aperçois que, sauf erreur, il n'y a pas de section de la FAQ consacrée à ce sujet (en tous cas, je ne l'ai pas trouvée). Je propose donc de créer une nouvelle section ou sous-section consacrée non pas au debugger Perl, mais plus généralement au débogage sous Perl (car il y a d'autres techniques que le débugger pour "déverminer" un programme). Je me ferai ensuite un plaisir de rédiger éventuellement quelques questions de base sur ce sujet.
Je pense que ce serait utile pour pouvoir renvoyer vers la FAQ les utilisateurs qui posent des questions de ce genre: "Je ne comprends pas, mon programme tourne, mais n'affiche pas les résultats que j'attends. Que se passe-t-il?".
Qu'en penses-tu, Djibril?
[FAQ] Comment arrêter le debugger Perl sur un warning du genre "Use of uninitialized value ..."
On a parfois beaucoup de difficulté à résoudre un warning "Use of uninitialized value ...". Perl indique la ligne de code concernée et éventuellement la ligne du fichier lu où cela arrive, mais cela ne suffit souvent pas, en particulier quand cet avertissement est émis pour seulement quelques éléments d'une longue liste ou quelque rares fois dans une grosse boucle while ou foreach. Même sous le debugger, il n'est pas possible d'exécuter pas à pas une boucle contenant plusieurs milliers, voire plusieurs millions, d'itérations.
Une astuce permet de demander au debugger de s'arrêter sur l'émission d'un warning de ce type (ou autre, d'ailleurs).
Considérons le programme suivant:
Code:
1 2 3 4 5 6 7 8 9 10 11
| use strict;
use warnings;
my @array = 0..5;
$array[$_] = $_ for 7..10;
foreach (@array) {
my $count = $_ + 5;
print $count, "\n";
}
print "end\n"; |
Avant d'entrer dans la boucle foreach, le tableau @array a le contenu suivant:
Code:
1 2 3 4 5 6 7 8 9 10 11 12
| DB<2> x @array
0 0
1 1
2 2
3 3
4 4
5 5
6 undef
7 7
8 8
9 9
10 10 |
On voit que le septième élément du tableau (indice 6) n'est pas défini.
A l'exécution, cela donne le warning suivant et une valeur probablement fausse:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| $ perl test_debug_warn.pl
5
6
7
8
9
10
Use of uninitialized value $_ in addition (+) at test_debug_warn.pl line 11.
5
12
13
14
15
end |
L'utilisation de debugger n'aide pas:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| $ perl -d test_debug_warn.pl
Loading DB routines from perl5db.pl version 1.33
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(test_debug_warn.pl:6): my @array = 0..5;
DB<1> c
5
6
7
8
9
10
Use of uninitialized value $_ in addition (+) at test_debug_warn.pl line 11.
at test_debug_warn.pl line 11
5
12
13
14
15
end
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info. |
Avec une boucle de 11 itérations, on peut certes aller pas à pas jusqu'à la ligne posant problème afin d'examiner le contexte et l'état des variables au moment de l'émission du warning, mais ce n'est plus possible pour une boucle contenant un grand nombre d'itérations. C'est là que l'on voudrait demander au debugger de s'arrêter au moment du warning.
Il suffit pour cela de configurer le debugger pour qu'il s'arrête sur les warnings, en plaçant dans le répertoire courant ou dans le répertoire de l'utilisateur un fichier nommé .perldb (c'est un fichier de configuration du debugger chargé lors du lancemenr du debugger) et contenant le code suivant:
Code:
1 2 3 4 5 6 7 8 9 10 11 12
| sub afterinit
{
$::SIG{'__WARN__'} = sub {
my $warning = shift;
if ( $warning =~ m{\s at \s \S+ \s line \s \d+ \. $}xms ) {
$DB::single = 1; # point d'arrêt, le debugger s'arrête ici
}
warn $warning;
};
print "sigwarn handler installed!\n";
return;
} |
Sans entrer dans le détail, disons que cela ajoute un point d'arrêt à la fonction de warning du debugger.
Maintenant, le debugger s'arrête juste après l'émission du warning, ce qui permet d'examiner le contenu de la variable $_ a ce moment_là:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| $ perl -d test_debug_warn.pl
Loading DB routines from perl5db.pl version 1.33
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
sigwarn handler installed!
main::(test_debug_warn.pl:6): my @array = 0..5;
DB<1> c
5
6
7
8
9
10
Use of uninitialized value $_ in addition (+) at test_debug_warn.pl line 11.
main::(test_debug_warn.pl:12): print $count, "\n";
DB<1> x $_
0 undef |