GDB cadre de stack corrompu – Comment déboguer?

J’ai la trace de stack suivante. Est-il possible de faire quelque chose d’utile pour le débogage?

Program received signal SIGSEGV, Segmentation fault. 0x00000002 in ?? () (gdb) bt #0 0x00000002 in ?? () #1 0x00000001 in ?? () #2 0xbffff284 in ?? () Backtrace stopped: previous frame inner to this frame (corrupt stack?) (gdb) 

Où commencer à regarder le code lorsque nous obtenons une Segmentation fault et que la trace de la stack n’est pas si utile?

NOTE: Si je publie le code, les experts SO vont me donner la réponse. Je veux prendre les directives de SO et trouver la réponse moi-même, donc je ne poste pas le code ici. Excuses

Ces fausses adresses (0x00000002 et similaires) sont en réalité des valeurs PC, pas des valeurs SP. Maintenant, quand vous obtenez ce type de SEGV, avec une adresse de faux (très petit) PC, 99% du temps est dû à un appel via un pointeur de fonction bidon. Notez que les appels virtuels en C ++ sont implémentés via des pointeurs de fonction, donc tout problème avec un appel virtuel peut se manifester de la même manière.

Une instruction d’appel indirect pousse simplement le PC après l’appel sur la stack, puis règle le PC à la valeur cible (fausse dans ce cas), donc si c’est ce qui s’est passé, vous pouvez facilement l’annuler en éteignant manuellement le PC . Dans le code x86 32 bits que vous venez de faire:

 (gdb) set $pc = *(void **)$esp (gdb) set $esp = $esp + 4 

Avec le code x86 64 bits dont vous avez besoin

 (gdb) set $pc = *(void **)$rsp (gdb) set $rsp = $rsp + 8 

Ensuite, vous devriez être capable de faire un bt et de déterminer où est réellement le code.

L’autre 1% du temps, l’erreur sera due à l’écrasement de la stack, généralement en débordant un tableau stocké dans la stack. Dans ce cas, vous pouvez obtenir plus de clarté sur la situation en utilisant un outil comme valgrind

Si la situation est assez simple, la réponse de Chris Dodd est la meilleure. On dirait qu’il a sauté à travers un pointeur NULL.

Toutefois, il est possible que le programme se soit propulsé dans le pied, le genou, le cou et les yeux avant de s’écraser: il a écrasé la stack, endommagé le pointeur du cadre et d’autres maux. Si tel est le cas, il est peu probable que le démêlage du hachage vous montre les pommes de terre et la viande.

La solution la plus efficace consistera à exécuter le programme sous le débogueur et à survoler les fonctions jusqu’à ce que le programme se bloque. Une fois qu’une fonction défaillante est identifiée, redémarrez-la et entrez dans cette fonction et déterminez la fonction qui appelle le blocage. Répétez l’opération jusqu’à ce que vous trouviez la seule ligne de code incriminée. 75% du temps, le correctif sera alors évident.

Dans l’autre 25% des situations, la ligne de code dite offensante est un hareng rouge. Il réagira à des conditions (non valides) configurant plusieurs lignes auparavant – peut-être des milliers de lignes auparavant. Si tel est le cas, le meilleur cours choisi dépend de nombreux facteurs: principalement votre compréhension du code et votre expérience:

  • L ‘installation d’ un sharepoint contrôle du débogueur ou l ‘insertion de documents d’ impression de diagnostic sur des variables critiques permettra peut – être d ‘obtenir le résultat A ha nécessaire !
  • La modification des conditions de test avec différentes entrées apportera peut-être plus de détails que le débogage.
  • Peut-être qu’une deuxième paire d’yeux vous obligera à vérifier vos hypothèses ou à rassembler des preuves ignorées.
  • Parfois, il suffit de dîner et de réfléchir aux preuves rassemblées.

Bonne chance!

En supposant que le pointeur de stack est valide …

Il peut être impossible de savoir exactement où se trouve le SEGV à partir de la trace. Je pense que les deux premières images de la stack sont complètement écrasées. 0xbffff284 semble être une adresse valide, mais les deux suivantes ne le sont pas. Pour un examen plus approfondi de la stack, vous pouvez essayer les éléments suivants:

gdb $ x / 32ga $ rsp

ou une variante (remplace le 32 par un autre numéro). Cela imprimera un certain nombre de mots (32) à partir du pointeur de stack de taille géante (g), formaté en adresses (a). Tapez “help x” pour plus d’informations sur le format.

L’instrumentation de votre code avec certains ‘printf’ sentinelles n’est peut-être pas une mauvaise idée, dans ce cas.

Regardez certains de vos autres registres pour voir si l’un d’eux a le pointeur de la stack en mémoire. De là, vous pourrez peut-être récupérer une stack. De plus, si cela est incorporé, la stack est souvent définie à une adresse très particulière. En utilisant cela, vous pouvez aussi parfois obtenir une stack décente. Tout cela suppose que lorsque vous avez sauté sur l’hyperespace, votre programme n’a pas bougé de mémoire en cours de route …

Si c’est un remplacement de stack, les valeurs peuvent bien correspondre à quelque chose reconnaissable du programme.

Par exemple, je me suis retrouvé à regarder la stack

 (gdb) bt #0 0x0000000000000000 in ?? () #1 0x000000000000342d in ?? () #2 0x0000000000000000 in ?? () 

et 0x342d est 13357, ce qui s’est avéré être un identifiant de nœud lorsque j’écorché les journaux d’application. Cela a immédiatement aidé à réduire le nombre de sites candidats susceptibles d’être écrasés.