Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème bizarre

21 réponses
Avatar
JKB
Bonjour à tous,

Je sèche depuis ce matin sur un problème bizarre. Ça doit être
complètement trivial, mais je ne comprend pas. Considérons le code
suivant qui provient d'un analyseur syntaxique que j'ai écrit :

/*
* Test de la présence de l'instruction EXIT dans une boucle
*/

l_element_pile_systeme = (*s_etat_processus).l_base_pile_systeme;
presence_boucle = d_faux;
drapeau_boucle_definie = d_faux;

while((l_element_pile_systeme != NULL) &&
(printf(">%d\n", presence_boucle), presence_boucle == d_faux))
{
printf("Boucle %d\n", presence_boucle);
if ((strcmp((*l_element_pile_systeme).type_cloture, "START") == 0) ||
(strcmp((*l_element_pile_systeme).type_cloture, "FOR") == 0))
{
printf("Là\n");
presence_boucle = d_vrai;
drapeau_boucle_definie = d_vrai;
}
else if ((strcmp((*l_element_pile_systeme).type_cloture, "DO") == 0) ||
(strcmp((*l_element_pile_systeme).type_cloture, "WHILE") == 0))
{
printf("Ici\n");
presence_boucle = d_vrai;
drapeau_boucle_definie = d_faux;
}

printf("<%s> %d\n", (*l_element_pile_systeme).type_cloture, presence_boucle);
l_element_pile_systeme = (*l_element_pile_systeme).suivant;
printf("<> %d\n", presence_boucle);
}

printf("Paf\n");

l_element_pile_systeme est un pointeur sur une structure de liste
chaînée qui contient au moins un champ 'suivant' et un champ statique
(char[6]) type_cloture. Je veux simplement que si la variable
entière presence_boucle devient vrai et qu'on n'est pas encore à la fin
de la liste chaîne, on sorte de la boucle.

Ce code _fonctionnait_. Il est actuellement compilé avec gcc-4.4 -O3
(mais je viens de tester -03 et gcc-4.3). Je ne sais plus avec quelle
configuration ça fonctionnait et je ne vois pas ce que j'aurais changé
depuis...

À l'exécution, ça donne :

>0
Boucle 0
<IF> 0
<> 0
>0
Boucle 0
Ici
<WHILE> 255
<> 255
>255
>0 <-- Je ne comprends pas ÇA...
Boucle 0
<> 0
<> 0
>0
Boucle 0
<> 0
<> 0
Paf

Si quelqu'un avait une idée... Parce que je sèche sur un bout de
code carrément simple et j'ai _honte_...

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.

10 réponses

1 2 3
Avatar
JKB
Le 16-10-2009, ? propos de
Problème bizarre,

Encore plus incompréhensible :

while((l_element_pile_systeme != NULL) && (presence_boucle == d_faux))
{
printf("Boucle %dn", presence_boucle);
if ((strcmp((*l_element_pile_systeme).type_cloture, "START") == 0) ||
(strcmp((*l_element_pile_systeme).type_cloture, "FOR") == 0))
{
printf("Làn");
presence_boucle = d_vrai;
drapeau_boucle_definie = d_vrai;
}
else if ((strcmp((*l_element_pile_systeme).type_cloture, "DO") == 0) ||
(strcmp((*l_element_pile_systeme).type_cloture, "WHILE") == 0))
{
printf("Icin");
presence_boucle = d_vrai;
drapeau_boucle_definie = d_faux;
}

if (presence_boucle != d_faux) { printf("toton"); break; }
printf("<%s> %dn", (*l_element_pile_systeme).type_cloture, presence_boucle);
l_element_pile_systeme = (*l_element_pile_systeme).suivant;
printf("<> %dn", presence_boucle);
}

donne :

Boucle 0
<IF> 0
<> 0
Boucle 0
Ici
toto <--------- break
Boucle 0
<> 0
<> 0
Boucle 0
<> 0
<> 0
Paf

Question : j'ai rajouté un break qui est exécuté. Pourquoi est-ce
que le truc retourne au while() en _modifiant_ la valeur de la variable
presence_boucle ?

Merci de vos lumières,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
JKB
Le 16-10-2009, ? propos de
Re: Problème bizarre,
JKB ?crivait dans fr.comp.lang.c :
Le 16-10-2009, ? propos de
Problème bizarre,

Encore plus incompréhensible :



En exécutant le code précédent en pas à pas sous gdb, ça marche ! Je
ne comprends plus du tout...

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
zwim
Le Fri, 16 Oct 2009 13:06:01 +0000 (UTC)
JKB a écrit
Le 16-10-2009, ? propos de
Re: Problème bizarre,
JKB ?crivait dans fr.comp.lang.c :
Le 16-10-2009, ? propos de
Problème bizarre,

Encore plus incompréhensible :



En exécutant le code précédent en pas à pas sous gdb, ça marche ! Je
ne comprends plus du tout...

JKB



Au contraire ce fait est très intéressant, maintenant on sait que le
pb ce situe au niveau de la structure de données.

Ce qui peut arriver c'est un débordement qui ne seproduit pas en
debug, ou alors un pb d'alignement dans le struct (par exemple un flag
à l'intérieur même de la structure, compilé différemment entre release
et debug).

Ca donne au moins des directions dans lesquelles regarder.


--
zwim.
Rien n'est impossible que la mesure de la volonté humaine...
Avatar
JKB
Le 16-10-2009, ? propos de
Re: Problème bizarre,
zwim ?crivait dans fr.comp.lang.c :
Le Fri, 16 Oct 2009 13:06:01 +0000 (UTC)
JKB a écrit
Le 16-10-2009, ? propos de
Re: Problème bizarre,
JKB ?crivait dans fr.comp.lang.c :
Le 16-10-2009, ? propos de
Problème bizarre,

Encore plus incompréhensible :



En exécutant le code précédent en pas à pas sous gdb, ça marche ! Je
ne comprends plus du tout...

JKB



Au contraire ce fait est très intéressant, maintenant on sait que le
pb ce situe au niveau de la structure de données.

Ce qui peut arriver c'est un débordement qui ne seproduit pas en
debug, ou alors un pb d'alignement dans le struct (par exemple un flag
à l'intérieur même de la structure, compilé différemment entre release
et debug).

Ca donne au moins des directions dans lesquelles regarder.



C'est compilé exactement de la même manière, avec l'option -g de
gcc...

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
michko
On 16 oct, 13:59, JKB wrote:
        Bonjour à tous,

        Je sèche depuis ce matin sur un problème bizarre. Ç a doit être
        complètement trivial, mais je ne comprend pas. Consid érons le code
        suivant qui provient d'un analyseur syntaxique que j'ai écrit :

    /*
     * Test de la présence de l'instruction EXIT dans une boucle
     */

    l_element_pile_systeme = (*s_etat_processus).l_base_pile_system e;
    presence_boucle = d_faux;
    drapeau_boucle_definie = d_faux;

    while((l_element_pile_systeme != NULL) &&
                        (printf(">%dn", presence _boucle), presence_boucle == d_faux))
    {
printf("Boucle %dn", presence_boucle);
        if ((strcmp((*l_element_pile_systeme).type_cloture, "STAR T") == 0) ||
                (strcmp((*l_element_pile_systeme).type_cl oture, "FOR") == 0))
        {
printf("Làn");
            presence_boucle = d_vrai;
            drapeau_boucle_definie = d_vrai;
        }
        else if ((strcmp((*l_element_pile_systeme).type_cloture, "DO") == 0) ||
                (strcmp((*l_element_pile_systeme).type_cl oture, "WHILE") == 0))
        {
printf("Icin");
            presence_boucle = d_vrai;
            drapeau_boucle_definie = d_faux;
        }

printf("<%s> %dn", (*l_element_pile_systeme).type_cloture, presence_bouc le);
        l_element_pile_systeme = (*l_element_pile_systeme).suiv ant;
printf("<> %dn", presence_boucle);
    }

        printf("Pafn");

        l_element_pile_systeme est un pointeur sur une structure de liste
chaînée qui contient au moins un champ 'suivant' et un champ statique
(char[6]) type_cloture. Je veux simplement que si la variable
entière presence_boucle devient vrai et qu'on n'est pas encore à la f in
de la liste chaîne, on sorte de la boucle.

        Ce code _fonctionnait_. Il est actuellement compilé ave c gcc-4.4 -O3
(mais je viens de tester -03 et gcc-4.3). Je ne sais plus avec quelle
configuration ça fonctionnait et je ne vois pas ce que j'aurais chang é
depuis...

        À l'exécution, ça donne :

>0

Boucle 0
<IF> 0
<> 0>0

Boucle 0
Ici
<WHILE> 255
<> 255>255
>0          <-- Je ne comprends pas ÇA...

Boucle 0
<> 0
<> 0>0

Boucle 0
<> 0
<> 0
Paf

        Si quelqu'un avait une idée... Parce que je sèche sur un bout de
code carrément simple et j'ai _honte_...

        Cordialement,

        JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2 % de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.



Sans doute un pb memoire, plutot que gdb, utilise
un outil comme valgrind, ou bien donne un code
complet. Par ailleurs, ton test sur printf me semble
un peu superflu...

PL
Avatar
JKB
Le 17-10-2009, ? propos de
Re: Problème bizarre,
michko ?crivait dans fr.comp.lang.c :
Sans doute un pb memoire, plutot que gdb, utilise
un outil comme valgrind, ou bien donne un code



J'ai utilisé un valgrind qui n'a _rien_ trouvé. De toute façon, je
ne vois pas comment avoir une corruption mémoire dans ce bout de
code, les seules variables touchées sont les deux drapeaux. Le reste
n'est accédé qu'en lecture et il n'y a aucun thread parallèle qui
pourrait modifier cette variable dans mon dos.

complet. Par ailleurs, ton test sur printf me semble
un peu superflu...



C'est simplement pour voir la valeur du drapeau _avant_ le test.

Le souci, c'est que ça fonctionne parfaitement sous gdb en pas à pas.
Si je l'exécute sous gdb sans passer sur la fonction en question en pas à pas,
le truc plante de la même façon qu'en exécution normale :

(gdb) run -scp recherche_adresse.rpl
Starting program: /usr/local/bin/rpl -scp recherche_adresse.rpl
[Thread debugging using libthread_db enabled]
+++RPL/2 (R) version 4.0.7 (vendredi 16/10/2009, 22:11:12 CEST)
+++Copyright (C) 1989 à 2008, 2009 BERTRAND Joël
2<


Boucle 0
<IF> 0
<> 0
Boucle 0
Ici
<WHILE> 255
<> 255
Boucle 0
<> 0
<> 0
Boucle 0
<> 0
<> 0
Paf
+++Erreur : Instruction 'EXIT' hors d'une boucle [19895]

Program exited with code 01.
(gdb) break instruction_exit
(gdb) run -scp recherche_adresse.rpl
Starting program: /usr/local/bin/rpl -scp recherche_adresse.rpl
[Thread debugging using libthread_db enabled]
+++RPL/2 (R) version 4.0.7 (vendredi 16/10/2009, 22:11:12 CEST)
+++Copyright (C) 1989 à 2008, 2009 BERTRAND Joël

Breakpoint 1, instruction_exit (s_etat_processus=0xab7b10)
at instructions_e2.conv.c:1179
warning: Source file is more recent than executable.
1179 {
(gdb) cont
Continuing.

Breakpoin 1, instruction_exit (s_etat_processus=0xab7b10)
at instructions_e2.conv.c:1179
1179 {
(gdb) cont
Continuing.
2<



Breakpoint 1, instruction_exit (s_etat_processus=0xab7b10)
at instructions_e2.conv.c:1179
1179 {
(gdb) next
1195 (*s_etat_processus).erreur_execution = d_ex;
(gdb) next
1197 if ((*s_etat_processus).affichage_arguments == 'Y')
(gdb) next
1240 else if ((*s_etat_processus).test_instruction == 'Y')
(gdb) next
1250 l_element_pile_systeme (*s_etat_processus).l_base_pile_systeme;
(gdb) next
1254 while((l_element_pile_systeme != NULL) && (presence_boucle
== d_faux))
1257 if ((strcmp((*l_element_pile_systeme).type_cloture,
"START") == 0) ||
(gdb) next
1265 (strcmp((*l_element_pile_systeme).type_cloture,
"WHILE") == 0))
(gdb) next
1256 printf("Boucle %dn", presence_boucle);
1257 if ((strcmp((*l_element_pile_systeme).type_cloture,
"START") == 0) ||
(gdb) next
1256 printf("Boucle %dn", presence_boucle);
(gdb) next
Boucle 0
1257 if ((strcmp((*l_element_pile_systeme).type_cloture,
"START") == 0) ||
1258 (strcmp((*l_element_pile_systeme).type_cloture,
"FOR") == 0))
(gdb) next
1264 else if ((strcmp((*l_element_pile_systeme).type_cloture,
"DO") == 0) ||
(gdb) next
1265 (strcmp((*l_element_pile_systeme).type_cloture,
"WHILE") == 0))
1264 else if ((strcmp((*l_element_pile_systeme).type_cloture,
"DO") == 0) ||
(gdb) next
1272 printf("<%s> %dn", (*l_element_pile_systeme).type_cloture,
presence_boucle);
...
(gdb) next
1265 (strcmp((*l_element_pile_systeme).type_cloture,
"WHILE") == 0))
(gdb) next
1264 else if ((strcmp((*l_element_pile_systeme).type_cloture,
"DO") == 0) ||
(gdb) next
1267 printf("Icin");
(gdb) next
Ici
1272 printf("<%s> %dn", (*l_element_pile_systeme).type_cloture,
presence_boucle);
(gdb) next
<WHILE> 255
1274 printf("<> %dn", presence_boucle);
(gdb) next
<> 255
1284 if ((*s_etat_processus).mode_execution_programme == 'Y')
(gdb)

Je suis sorti normalement de la boucle...

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
zwim
Le Sat, 17 Oct 2009 09:21:52 +0000 (UTC)
JKB a écrit
Breakpoint 1, instruction_exit (s_etat_processus=0xab7b10)
at instructions_e2.conv.c:1179
warning: Source file is more recent than executable.



Ceci n'est pas anodin, je pense...
Ce que tu debuggues et ce que tu executes n'est pas la même chose.
(d'ailleurs le source de ton premier post ne correspond pas à ce qu'on
voie dans la session gdb).

Cela dit il n'y a rien dans ce que tu as posté qui permet de conclure
et je crois pas que l'erreur soit là, tu te focalises trop sur la
partie qui a plante, alors que le problème peut-être très loin
ailleurs.

Je continue à penser qu'il y a un soucis dans tes déclarations, en
particulier l'affectation suivante est-elle correcte, les structures
sont-elles compatibles.
l_element_pile_systeme = (*s_etat_processus).l_base_pile_systeme;

S'il y a un UB quelque part ça peut se manifester de manière étrange
ailleurs, en particulier dans un bout de code censé être parfait.

D'autre part pourquoi ces (*liste).champ, et pas liste ->champ ?
C'est lourd à relire.

Enfin es-tu certain que les strcmp ne débordent pas ?
Un memcpy de type_cloture dans un char[40] par exemple, en début de
boucle permettrait de savoir si le est-bien présent en 6 eme
position.

Si tu veux de l'aide (bien que fclc ne soit pas un forum de debug
collectif...) poste au moins un fichier .c autonome (déclarations +
code qui reproduit le pb).
Si ça se trouve rien qu'en essayant de faire ça, tu trouveras ton pb.


--
zwim.
Rien n'est impossible que la mesure de la volonté humaine...
Avatar
zwim
Le Fri, 16 Oct 2009 11:59:29 +0000 (UTC)
JKB a écrit
while((l_element_pile_systeme != NULL) &&
(printf(">%dn", presence_boucle), presence_boucle == d_faux))



Par ailleurs comme l'a fait remarquer Michko, le printf à l'intérieur
du while est ambigu.

Es-tu sûr que c'est bien presence_boucle == d_faux qui est évalué par
le while et pas la valeur de retour de printf toujours vraie et qui te
conduit à ne jamais sortir de la boucle ?

A-t'on le même résultat avec ça (j'espère parce que sinon, on a
cherché pour rien...) ?

while((l_element_pile_systeme != NULL) &&(presence_boucle == d_faux))



--
zwim.
Rien n'est impossible que la mesure de la volonté humaine...
Avatar
JKB
Le 17-10-2009, ? propos de
Re: Problème bizarre,
zwim ?crivait dans fr.comp.lang.c :
Le Sat, 17 Oct 2009 09:21:52 +0000 (UTC)
JKB a écrit
Breakpoint 1, instruction_exit (s_etat_processus=0xab7b10)
at instructions_e2.conv.c:1179
warning: Source file is more recent than executable.



Ceci n'est pas anodin, je pense...



Si, c'est un problème dans mon makefile (j'ai dû bricoler une
translation de sources à grands coups d'iconv et de touch et ça fait
parfois ça).

Ce que tu debuggues et ce que tu executes n'est pas la même chose.
(d'ailleurs le source de ton premier post ne correspond pas à ce qu'on
voie dans la session gdb).



J'ai fait un tas de modifications entre temps pour essayer de voir
d'où venait le problème.

Cela dit il n'y a rien dans ce que tu as posté qui permet de conclure
et je crois pas que l'erreur soit là, tu te focalises trop sur la
partie qui a plante, alors que le problème peut-être très loin
ailleurs.



Possible. Mais je viens de passer l'après-midi à compulser la sortie
assembleur de gcc sur sparc (je ne connais pas l'assembleur amd64)
et je puis assurer que seule la moitié du premier test est
effectuée (l'autre moitié est faite sur un registre qui est toujours
nul parce qu'initialisé à 0 !). Ce qui est bizarre, c'est que si
j'isole ce bloc et que je le compile _seul_, les deux parties sont dans
le code assembleur et écrite de façon correcte !

Je continue à penser qu'il y a un soucis dans tes déclarations, en
particulier l'affectation suivante est-elle correcte, les structures
sont-elles compatibles.



Oui.

l_element_pile_systeme = (*s_etat_processus).l_base_pile_systeme;

S'il y a un UB quelque part ça peut se manifester de manière étrange
ailleurs, en particulier dans un bout de code censé être parfait.

D'autre part pourquoi ces (*liste).champ, et pas liste ->champ ?
C'est lourd à relire.



Question d'habitude... Je trouve personnellement la notation (*x).y
plus claire que x->y quand les notations deviennent compliquées...

Enfin es-tu certain que les strcmp ne débordent pas ?



Oui. C'est la première des choses que j'ai vérifiées. J'ai même
alloué un temps la mémoire à coups de mmap() et de mprotect() pour
provoquer un segfault en cas de modification à l'insu de mon plein
gré. Rien...

Un memcpy de type_cloture dans un char[40] par exemple, en début de
boucle permettrait de savoir si le est-bien présent en 6 eme
position.



Déjà fait. Il y est bien.

Si tu veux de l'aide (bien que fclc ne soit pas un forum de debug
collectif...) poste au moins un fichier .c autonome (déclarations +
code qui reproduit le pb).
Si ça se trouve rien qu'en essayant de faire ça, tu trouveras ton pb.



J'essaye justement d'obtenir un exemple minimal qui provoque le
problème dans gcc. Je ne suis pas sûr que mon programme soit exempt
de tous bugs, mais je suis au moins sûr qu'il y en a un dans gcc.

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
JKB
Le 17-10-2009, ? propos de
Re: Problème bizarre,
zwim ?crivait dans fr.comp.lang.c :
Le Fri, 16 Oct 2009 11:59:29 +0000 (UTC)
JKB a écrit
while((l_element_pile_systeme != NULL) &&
(printf(">%dn", presence_boucle), presence_boucle == d_faux))



Par ailleurs comme l'a fait remarquer Michko, le printf à l'intérieur
du while est ambigu.

Es-tu sûr que c'est bien presence_boucle == d_faux qui est évalué par
le while et pas la valeur de retour de printf toujours vraie et qui te
conduit à ne jamais sortir de la boucle ?

A-t'on le même résultat avec ça (j'espère parce que sinon, on a
cherché pour rien...) ?

while((l_element_pile_systeme != NULL) &&(presence_boucle == d_faux))





J'ai rajouté un printf() pour voir. Le programme originel n'a aucun
de ces printf().

Pour l'instant, je me dirige vers la rédaction d'un rapport de bug
du compilo et de l'exemple minimal qui va bien... Le truc fonctionne
parfaitement bien avec Sun Studio et des vieux gcc.

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
1 2 3