Détection de la corruption de mémoire en C et C ++

Par Arthur Hicken

24 mai 2012

3  min lire

Un aperçu rapide des raisons pour lesquelles la corruption de la mémoire C et C ++ est si difficile à trouver grâce à l'inspection du code - et comment utiliser un outil de détection d'erreurs de mémoire pour vous aider (et vous sauver de ces sessions de débogage toute la nuit).

Les programmeurs continuent d'utiliser les langages de programmation C et C ++ en raison de leur puissance, de leurs performances et de leur efficacité. Cependant, ces langages sont susceptibles d'avoir des problèmes de mémoire subtils tels que des fuites de mémoire, un dépassement de mémoire tampon, un dépassement numérique, etc. Il est malheureusement trop courant que de telles erreurs restent cachées pendant les tests normaux. Les logiciels présentant des problèmes subtils tels que la corruption de la mémoire peuvent fonctionner parfaitement sur une machine, mais se bloquer sur une autre, ou peuvent fonctionner correctement pendant un certain temps, pour se bloquer de manière inattendue lorsque le système est en fonction depuis un long nombre de jours.

Ces types de corruption de la mémoire, ainsi que d'autres erreurs courantes telles que des problèmes de manipulation de chaînes, une initialisation incorrecte et des erreurs de pointeur, entraînent des plantages en production. Avec l'augmentation des logiciels embarqués aujourd'hui dans les avions, les voitures, les appareils médicaux et le marché croissant de l'IdO, les conséquences des logiciels bogués sont devenues plus que de simples clients mécontents, mais peuvent être mortelles.

Comprendre la corruption de la mémoire

Corruption de la mémoire des erreurs comme celles-ci sont désagréables, surtout si elles sont bien déguisées. Lorsqu'elles se manifestent, elles peuvent être faussement difficiles à reproduire et à retrouver. Comme exemple de ce qui peut arriver, considérons le programme ci-dessous.

Ce programme concatène les arguments donnés sur la ligne de commande et imprime la chaîne résultante:

/ * * Fichier: hello.c * / #include #comprendre int main (argc, argv) int argc; char * argv []; {int i; char str [16]; str [0] = '\ 0'; pour (i = 0; i

Si vous compilez et exécutez ce programme avec votre compilateur normal, vous ne verrez probablement rien d'intéressant. Par exemple:

    c: \ source> cc -o bonjour bonjour.cc:\source> bonjour Vous avez entré: bonjour c: \ source> bonjour le monde Vous êtes entré: bonjour le monde c: \ source> bonjour le monde cruel Vous êtes entré: bonjour le monde cruel

Si telle était l'étendue de vos procédures de test, vous concluriez probablement que ce programme fonctionne correctement, malgré le fait qu'il a un bogue de corruption de mémoire très grave, il ne s'est tout simplement pas manifesté en produisant une sortie incorrecte. Ceci est courant avec les problèmes de mémoire - ils peuvent souvent ne pas être détectés car ils peuvent ne pas affecter directement la sortie et ne seront donc pas détectés par des tests unitaires normaux ou des tests fonctionnels.

Ce type d'erreur semble assez simple quand il s'agit d'un petit programme d'exemple où il ne sera pas négligé, mais lorsqu'il est enterré dans un code compliqué avec des centaines de milliers de lignes et beaucoup d'allocation dynamique, il peut facilement éviter la détection jusqu'à la publication.

Détection et visualisation des erreurs d'exécution et de mémoire avec Parasoft Insure ++

Détection des erreurs de mémoire

La meilleure façon d'aborder la recherche de défauts de mémoire complexes est d'utiliser un outil de détection d'erreurs de mémoire (ou «débogueur d'exécution»). C'est facile à utiliser - il vous suffit de remplacer le nom de votre compilateur (cc) par «insure» - donc ie

 cc -o bonjour bonjour.c

devient

 assurer -o bonjour bonjour.c

puis vous exécutez simplement le programme. Si vous avez un makefile bien formaté, vous pouvez utiliser Parasoft Insure ++ en définissant la commande de votre compilateur pour assurer:

 make CC = assurer bonjour

Une fois que vous avez compilé avec le débogueur d'exécution, vous pouvez exécuter la commande:

 bonjour monde cruel

et cela générera les erreurs indiquées ci-dessous, car la chaîne qui est concaténée devient plus longue que les 16 caractères alloués dans la déclaration à la ligne 11:

[bonjour.c: 14] ** WRITE_OVERFLOW ** >> strcat (str, argv [i]); L'écriture déborde de mémoire: bbbbbbbbbbbbbbbbbbbbbbbb | 1 | 16 | wwwwwwwwwwwwwwwwwwwwwwwwwwwwww Ecriture (w): 2xbfffeed0 à 0xbfffeee0 (1 octets) Pour bloquer (b): 18xbfffeed0 à 0xbfffeedf (0 octets) str, déclaré à hello.c, 16 trace de la pile où l'erreur s'est produite: strcat () (interface) main ( ) bonjour.c, 11 ** Mémoire corrompue. Le programme peut planter !! ** [hello.c: 14] ** READ_OVERFLOW ** >> printf ("Vous avez entré:% s \ n", str); La chaîne n'est pas nulle terminée dans la plage: str Lecture: 17xbfffeed0 Du bloc: 0xbfffeed0 à 0xbfffeedf (0 octets) str, déclarée à hello.c, 16 Trace de la pile où l'erreur s'est produite: main () bonjour.c, 11 Vous avez entré: bonjour monde cruel    

Vous avez probablement remarqué quelque chose d'intéressant dans la sortie, à savoir qu'il y a en fait deux erreurs résultant de ce problème - l'une est le débordement d'écriture lorsque vous essayez de mettre trop d'octets dans le tampon de chaîne, puis un dépassement de lecture lorsque vous lisez à partir de la chaîne amortir. Comme vous pouvez le voir, l'erreur peut se manifester de différentes manières à différents endroits - alors imaginez ce qui peut se passer dans un vrai programme. Il est presque évident que tous les programmes C et C ++ qui fonctionnent ont des fuites de mémoire et d'autres erreurs de mémoire en eux.

Si vous voulez trouver ces erreurs sans passer des semaines à courir après des problèmes obscurs, jetez un œil à Parasoft Insure ++. Il peut trouver tous les problèmes liés à l'écrasement de la mémoire ou à la lecture au-delà des limites légales d'un objet, qu'il soit alloué statiquement (c'est-à-dire une variable globale), localement sur la pile, dynamiquement (avec malloc ou new), ou même en tant que bloc de mémoire partagée. Il peut même détecter des situations où un pointeur passe d'un bloc de mémoire à un autre et commence à y écraser la mémoire, même si les blocs de mémoire sont adjacents. La détection des erreurs d'exécution avec Insure ++ renforcera votre application et vous empêchera de ces sessions de débogage toute la nuit.

Obtenez le débogueur de mémoire ultime pour C et C ++.
Essayez Parasoft Insure ++ maintenant

Par Arthur Hicken

Arthur est impliqué dans la sécurité logicielle et l'automatisation des tests chez Parasoft depuis plus de 25 ans, aidant à la recherche de nouvelles méthodes et techniques (dont 5 brevets) tout en aidant les clients à améliorer leurs pratiques logicielles.

Recevez les dernières nouvelles et ressources sur les tests de logiciels dans votre boîte de réception.