informatique (MP2I/MPI) · Chapitre 8 · Application directe du cours
Le débordement qui ne plante pas
Mémoire, fichiers et entrées-sorties · niveau 2
Énoncé
Comparer le sort de ces deux programmes.
/* (A) */ int* p = NULL;
*p = 1;
/* (B) */ int voisine = 1000;
int t[5] = {0, 0, 0, 0, 0};
for (int i = 0; i < 8; i = i + 1) { t[i] = i; }
printf("voisine = %d\n", voisine);Corrigé
(A) est tué par le système : code de sortie , soit le signal , SIGSEGV. L'adresse n'appartient à aucune plage du processus, le matériel intercepte, le système tue. Rien n'a été corrompu.
(B) compilé avec -fno-stack-protector affiche :
voisine = 6
t = 0 1 2 3 4
et se termine avec le code . Les tours ont écrit hors du tableau, dans une mémoire qui appartient bel et bien au processus : celle de voisine. La variable a changé de valeur sans qu'aucune ligne du programme ne la nomme. Le tableau, lui, est intact — le programme peut donc être faux ailleurs qu'à l'endroit de la faute.
Le classement est contre-intuitif, et c'est le point de l'exercice :
| Ce qui arrive | Gravité | |
|---|---|---|
| (A) hors du processus | mort immédiate, signal 11 | le bon cas |
| (B) hors tableau, dans le processus | une autre variable change | le mauvais |
Une nuance mesurée. Compilé sans -fno-stack-protector, c'est-à-dire par défaut sur la plupart des systèmes actuels, le même programme (B) se termine par le code , SIGABRT : le compilateur avait glissé une valeur témoin — un canari — entre les variables locales et l'adresse de retour, et il a constaté à la sortie de la fonction qu'elle avait changé. Cette protection ne couvre que le débordement vers le haut d'un tableau local ; elle n'a rien vu, et ne peut rien voir, du même débordement sur un bloc du tas. Elle réduit la surface d'attaque, elle ne rend pas le programme correct.