Forum Programmation.c bug gcc ? ou je n'y comprend plus rien ...

Posté par  (site web personnel) .
Étiquettes : aucune
0
2
sept.
2006
Bonsoir,

J'ai un drôle de truc qui m'arrive dans mon projet ... Lorsque j'utilise un débuger pour voir ce qui se passe, lorsque l'instruction return NULL; est exécutée à la fin d'une fonction, j'ai un NULL qui vient se mettre quelque part dans ma structure de donnée. Je n'y comprend rien.
J'ai bien vérifié, du coté où on appelle la fonction, le résultat arrive dans une variable toute neuve, je n'y comprend rien.

je me demande si ce ne serait pas un bug de GCC ... mais cela ne semble pas être le cas car que ce soit avec GCC-4.0 ou GCC-3.4 la même chose se produit.

-----

Mon projet (que j'appelle moon pour le moment, pas très original, je sais) consiste à créer un langage de programmation dans le style lisp/scheme mais pas exactement pareil (sinon, je prendrait ce qui existe). Pour cela, j'utilise le garbage collector Hans Boehm [2] mais je ne pense pas que le problème vienne de là.

Ce qui se passe, c'est que lors de l'exécution, j'ai une pile d'objets qui permet notament à un objet enfant de parcourir tous ses parents à la recherche de la définition d'une variable. Ainsi, certains objets sont dotés d'un environnement, c'est à dire globalement un pointeur void* et un pointeur sur une fonction qui doit permettre de dire si la variable recherchée est définie dans cet environement.

Je ne sais vraiment pas quoi faire, je ne vois pas bien quelle pourrait être la cause de tout ça. Et surtout je ne vous pas comment l'instruction return pour modifier des données dans le tas, de plus, logiquement, la valeur de retour ne passe que dans des registres [3] (du moins sur une architecture x86).

Si quelqu'un veut voir ma source, c'est par là [1] ou par là [4] (bazaar-ng). Pour compiler, il faut cmake [5] et le bon garbage collector [2]. Ensuite il suffit de lancer la commande cmake . pour configurer la sources puis make pour construire l'exécutable.
Il suffit de lancer la commande ./moon test.moon pour que l'erreur se produise. Le fichier .kdbgrc.moon contient ce qu'il faut pour lancer kdbg.

Pour bien la voir, il faut lancer un débuger et metre un point d'arrêt dans la fonction moon_environment_resolve dans moonlib/environment.c [6]. les deux premières fois que le programme est arrêté, relancer l'exécution, c'est à la 3e fois qu'on peut continuer en pas à pas et voir que l'instruction return NULL met NULL dans parents->stack.
Pour info, la fonction appelante, est moon_resolve dans le fichier moonlib/core-inline.h [7]

je ne vous demande pas de réparer complètement mon code, mais juste de m'aider à voir où il pourrait y avoir un truc qui cloche ... car je ne vois pas du tout :(
Merci de toute aide

Mildred

--

[1] http://bzr.mildred632.free.fr/viewsource/Projects/moon-c-gc
[2] http://www.hpl.hp.com/personal/Hans_Boehm/gc/
[3] http://en.wikipedia.org/wiki/Calling_convention
[4] http://bzr.mildred632.free.fr/Projects/moon-c-gc/moon-src.ta(...)
[5] http://cmake.org
[6] http://bzr.mildred632.free.fr/viewsource/Projects/moon-c-gc/(...)
[7] http://bzr.mildred632.free.fr/viewsource/Projects/moon-c-gc/(...)
  • # bizarre

    Posté par  . Évalué à 5.

    en parcourant très rapidement les sources, ya parfois des choses bizarres, genre:
    moon-c-gc/common/strbuf.c:buffer_to_string_delete
    (...)
    Free(B);
    Free(B->data);
    (...)

    c'est normal ou pas?
    parce que ton pb, je trouve que ça sent fort la corruption de heap, quand même.
    • [^] # Re: bizarre

      Posté par  (site web personnel) . Évalué à 2.

      Non, ce n'est pas normal, merci de cette remarque. Cependant, cela ne change malhereusement rien au problème (sans doute car j'utilise un garbage collector).

      Je pense bien que l'erreur doit se trouver ailleurs, invisible, mais comment savoir où ? J'ai essayé la compilation avec Electric Fence alors normalement, tout débordement devrait être détecté ...
      • [^] # Re: bizarre

        Posté par  . Évalué à 3.

        Tu peux aussi essayer avec valgrind.
        Comme le post précédent le dit, c'est une corruption de mémoire.

        http://valgrind.org/
      • [^] # Re: bizarre

        Posté par  . Évalué à 3.

        Peut-être dans moon_find_envS(), la variable S2=&stack est allouée sur la pile,
        et son adresse est retournée comme résultat en fin de fonction, mais cet espace mémoire doit être réutilisé après par d'autre fonctions.

        Tu peux enlever la variable stack et remplacer le memcpy par un moonS_copy.

        Mais ....
        ... dans moon_resolve, la variable parents est un pointeur vers une
        zone mémoire allouée par un malloc et un peu plus loin, cette adresse est écrasée par : parents = moon_find_envS(parents);
        donc tu ne peux plus libérer cette zone.
        • [^] # Re: bizarre

          Posté par  (site web personnel) . Évalué à 2.

          Merci beaucoup, encore une erreur, mon code ne doit pas être très propre lorsqu'on voit ça ... Auparavant, j'utilisais un Malloc mais comme je devais différencier le cas où la valeur de retour était NULL car le malloc avait échoué et le cas ou c'est parce qu'aucun environnement n'avait été trouvé.

          Merci beaucoup pour cette aide

          dans moon_resolve, la variable parents est un pointeur vers une zone mémoire allouée par un malloc et un peu plus loin, cette adresse est écrasée par : parents = moon_find_envS(parents);
          donc tu ne peux plus libérer cette zone.

          Ce n'est pas gênant, c'est le garbage collector qui s'en charge :)

          En cherchant sur google "heap corruption", j'ai trouvé mpatrol ... et lorsque je l'ai utilisé, il m'a dit
          ERROR: [ILLMEM]: illegal memory access at address 0x00000005
          0x00000005 not in heap

          De plus, maintenant, electric fence me fait un joli segfault, je vais pouvoir débuger comme avant.

          merci beaucoup
      • [^] # Re: bizarre

        Posté par  . Évalué à 2.

        Je pense bien que l'erreur doit se trouver ailleurs, invisible, mais comment savoir où ?

        Depuis un an, je développe beaucoup en C sur un projet, et pour beaucoup d'erreur, le code fautif était très loin de l'endroit où se manifestait le plantage. Tout simplement parce que l'erreur, par exemple un dépassement de tampon, écrasait des données qui n'étaient utilisée que plus loin.

        Maintenant, comment savoir où ... Utiliser Electric Fence était une bonne idée, mais ne résoud pas tout. Valgrind, mentionné par quelqu'un d'autre peut aider.

        Sinon, reste à étudier le code, ajouter des informations de débugage, en affichant par exemple le contenu d'un tas de structures. Pour mes développements, sur lequels je suis plus ou moins une logique objet, j'ai pour chacune de mes structures de données une fonction qui en affiche le contenu, avec les adresses des pointeurs. Afficher ces infos avant et après des appels de fonctions peut permettre de contrôler quels pointeurs/contenus ont été modifiés.
        • [^] # Re: bizarre

          Posté par  (site web personnel) . Évalué à 4.

          Je pense que la vrai solution est d'avoir une méthodologie de programmation assez rigoureuse : abuser des assert(3), bien vérifier toutes les valeurs de retour, compiler avec -W -Wall -pedantic, vérifier régulièrement que rien ne cloche avec Electric Fence, Valgrind et d'autres compilateurs (celui d'Intel donne beaucoup plus de warnings que GCC par exemple, il est pas libre mais il est disponible gratuitement sous certaines conditions), définir un coding style et s'y tenir,...

          Programmer proprement quoi. Une fois qu'on fait ça, retrouver un bug devient généralement bien plus facile pour la simple raison qu'on le trouve plus tôt dans le développement.

          Voir aussi le guide superflu de programmation en langage C :
          http://docs.happycoders.org/orgadoc/dev/C/c-superflu.pdf

          Pour ce qui est de l'affiche des structures des données, c'est plutôt du ressort du debugger (ddd marche bien pour ça) même s'il est vrai que dans certains cas ça reste plus pratique d'avoir une fonction d'affichage à côté.
          À ce sujet j'ai commencé un vague argumentaire à l'encontre du "printf()-debugging". Faudra que je pense à en faire un vrai texte un jour.
          http://www.krunch.be/vrac/txt/printf-debugging-harmful

          pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

          • [^] # Re: bizarre

            Posté par  (site web personnel) . Évalué à 2.

            Merci pour la doc, ca va m'intéresser.

            Pour le printf debugging, je ne vois pas trop ce qu'il y a de mal à ça, si on s'y prend bien. Ce n'est pas la solution ultime mais ca peut aider à voir où est le problème.
            Et c'est comme ça que je fesait au début (avant de découvrir kdbg puis ddd), et c'est comme ça que je fais toujours avec des langages comme php.

            Tu pourrais peut être en faire un journal pour expliquer ton point de vue à fond ... ça m'intéresserait.

            Mildred
  • # Merci à tous

    Posté par  (site web personnel) . Évalué à 2.

    Tout fonctionne correctement maintenant, un très grand merci à tous !!!

    Je pense que le problème venait de la fonction moon_find_envS() qui retournait un objet alloué sur la pile ... forcément, ca ne peux pas marcher.

    Encore merci.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.