Вы находитесь на странице: 1из 58

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

retour

Gestion de la mmoire en C

1 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Notice
Le prsent document est publi sous la licence Verbatim Copying telle que dnie par la Free Software Fondation dans le cadre du projet GNU. Toute copie ou diusion de ce document dans son intgralit est permise (et mme encourage), quel qu'en soit le support la seule condition que cette notice, inclant les copyrights, soit prserve. Copyright (C) 2002, 2003, 2004 Yann LANGLAIS, ilay. La plus rcente version en date de ce document est sise l'url http://ilay.org /yann/articles/mem/. Toute remarque, suggestion ou correction est bienvenue et peut tre adresse Yann LANGLAIS, ilay.org.

2 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Introduction
Le langage C est souvent considr comme un langage dicile et peu able. La seconde assertion n'est pas acceptable dans la mesure o la plupart des applications, y compris les L4G et RAD sont eux mmes crits en C. En fait, ces ides reues proviennent principalement de l'utilisation intensive des pointeurs. Si le C est souvent mal considr, c'est bien souvent cause de la mconnaissance du concept de pointeur et de la gestion de la mmoire qui lui est associ. Le prsent document se propose de prsenter ces concepts depuis leurs fondements thoriques jusqu' leur application pratique. Il ne s'agit pas pour autant de dnir les direntes notions avec la plus grande rigueur qui soit. Mon propos n'est pas de faire de l'initiation l'assembleur, ni l'lectronique. Mon but est de prsenter la gestion de la mmoire sous un angle dirent de celui gnralement adopt. L'audience vise est principalement celle des dveloppeurs ayant dj t initis au langage C.
(Table des matires)

3 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

La mmoire
La mmoire physique de l'ordinateur
La mmoire de l'ordinateur est assimilable, en premire approximation un long tableau continu. La largeur de ce tableau s'exprime en "bits". En gnral, les cette taille comporte des subdivisions. En eet, pour une taille de 32bits, par exemple, un octet n'etant cod que sur 8bits, il est ncessaire, an de ne pas perdre trop d'espace, de pouvoir stocker 4 octets dirents par case de 32 bits et donc accder de manire indpendante ces 4 subdivisions. Un bus 32bits est en gnral dcoup en subdivisions de 8 et 16 bits. Chaque subdivision (octet) est numrote. Cette numrotation correspond une adresse mmoire.

Espace mmoire des programmes C


Cette dernire vision des choses ne s'applique pas la ralit virtuelle d'un processus. En eet, il est frquent de voir des processus utiliser plus de mmoire que la quantit de RAM physique rellement disponible. Dans ce dernier cas, l'application utilise une partie de la mmoire RAM, mais aussi d'autres formes telle que le swap. Le systme et les dirents composants matriels (en particulier la "Memory Management Unit", MMU ou unit de gestion de la mmoire) se chargent d'agrger les direntes ressources (RAM, swap, disque dur, ...) et de faire croire aux processus que la mmoire est un vaste tableau homogne et contigu. Les mcanismes rendant possible cette illusion sont assez complexes dpassent de loin le cadre de ce document, mais ce sujet est largement couvert . Il est cependant ncessaire de noter que les cases du "tableau-mmoire" ne sont pas rllement prsentes (i.e. pointent rellement vers des zones de mmoire physique relle) que lorsque celles-ci sont rellement utilises. Pour chaque processus, cette zone contige s'tale de 0x00000000 0xFFFFFFFF. La zone infrieure la zone de chargement du segment text du programme est rserve et ne peut tre accde en criture. La zone suprieure la valeur de la macro PAGE_OFFSET est rserve pour le noyau (mapping noyau des zones de mmoire du processus). Cet espace mmoire est rempli selon certaines rgles dpendantes des sytmes et des architectures matrielles.
1

4 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Figure 1 : utilisation de la mmoire pour chaque processus.

Zone programme
Tout d'abord la zone de "programme", dcoupe en plusieurs segments dont : Le segment texte (.text) contient le code machine du programme. Le segment bss (.bss) contient les donnes non initialises (variables globales du C). BSS signie "Block Stating Symbol". Le segment data (.data) contient les donnes initialises du programmes (constantes globales).

Le tas (heap)
Ensuite, vient le tas (heap). C'est la mmoire alloue dynamiquement avec les
5 sur 58 22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

fonctions de type malloc(). La croissance de cette zone s'eectue vers les adresses hautes. L'adresse de base du tas est donne par la fonction sbrk(0) avant toute allocation ou par brk(0).

Le mmoire libre
Vient la zone de mmoire libre", ou mmoire non alloue. Elle est consomme par le tas. La rservation d'une zone suppmentaire se fait avec la fonction sbrk(taillesupp) ou taillesup est la taille de la zone rserver.

Zone de liens dynamiques


Aprs cette zone de mmoire libre, une partie de la mmoire est rserve pour les bibliothques dynamiques (links), charges soit lors du chargement de l'excutable quand les bibliothques ont t rfrences lors de la phase d'dition de liens (symboles ncessaires la compilation), soit pendant l'exction du programme et par le programme lui mme par l'appel aux fonctions dlopen() et dlsym() (programmation de greons, chargement de modules ...).

La pile (stack)
Enn, la dernire zone de l'espace utilisateur est la pile. La pile commence, l'inverse des autres zones, l'adresse la plus haute (soit thoriquement PAGE_OFFSET-1). La pile croit donc vers les adresses basses. La pile se compose de boites ou cadres (frames). Chacune de ces boites correspont une procdure ou fonction. La fonction main() sera la boite 1 (seconde sur la pile). Si main() appelle une fonction "toto()", alors, lorsque le programme passera dans toto(), une boite numrote 2 sera place sur la pile, au "dessus" de la boite numrote 1 de main(). A la sortie de la fonction toto(), la boite numro 2 sera dtruite (dpile/modication de la topographie ou mapping de la mmoire virtelle). Chaque boite contient les variables locales la procdure (i.e. dnie sur la pile), l'adresse de retour de la procdure, une sauvegarde des paramres passe en entre la procdure, voire aussi une copie de tout ou partie de la zone de registres du microprocesseur. Une boite, ou frame, n'est donc valide que tant que l'on ne sort pas de la fonction laquelle elle est associe. Il n'est donc possible d'utiliser un pointeur sur une zone de mmoire rserve sur la pile que dans la fonction o cette mmoire est rserve et les sous fonctions appeles par cette fonction. Des la sortie d'une fonction, la zone la frame associe cette fonction est limine de la carte de la mmoire virtuelle. La zone occupe par l'ancienne frame se retrouve donc contenir des donnes alatoires. En corrolaires : La pile est rserve statiquement. Il est impossible de changer dynamiquement sa taille. Une pile est allou localement : pour le programme (variable globale non statique, ou dnie comme externe), pour le chier en cours (variable globale statique), pour la fonction en cours (variables dnies en dbut de fonction).

6 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

La pile reprsente la proportion de la mmoire de travail utilise temporairement pour un traitement particulier.
% cat frameshow.c #include int function3(int a, int b, int c, int d) { int i_3 = 0x30303030; printf("in function3\n"); return 0x3F3F3F3F; } int function2(int a, int b, int c, int d) { int i_2 = 0x20202020; printf("in function2\n"); function3(0xCCCCCCC1, 0xCCCCCCC2, 0xCCCCCCC3, 0xCCCCCCC4); return 0x2F2F2F2F; } int function1(int a, int b, int c, int d) { int i_1 = 0x10101010; printf("in function1\n"); function2(0xBBBBBBB1, 0xBBBBBBB2, 0xBBBBBBB3, 0xBBBBBBB4); return 0x1F1F1F1F; } int final(int a, int b) { int i_final = 0x0FF00FF0; return i_final; } int main() { int i_main = 0x12345678; printf("in main\n"); function1(0xAAAAAAA1, 0xAAAAAAA2, 0xAAAAAAA3, 0xAAAAAAA4); final(0xDDDDDDD1, 0xDDDDDDD2); return 0; } % cc -g frameshow.c -o frameshow % dis frameshow **** DISASSEMBLER

****

disassembly for frameshow section .text _start() 106b8: 106bc: 106c0: 106c4: 106c8: 106cc: 106d0: 106d4: 106d8:

bc e0 13 e0 a2 13 e2 13 e2

10 03 00 22 03 00 22 00 22

20 a0 00 60 a0 00 60 00 60

00 40 83 54 44 83 50 83 44

clr ld sethi st add sethi st sethi st

%fp [%sp + 64], %l0 %hi(0x20c00), %o1 %l0, [%o1 + 0x54] %sp, 68, %l1 %hi(0x20c00), %o1 %l1, [%o1 + 0x50] %hi(0x20c00), %o1 %l1, [%o1 + 0x44]

7 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
106dc: 106e0: 106e4: 106e8: 106ec: 106f0: 106f4: 106f8: 106fc: 10700: 10704: 10708: 1070c: 10710: 10714: 10718: 1071c: 10720: 10724: 10728: 1072c: 10730: 10734: 10738: 1073c: 10740: 10744: 10748: 1074c: 10750: 10754: 10758: 1075c: 10760: 10764: 10768: 1076c: 10770: 10774: 10778: 1077c: 10780: 10784: 10788: 1078c: 10790: 10794: 10798: 1079c: 107a0: 107a4: 107a8: 107ac: 107b0: 107b4: 107b8: 107bc: 107c0: a5 a4 a4 27 e8 80 12 01 e4 2b aa 80 02 01 ad ae ac ac ab 29 a8 c1 ec ae af af ac ac ec c1 9c 80 02 90 40 01 11 40 90 11 d0 80 12 01 11 d0 80 02 01 40 01 40 01 90 92 94 96 40 2c 04 04 00 04 a5 80 00 24 00 15 90 80 00 2d 0d 0d 15 2d 00 15 2d 05 20 3d 2d 2d 15 25 0d 23 90 80 10 00 00 00 00 12 00 02 90 80 00 00 02 90 80 00 00 00 00 00 10 10 10 10 00 20 a0 40 00 e0 20 00 00 e0 00 60 00 00 00 60 a3 60 80 a0 00 20 00 00 00 e0 e0 80 80 00 00 a0 00 00 00 40 00 00 40 22 00 20 00 00 00 00 20 00 00 00 40 00 00 00 00 00 00 00 00 02 04 12 83 38 00 03 00 38 00 00 15 12 00 02 00 3f 17 16 83 3c 00 00 17 1f 1e 17 15 00 00 20 01 04 01 f1 00 42 ee 7c 83 48 08 09 00 83 4c 08 04 00 e2 00 b2 00 10 11 12 13 88 sll add add sethi ld cmp bne nop st sethi or orcc be nop sll and and or sll sethi or st ld sub sra sll andn or st ld sub orcc be mov call nop sethi call or sethi ld orcc bne nop sethi ld orcc be nop call nop call nop mov mov mov mov call %l0, 2, %l2 %l2, 4, %l2 %l1, %l2, %l2 %hi(0x20c00), %l3 [%l3 + 0x38], %l4 %l4, 0 0x10700

http://ilay.org/yann/articles/mem/

%l2, [%l3 + 56] %hi(__fsr_init_value), %l5 %l5, __fsr_init_value, %l5 %g0, %l5, %g0 0x10754 %l5, 2, %l6 %l6, 768, %l7 %l5, 63, %l6 %l6, %l7, %l6 %l6, 22, %l5 %hi(0x20c00), %l4 %l4, 0x3c, %l4 ! __crt_scratch %fsr, [%l4] [%l4], %l6 %g0, %l7, %l7 %l7, 31, %l7 %l7, 30, %l7 %l6, %l7, %l6 %l6, %l5, %l6 %l6, [%l4] [%l4], %fsr %sp, 32, %sp %g0, %g1, %g0 0x1076c %g1, %o0 atexit %hi(0x10800), %o0 atexit %o0, 636, %o0 %hi(0x20c00), %o0 [%o0 + 0x48], %o0 %g0, %o0, %g0 0x107a8 %hi(0x20c00), %o0 [%o0 + 0x4c], %o0 %g0, %o0, %g0 0x107a8 atexit _init %l0, %l1, %l2, %l3, main %o0 %o1 %o2 %o3

! __fsr_init_va

8 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
107c4: 107c8: 107cc: 107d0: 107d4: 107d8: 107dc: 107e0: 107e4: function3() 107e8: 107ec: 107f0: 107f4: 107f8: 107fc: 10800: 10804: 10808: 1080c: 10810: 10814: 10818: 1081c: 10820: 10824: 10828: 1082c: 10830: 10834: 10838: 1083c: 10840: 10844: 10848: 1084c: function2() 10850: 10854: 10858: 1085c: 10860: 10864: 10868: 1086c: 10870: 10874: 10878: 1087c: 10880: 10884: 10888: 1088c: 10890: 10894: 10898: 1089c: 108a0: 01 40 01 40 01 00 00 00 00 9d f6 f4 f2 f0 21 a0 e0 21 a0 40 90 21 a0 10 e0 10 01 e0 b0 81 81 00 00 00 00 9d f6 f4 f2 f0 21 a0 e0 21 a0 40 90 21 a0 23 a2 25 a4 27 a6 90 00 00 00 00 00 01 01 01 01 e3 27 27 27 27 0c 14 27 00 14 00 14 0f 14 80 27 80 00 07 14 c7 e8 01 01 01 01 e3 27 27 27 27 08 14 27 00 14 00 14 0c 1c 0c 1c 0c 1c 0c 1c 14 00 40 00 40 00 00 00 00 00 bf a0 a0 a0 a0 0c 20 bf 00 22 40 00 cf 23 00 bf 00 00 bf 00 e0 00 00 00 00 00 bf a0 a0 a0 a0 08 20 bf 00 22 40 00 cc 3c cc 7c cc bc cc fc 00 00 db 00 dc 00 00 00 00 00 98 50 4c 48 44 0c 30 f8 42 b8 cf 00 cf 3f 04 fc 02 00 fc 00 08 00 00 00 00 00 98 50 4c 48 44 08 20 f8 42 c8 b5 00 cc c1 cc c2 cc c3 cc c4 00 nop call nop call nop unimp unimp unimp unimp save st st st st sethi or st sethi or call or sethi or ba st ba nop ld or ret restore unimp unimp unimp unimp save st st st st sethi or st sethi or call or sethi xor sethi xor sethi xor sethi xor or

http://ilay.org/yann/articles/mem/

exit _exit 0x10000 0x10000 0x10000 0x10000 %sp, -104, %sp %i3, [%fp + 80] %i2, [%fp + 76] %i1, [%fp + 72] %i0, [%fp + 68] %hi(0x30303000), %l0 %l0, 0x30, %l0 ! 0x30303030 %l0, [%fp - 8] %hi(0x10800), %l0 %l0, 0x2b8, %l0 ! 0x10ab8 printf %l0, %g0, %o0 %hi(0x3f3f3c00), %l0 %l0, 0x33f, %l0 ! 0x3f3f3f3f 0x10830 %l0, [%fp - 4] 0x10830 [%fp - 4], %l0 %l0, %g0, %i0

0x10000 0x10000 0x10000 0x10000 %sp, -104, %sp %i3, [%fp + 80] %i2, [%fp + 76] %i1, [%fp + 72] %i0, [%fp + 68] %hi(0x20202000), %l0 %l0, 0x20, %l0 ! 0x20202020 %l0, [%fp - 8] %hi(0x10800), %l0 %l0, 0x2c8, %l0 ! 0x10ac8 printf %l0, %g0, %o0 %hi(0x33333000), %l0 %l0, -831, %l0 %hi(0x33333000), %l1 %l1, -830, %l1 %hi(0x33333000), %l2 %l2, -829, %l2 %hi(0x33333000), %l3 %l3, -828, %l3 %l0, %g0, %o0

9 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
108a4: 108a8: 108ac: 108b0: 108b4: 108b8: 108bc: 108c0: 108c4: 108c8: 108cc: 108d0: 108d4: 108d8: 108dc: 108e0: 108e4: 108e8: 108ec: function1() 108f0: 108f4: 108f8: 108fc: 10900: 10904: 10908: 1090c: 10910: 10914: 10918: 1091c: 10920: 10924: 10928: 1092c: 10930: 10934: 10938: 1093c: 10940: 10944: 10948: 1094c: 10950: 10954: 10958: 1095c: 10960: 10964: 10968: 1096c: 10970: 10974: 10978: 1097c: 10980: 10984: 92 94 7f 96 21 a0 10 e0 10 01 e0 b0 81 81 00 00 00 00 00 9d f6 f4 f2 f0 21 a0 e0 21 a0 40 90 21 a0 23 a2 25 a4 27 a6 90 92 94 7f 96 21 a0 10 e0 10 01 e0 b0 81 81 00 00 00 14 14 ff 14 0b 14 80 27 80 00 07 14 c7 e8 01 01 01 01 01 e3 27 27 27 27 04 14 27 00 14 00 14 11 1c 11 1c 11 1c 11 1c 14 14 14 ff 14 07 14 80 27 80 00 07 14 c7 e8 01 01 01 40 80 ff c0 cb 23 00 bf 00 00 bf 00 e0 00 00 00 00 00 00 bf a0 a0 a0 a0 04 20 bf 00 22 40 00 11 3f 11 7f 11 bf 11 ff 00 40 80 ff c0 c7 23 00 bf 00 00 bf 00 e0 00 00 00 00 00 00 cf 00 cb 2f 04 fc 02 00 fc 00 08 00 00 00 00 00 00 98 50 4c 48 44 04 10 f8 42 d8 8d 00 11 b1 11 b2 11 b3 11 b4 00 00 00 c1 00 c7 1f 04 fc 02 00 fc 00 08 00 00 00 00 or or call or sethi or ba st ba nop ld or ret restore unimp unimp unimp unimp unimp save st st st st sethi or st sethi or call or sethi xor sethi xor sethi xor sethi xor or or or call or sethi or ba st ba nop ld or ret restore unimp unimp unimp

http://ilay.org/yann/articles/mem/
%l1, %g0, %o1 %l2, %g0, %o2 function3 %l3, %g0, %o3 %hi(0x2f2f2c00), %l0 %l0, 0x32f, %l0 ! 0x2f2f2f2f 0x108cc %l0, [%fp - 4] 0x108cc [%fp - 4], %l0 %l0, %g0, %i0

0x10000 0x10000 0x10000 0x10000 0x10000 %sp, -104, %sp %i3, [%fp + 80] %i2, [%fp + 76] %i1, [%fp + 72] %i0, [%fp + 68] %hi(0x10101000), %l0 %l0, 0x10, %l0 ! 0x10101010 %l0, [%fp - 8] %hi(0x10800), %l0 %l0, 0x2d8, %l0 ! 0x10ad8 printf %l0, %g0, %o0 %hi(0x44444400), %l0 %l0, -79, %l0 %hi(0x44444400), %l1 %l1, -78, %l1 %hi(0x44444400), %l2 %l2, -77, %l2 %hi(0x44444400), %l3 %l3, -76, %l3 %l0, %g0, %o0 %l1, %g0, %o1 %l2, %g0, %o2 function2 %l3, %g0, %o3 %hi(0x1f1f1c00), %l0 %l0, 0x31f, %l0 ! 0x1f1f1f1f 0x1096c %l0, [%fp - 4] 0x1096c [%fp - 4], %l0 %l0, %g0, %i0

0x10000 0x10000 0x10000

10 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
10988: 1098c: final() 10990: 10994: 10998: 1099c: 109a0: 109a4: 109a8: 109ac: 109b0: 109b4: 109b8: 109bc: 109c0: 109c4: 109c8: 109cc: 109d0: 109d4: 109d8: 109dc: main() 109e0: 109e4: 109e8: 109ec: 109f0: 109f4: 109f8: 109fc: 10a00: 10a04: 10a08: 10a0c: 10a10: 10a14: 10a18: 10a1c: 10a20: 10a24: 10a28: 10a2c: 10a30: 10a34: 10a38: 10a3c: 10a40: 10a44: 10a48: 10a4c: 10a50: 10a54: 10a58: 10a5c: 10a60: 10a64: 9d 21 a0 e0 21 a0 40 90 21 a0 23 a2 25 a4 27 a6 90 92 94 7f 96 21 a0 23 a2 90 7f 92 10 c0 10 01 e0 b0 e3 04 14 27 00 14 00 14 15 1c 15 1c 15 1c 15 1c 14 14 14 ff 14 08 1c 08 1c 14 ff 14 80 27 80 00 07 14 bf 8d 22 bf 00 22 40 00 55 3e 55 7e 55 be 55 fe 00 40 80 ff c0 88 3d 88 7d 00 ff 40 00 bf 00 00 bf 00 98 15 78 f8 42 e8 55 00 55 a1 55 a2 55 a3 55 a4 00 00 00 b1 00 88 d1 88 d2 00 d2 00 04 fc 02 00 fc 00 save sethi or st sethi or call or sethi xor sethi xor sethi xor sethi xor or or or call or sethi xor sethi xor or call or ba st ba nop ld or 9d f2 f0 21 a0 e0 e0 10 e0 10 01 e0 b0 81 81 00 00 00 00 00 e3 27 27 03 14 27 07 80 27 80 00 07 14 c7 e8 01 01 01 01 01 bf a0 a0 fc 23 bf bf 00 bf 00 00 bf 00 e0 00 00 00 00 00 00 98 48 44 03 f0 f8 f8 04 fc 02 00 fc 00 08 00 00 00 00 00 00 save st st sethi or st ld ba st ba nop ld or ret restore unimp unimp unimp unimp unimp 00 01 00 00 00 01 00 00 unimp unimp 0x10000 0x10000

http://ilay.org/yann/articles/mem/

%sp, -104, %sp %i1, [%fp + 72] %i0, [%fp + 68] %hi(0xff00c00), %l0 %l0, 0x3f0, %l0 ! 0xff00ff0 %l0, [%fp - 8] [%fp - 8], %l0 0x109bc %l0, [%fp - 4] 0x109bc [%fp - 4], %l0 %l0, %g0, %i0

0x10000 0x10000 0x10000 0x10000 0x10000 %sp, -104, %sp %hi(0x12345400), %l0 %l0, 0x278, %l0 ! 0x12345678 %l0, [%fp - 8] %hi(0x10800), %l0 %l0, 0x2e8, %l0 ! 0x10ae8 printf %l0, %g0, %o0 %hi(0x55555400), %l0 %l0, -351, %l0 %hi(0x55555400), %l1 %l1, -350, %l1 %hi(0x55555400), %l2 %l2, -349, %l2 %hi(0x55555400), %l3 %l3, -348, %l3 %l0, %g0, %o0 %l1, %g0, %o1 %l2, %g0, %o2 function1 %l3, %g0, %o3 %hi(0x22222000), %l0 %l0, -559, %l0 %hi(0x22222000), %l1 %l1, -558, %l1 %l0, %g0, %o0 final %l1, %g0, %o1 0x10a60 %g0, [%fp - 4] 0x10a60 [%fp - 4], %l0 %l0, %g0, %i0

11 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
10a68: 10a6c: section .init _init() 10a70: 10a74: 10a78: section .fini _fini() 10a7c: 10a80: 10a84: 81 c7 e0 08 81 e8 00 00 ret restore

http://ilay.org/yann/articles/mem/

9d e3 bf a0 81 c7 e0 08 81 e8 00 00

save ret restore

%sp, -96, %sp

9d e3 bf a0 81 c7 e0 08 81 e8 00 00

save ret restore

%sp, -96, %sp

% dbx frameshow Reading frameshow Reading ld.so.1 Reading libc.so.1 Reading libdl.so.1 Reading libc_psr.so.1 dbx> alias P="print -f0x%x" dbx> print main main = &main() at 0x109e0 dbx> print function1 function1 = &function1(int a, int b, int c, int d) at 0x108f0 dbx> print function2 function2 = &function2(int a, int b, int c, int d) at 0x10850 dbx> print function3 function3 = &function3(int a, int b, int c, int d) at 0x107e8 dbx> stop in main (2) stop in main dbx> run Running: frameshow (process id 28873) stopped in main at line 31 in file "frameshow.c" 31 int i_main = 0x12345678; dbx> next stopped in main at line 32 in file "frameshow.c" 32 printf("in main\n"); dbx> P $sp $sp = 0xffbef3e0 dbx> P $fp $fp = 0xffbef448 dbx> ex $sp, $fp 0xffbef3e0: 0x12345678 0x00000000 0x00000000 0x00000000 0xffbef3f0: 0x00000000 0x00000000 0x00000000 0xff3dc890 0xffbef400: 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef448 0x000107c0 0xffbef410: 0xffbef420: 0x00000000 0x00000000 0x00000003 0xffbef4ac 0x00000004 0xffbef4b4 0x00000005 0xffbef5fc 0xffbef430: 0xffbef440: 0x12345678 0x00000000 0x00000001 dbx> regs current frame: [1] g0-g3 0x00000000 0xff319c04 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x00000000 0xff3420d8 0xff33e5d8 0xffffffff o4-o7 0x000222e8 0xff29bc20 0xffbef3e0 0xff29bc20

12 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

l0-l3 0x12345678 0x00000000 0x00000000 0x00000000 l4-l7 0x00000000 0x00000000 0x00000000 0xff3dc890 i0-i3 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 i4-i7 0x00000000 0x00000000 0xffbef448 0x000107c0 y 0x00000000 ccr 0x00000000 pc 0x000109f0:main+0x10 sethi %hi(0x10800), %l0 npc 0x000109f4:main+0x14 or %l0, 0x2e8, %l0 dbx> next stopped in main at line 33 in file "frameshow.c" 33 function1(0xAAAAAAA1, 0xAAAAAAA2, 0xAAAAAAA3, 0xAAAAAAA4); dbx> step stopped in function1 at line 18 in file "frameshow.c" 18 int i_1 = 0x10101010; dbx> next stopped in function1 at line 19 in file "frameshow.c" 19 printf("in function1\n"); dbx> next stopped in function1 at line 20 in file "frameshow.c" 20 function2(0xBBBBBBB1, 0xBBBBBBB2, 0xBBBBBBB3, 0xBBBBBBB4); dbx> P $sp $sp = 0xffbef378 dbx> P $fp $fp = 0xffbef3e0 dbx> ex $sp, 0xffbef448 0xffbef378: 0x00010ad8 0x00000000 0x00000000 0x00000000 0xffbef388: 0x00000000 0x00000000 0x00000000 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 input parameters 0xffbef398: 0xffbef3a8: 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c previous stack end and return a 0xffbef3e0 0x000109f8 0x00000000 0x00000000 0xffbef3b8: 0xffbef3c8: 0x00000000 0x00000000 0x00000000 0xff29bc20 0xffbef3d8: 0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2 parameters passed 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 function1 0xffbef3e8: 0xffbef3f8: 0x00000000 0xff3dc890 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef408: 0xffbef418: 0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xffbef428: 0xffbef438: 0xff29bc20 0xffbef5fc 0x12345678 0x00000000 value of i_main on stack 0x00000001 0xffbef448: dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x0000000d 0xff340284 0xff343a54 0x00000000 o4-o7 0x00000000 0x00000000 0xffbef378 0x00010918 l0-l3 0x00010ad8 0x00000000 0x00000000 0x00000000 l4-l7 0x00000000 0x00000000 0x00000000 0x00000000 i0-i3 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 i4-i7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c y 0x00000000 ccr 0x00000099 pc 0x00010920:function1+0x30 sethi %hi(0x44444400), %l0 npc 0x00010924:function1+0x34 xor %l0, -0x4f, %l0 dbx> step stopped in function2 at line 11 in file "frameshow.c" 11 int i_2 = 0x20202020; dbx> next stopped in function2 at line 12 in file "frameshow.c"

13 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

12 printf("in function2\n"); dbx> next stopped in function2 at line 13 in file "frameshow.c" 13 function3(0xCCCCCCC1, 0xCCCCCCC2, 0xCCCCCCC3, 0xCCCCCCC4); dbx> P $sp $sp = 0xffbef310 dbx> P $fp $fp = 0xffbef378 dbx> ex $sp, 0xffbef448 0xffbef310: 0x00010ac8 0x00000000 0x00000000 0x00000000 0xffbef320: 0x00000000 0x00000000 0x00000000 0x00000000 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0xffbef330: 0xffbef340: 0x00000000 0x00000000 0xffbef378 0x0001094c 0xffbef350: 0xffbef5fc 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef360: 0xffbef370: 0x20202020 0x00000000 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xffbef380: 0xffbef390: 0x00000000 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xff29bc20 0xffbef3a0: 0xffbef3b0: 0xffbef3e0 0x00010a2c 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0xffbef3c0: 0xffbef3d0: 0x00000000 0xff29bc20 0x10101010 0x000109f8 0xffbef3e0: 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 0x00000000 0xff3dc890 0xffbef3f0: 0xffbef400: 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef448 0x000107c0 0xffbef410: 0xffbef420: 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xff29bc20 0xffbef5fc 0xffbef430: 0xffbef440: 0x12345678 0x00000000 0x00000001 dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x0000000d 0xff340284 0xff343a54 0x00000000 o4-o7 0x00000000 0x00000000 0xffbef310 0x00010878 l0-l3 0x00010ac8 0x00000000 0x00000000 0x00000000 l4-l7 0x00000000 0x00000000 0x00000000 0x00000000 i0-i3 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 i4-i7 0x00000000 0x00000000 0xffbef378 0x0001094c y 0x00000000 ccr 0x00000099 pc 0x00010880:function2+0x30 sethi %hi(0x33333000), %l0 npc 0x00010884:function2+0x34 xor %l0, -0x33f, %l0 dbx> step stopped in function3 at line 5 in file "frameshow.c" 5 int i_3 = 0x30303030; dbx> next stopped in function3 at line 6 in file "frameshow.c" 6 printf("in function3\n"); dbx> next stopped in function3 at line 7 in file "frameshow.c" 7 return 0x3F3F3F3F; dbx> P $sp $sp = 0xffbef2a8 dbx> P $fp $fp = 0xffbef310 dbx> ex $sp, 0xffbef448 0xffbef2a8: 0x00010ab8 0x00000000 0x00000000 0x00000000

14 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2c8: 0xccccccc1 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0xffbef310 0x000108ac 0xffbef2d8: 0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000 0x30303030 0x00000000 0xccccccc1 0xccccccc2 0xffbef308: 0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0x00000000 0x00000000 0xbbbbbbb1 0xbbbbbbb2 0xffbef328: 0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1 0xffbef348: 0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0x00000000 0x20202020 0x00000000 0xffbef368: 0xffbef378: 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0xffbef388: 0x00000000 0x00000000 0x00000000 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0xffbef398: 0xffbef3a8: 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xffbef3b8: 0xffbef3c8: 0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20 0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2 0xffbef3d8: 0xffbef3e8: 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 0x00000000 0xff3dc890 0x00000001 0xffbef4ac 0xffbef3f8: 0xffbef408: 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef418: 0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xffbef428: 0xffbef438: 0xff29bc20 0xffbef5fc 0x12345678 0x00000000 0x00000001 0xffbef448: dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x0000000d 0xff340284 0xff343a54 0x00000000 o4-o7 0x00000000 0x00000000 0xffbef2a8 0x00010810 l0-l3 0x00010ab8 0x00000000 0x00000000 0x00000000 l4-l7 0x00000000 0x00000000 0x00000000 0x00000000 i0-i3 0xccccccc1 0xccccccc2 0xccccccc3 0xccccccc4 i4-i7 0x00000000 0x00000000 0xffbef310 0x000108ac y 0x00000000 ccr 0x00000099 pc 0x00010818:function3+0x30 sethi %hi(0x3f3f3c00), %l0 npc 0x0001081c:function3+0x34 or %l0, 0x33f, %l0 dbx> next stopped in function3 at line 8 in file "frameshow.c" 8 } dbx> next stopped in function2 at line 14 in file "frameshow.c" 14 return 0x2F2F2F2F; dbx> P $sp $sp = 0xffbef310 dbx> P $fp $fp = 0xffbef378 dbx> ex 0xffbef2a8, 0xffbef448 0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000 0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4 0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac 0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef308: 0x30303030 0x3f3f3f3f 0xccccccc1 0xccccccc2

15 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0xffbef328: 0x00000000 0x00000000 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xffbef338: 0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1 0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0x00000000 0x20202020 0x00000000 0xffbef368: 0xffbef378: 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef388: 0xffbef398: 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c 0xffbef3a8: 0xffbef3b8: 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20 0xffbef3c8: 0xffbef3d8: 0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2 0xffbef3e8: 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 0x00000000 0xff3dc890 0x00000001 0xffbef4ac 0xffbef3f8: 0xffbef408: 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1 0xffbef418: 0xffbef428: 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xff29bc20 0xffbef5fc 0x12345678 0x00000000 0xffbef438: 0xffbef448: 0x00000001 dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4 o4-o7 0x00000000 0x00000000 0xffbef310 0x000108ac l0-l3 0xccccccc1 0xccccccc2 0xccccccc3 0xccccccc4 l4-l7 0x00000000 0x00000000 0x00000000 0x00000000 i0-i3 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 i4-i7 0x00000000 0x00000000 0xffbef378 0x0001094c y 0x00000000 ccr 0x00000099 pc 0x000108b4:function2+0x64 sethi %hi(0x2f2f2c00), %l0 npc 0x000108b8:function2+0x68 or %l0, 0x32f, %l0 dbx> next stopped in function2 at line 15 in file "frameshow.c" 15 } dbx> next stopped in function1 at line 21 in file "frameshow.c" 21 return 0x1F1F1F1F; dbx> P $sp $sp = 0xffbef378 dbx> P $fp $fp = 0xffbef3e0 dbx> ex 0xffbef2a8, 0xffbef448 0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000 0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4 0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac 0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef308: 0x30303030 0x3f3f3f3f 0x2f2f2f2f 0xccccccc2 0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0xffbef328: 0x00000000 0x00000000 0x2f2f2f2f 0xbbbbbbb2 0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1 0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000 0xffbef368: 0x00000000 0x00000000 0x20202020 0x2f2f2f2f

16 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

0xffbef378: 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0xffbef388: 0x00000000 0x00000000 0x00000000 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0xffbef398: 0xffbef3a8: 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c 0xffbef3b8: 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20 0xffbef3c8: 0xffbef3d8: 0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 0xffbef3e8: 0xffbef3f8: 0x00000000 0xff3dc890 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef408: 0xffbef418: 0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xffbef428: 0xffbef438: 0xff29bc20 0xffbef5fc 0x12345678 0x00000000 0xffbef448: 0x00000001 dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x2f2f2f2f 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 o4-o7 0x00000000 0x00000000 0xffbef378 0x0001094c l0-l3 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 l4-l7 0x00000000 0x00000000 0x00000000 0x00000000 i0-i3 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 i4-i7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c y 0x00000000 ccr 0x00000099 pc 0x00010954:function1+0x64 sethi %hi(0x1f1f1c00), %l0 npc 0x00010958:function1+0x68 or %l0, 0x31f, %l0 dbx> next stopped in function1 at line 22 in file "frameshow.c" 22 } dbx> next stopped in main at line 34 in file "frameshow.c" 34 final(0xDDDDDDD1, 0xDDDDDDD2); dbx> step stopped in final at line 25 in file "frameshow.c" 25 int i_final = 0x0FF00FF0; dbx> next stopped in final at line 26 in file "frameshow.c" 26 return i_final; dbx> P $sp $sp = 0xffbef378 dbx> P $fp $fp = 0xffbef3e0 dbx> ex 0xffbef2a8, 0xffbef448 0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000 0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4 0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac 0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef308: 0x30303030 0x3f3f3f3f 0x2f2f2f2f 0xccccccc2 0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0xffbef328: 0x00000000 0x00000000 0x2f2f2f2f 0xbbbbbbb2 0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1 0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000 0xffbef368: 0x00000000 0x00000000 0x20202020 0x2f2f2f2f

17 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
0xffbef378: 0x0ff00ff0 0x00000000 0x00000000 0x00000000 0xffbef388: 0x00000000 0x00000000 0x00000000 0x00000000 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0xffbef398: 0xffbef3a8: 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48 0xffbef3b8: 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20 0xffbef3c8: 0xffbef3d8: 0x0ff00ff0 0x1f1f1f1f 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 0xffbef3e8: 0xffbef3f8: 0x00000000 0xff3dc890 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef408: 0xffbef418: 0xffbef448 0x000107c0 0x00000000 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xffbef428: 0xffbef438: 0xff29bc20 0x00000000 0x12345678 0x00010764 0xffbef448: 0x00000001 dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x00000000 0x00000000 0x00000000 0x00000000 o4-o7 0x00000000 0x00000000 0xffbef378 0x00000000 l0-l3 0x0ff00ff0 0x00000000 0x00000000 0x00000000 l4-l7 0x00000000 0x00000000 0x00000000 0x00000000 i0-i3 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 i4-i7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48 y 0x00000000 ccr 0x00000099 pc 0x000109a8:final+0x18 ld [%fp - 0x8], %l0 npc 0x000109ac:final+0x1c ba final+0x2c dbx> next stopped in final at line 27 in file "frameshow.c" 27 } dbx> next stopped in main at line 35 in file "frameshow.c" 35 return 0; dbx> P $sp $sp = 0xffbef3e0 dbx> P $fp $fp = 0xffbef448 dbx> ex 0xffbef2a8, 0xffbef448 0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000 0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4 0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac 0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef308: 0x30303030 0x3f3f3f3f 0x2f2f2f2f 0xccccccc2 0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000 0xffbef328: 0x00000000 0x00000000 0x2f2f2f2f 0xbbbbbbb2 0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000 0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1 0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000 0xffbef368: 0x00000000 0x00000000 0x20202020 0x2f2f2f2f 0xffbef378: 0x0ff00ff0 0x00000000 0x00000000 0x00000000 0xffbef388: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef398: 0x0ff00ff0 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0xffbef3a8: 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48 0xffbef3b8: 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xffbef3c8: 0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20

http://ilay.org/yann/articles/mem/

18 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
0xffbef3d8: 0x0ff00ff0 0x0ff00ff0 0xddddddd1 0xddddddd2 0xffbef3e8: 0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 0x00000000 0xff3dc890 0x00000001 0xffbef4ac 0xffbef3f8: 0xffbef408: 0xffbef4b4 0x00020c00 0x00000000 0x00000000 0xffbef418: 0xffbef448 0x000107c0 0x00000000 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xffbef428: 0xffbef438: 0xff29bc20 0x00000000 0x12345678 0x00010764 0x00000001 0xffbef448: dbx> regs current frame: [1] g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000 g4-g7 0x00000000 0x00000000 0x00000000 0x00000000 o0-o3 0x0ff00ff0 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 o4-o7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48 l0-l3 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 l4-l7 0x00000000 0x00000000 0x00000000 0xff3dc890 i0-i3 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00 i4-i7 0x00000000 0x00000000 0xffbef448 0x000107c0 y 0x00000000 ccr 0x00000099 pc 0x00010a50:main+0x70 ba main+0x80 npc 0x00010a54:main+0x74 st %g0, [%fp - 0x4]

http://ilay.org/yann/articles/mem/

La mmoire C
Un programme C gre la mmoire de trois faons direntes: La mmoire globale du segment data, accessible depuis n'importe quel endroit du programme, o sont stockes les donnes statiques globales, La mmoire globale du tas, accessible depuis n'importe quel endroit du programme, o sont stockes les donnes dynamiquement alloues (malloc, ralloc, free, ...) La mmoire locale aussi appele la pile, accessible localement seulement, o sont passs les paramtres des fonctions et stockes les donnes locales et temporaires. Exemple :
#include <stdio.h> #include <stdlib.h> static int i_stat = 4; /* Stock dans le segment data */ int i_glob; /* Stock dans le segment bss */ int *pi_pg; /* Stock dans le segment bss */

/* main est stock dans le segment text de la zone de programme */ int main(int nargs, char **args) { /* paramtres nargs et args stocks dans la frame numro 1 de la p int *pi_loc; /* dans la frame 1 de la pile */ void *sbrk0; /* ncessaire pour stocker l'adresse de base avant le premier malloc */ sbrk0 = (void *) sbrk(0); if (!(pi_loc = (int *) malloc(sizeof(int) * 16)))

19 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

/* rservation de 16 x sizeof(int) sur le tas */ return 1; if (!(pi_pg = (int *) malloc(sizeof(int) * 8))) { /* rservation de 8 x sizeof(int) sur le tas */ free(pi_loc); return 2; de i_stat de i_glob de pi_pg de main de nargs de args de pi_loc (heap) = = = = = = = = = = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x (zone programme, segment data)\n", (zone programme, segment bss)\n", (zone programme, segment bss)\n", (zone programme, segment text)\n", (pile frame 1)\n", &nargs); (pile frame 1)\n", &args); (pile frame 1)\n", &pi_loc); (tas)\n", sbrk0); (tas)\n", pi_loc); (tas)\n", pi_pg); &i_stat); &i_glob); &pi_pg); main);

} printf("adresse printf("adresse printf("adresse printf("adresse printf("adresse printf("adresse printf("adresse printf("sbrk(0) printf("pi_loc printf("pi_pg free(pi_pg); free(pi_loc); return 0; }

Donne sous Sparc/Solaris :


adresse adresse adresse adresse adresse adresse adresse sbrk(0) pi_loc pi_pg de i_stat de i_glob de pi_pg de main de nargs de args de pi_loc (heap) = = = = = = = = = = 0x00020c70 0x00020ca4 0x00020ca8 0x0001068c 0xffbeefa4 0xffbeefa8 0xffbeef4c 0x00020c00 0x00020cb8 0x00020d08 (zone (zone (zone (zone (pile (pile (pile (tas) (tas) (tas) programme, programme, programme, programme, frame 1) frame 1) frame 1) segment segment segment segment data) bss) bss) text)

Paralllement, l'utilitaire elfdump donne :


index [17] [21] [47] [60] [68] [80] value 0x00020c68 0x00020c88 0x00020c70 0x00020ca4 0x0001068c 0x00020ca8 size type bind oth ver 0x00000000 SECT LOCL D 0x00000000 SECT LOCL D 0x00000004 OBJT LOCL D 0x00000004 OBJT GLOB D 0x000001e0 FUNC GLOB D 0x00000004 OBJT GLOB D shndx 0 .data 0 .bss 0 .data 0 .bss 0 .text 0 .bss name

i_stat i_glob main pi_pg

20 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

On notera que la variables pi_pg est stocke dans le segment bss mais que les donnes pointes par la variable sont elles stockes dans le tas. De mme, la variable pi_loc est stocke sur la pile, mais les donnes vers lesquelles elle pointe sont stockes sur le tas.

A retenir : La mmoire d'un processus est assimilable un espace contigu, Cet espace est organis en dirents groupes fonctionnels, Les donnes d'un programme ne sont pas toutes stockes au mme endroit en fonction de leur porte et de leur mode de rservation.
(Table des matires)

Le tas Exploration du tas principes d'un allocateur memoire


Un allocateur mmoire est un ensemble de routine responsable de la gestion du tas. Bien qu'un processus pense avoir toute la mmoire pour lui, il faut nanmoins s'assurer d'une part que cette mmoire est rellement disponible (et ne s'envolera pas toute seule lors de modications des pages mmoires par la mmu), et d'autre part que les variables d'une fonction ne soit pas crases par une celles d'une autre. Par ailleurs, les direntes sous parties d'un programme ne ncessitent pas de conserver toute la mmoire alloue pendant toute la dure de l'excution. Par exemple, lorsque l'on referme un chier, il est prfrable librer toute la mmoire qui lui correspond. Cet espace se verra de nouveau disponible pour ouvrir un autre document.

21 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

En rsum, l'allocateur doit se charger des taches suivantes: rservation de pages mmoire auprs du noyau (brk/sbrk) segmentation et rservation de ces pages en fonction des besoins remise disposition de la mmoire prcdement alloue La rservation de pages mmoire est normalement transparent vis vis de l'utilisateur. Par contre, la rservation et la libration de la mmoire sont des oprations en interface avec le programmeur. Les points d'entre de ces deux oprations sont les fonctions malloc() et free(). A ces 2 oprations viennent s'ajouter realloc(), qui permet de modier la taille d'uen zone alloue.

Allocateur minimaliste
Voyons tout d'abord un allocateur minimaliste qui ne libre pas rellement la mmoire, mais dont nous pourrons nous servir le cas chant pour dbugger la mmoire.

Allocateur standards
L'allocateur minimaliste ne rpond pas au problme de la libration. Il a de plus l'inconvniant d'appeler des routines systmes (sbrk) peu performantes chaque malloc.

La pile Notion de type


Un des points les plus importants lorsque l'on parle de langage volu est la notion de typage. Nous ne parlerons pas de la notion thorique de typage, mais de la notion pratique. Dans la pratique, un ordinateur ne reconnait aucun type de donne quant son stockage en mmoire. Il n'existe pas une mmoire spcique pour les entiers et une autre pour les caractres. La seule exception cette rgle se trouve dans les registres des microprocesseurs qui, eux, pour des raisons de performances, direncient les nombres entiers des nombres rels. La notion de type de bas niveau correspond la taille mmoire sur laquelle est encode une entit. Le type dnit donc la taille de la donne manipuler.
(Table des matires)

Types simples
Les types simples sont les types prdnis par le langage C: char, short, int, long, oat, double, et les pointeurs (void *). Il est noter que quel que soit le type de pointeur (char *, int * double *, void *), la taille d'encodage est toujours la mme. Aussi, un pointeur gnrique peut tre appel void *. Ces types ont des tailles xes pour une architecture donne, mais varient d'une architecture l'autre. Il semble mme que la taille d'un octet n'ai pas toujours t de 8bits2

22 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Il est impratif de ne pas supposer de leur taille si l'on recherche la portabilit. On pourra utiliser sizeof(type) en lieu et place de la taille suppose.
1 #include <stdio.h> 2 int main(void) { 3 printf("sizeof(char) 4 printf("sizeof(short) 5 printf("sizeof(int) 6 printf("sizeof(long) 7 8 9 10 11 12 13 14 15 } printf("sizeof(long long) printf("sizeof(float) printf("sizeof(double) printf("sizeof(void *) printf("sizeof(char *) printf("sizeof(int *) printf("sizeof(double *) return 0;

= = = = = = = = = = =

%d\n", %d\n", %d\n", %d\n", %d\n", %d\n", %d\n", %d\n", %d\n", %d\n", %d\n",

sizeof(char)); sizeof(short)); sizeof(int)); sizeof(long)); sizeof(long long));3 sizeof(float)); sizeof(double)); sizeof(void *)); sizeof(char *)); sizeof(int *)); sizeof(double *));

donne sur linux iX86:


sizeof(char) sizeof(short) sizeof(int) sizeof(long) sizeof(long long) sizeof(float) sizeof(double) sizeof(void *) sizeof(char *) sizeof(int *) sizeof(double *) = = = = = = = = = = = 1 2 4 4 84 4 8 4 4 4 4

A retenir: D'un point de vue pratique, le type des donnes en mmoire est assimilable la taille des donnes Il ne faut jamais prjuger de la taille d'un type, mais utiliser sizeof() Tous les pointeurs ont la mme taille sur une architecture donne. Cette taille est cohrente avec la taille du bus mmoire.

(Table des matires)

Alignement
Comme nous l'avons vu dans la description de la mmoire virtuelle, la mmoire est comparable un tableau. On ne peut, en thorie, accder directement qu'a une case entire dont la taille correspond la taille de la mmoire (32bits). Il n'est donc pas possible d'accder directement une fraction d'une case mmoire.

23 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Or comme nous venons de le voir, les types de donns n'ont pas obligatoirement des tailles identiques la taille de la mmoire. Prennons par exemple le caractre char. Celui-ci est cod sur un seul octet. Mais, dans le cas d'une mmoire de 32bits, la taille d'une case est de 4 octets. On devra donc laisser, thoriquement, 3 octets vides. Dans la pratique, les choses sont un peu plus complexes car mme si la taille du bus mmoire est prpondrante, tous les octets sont directement numrots. Il est donc possible, par l'entremise d'outils inclus dans les microprocesseurs et les compilateurs, d'accder des donnes de 1, 2 ou 4 octets directement. Certaines architectures imposent cependant certaines contraintes d'alignement: les donnes ne peuvent tre stockes qu' des adresses multiples de la taille sur laquelle est code ces donnes et au maximum, des adresses multiples de la taille du bus.

Pour vrier si l'architecture possde une contrainte d'alignement, il sut de compiler et de lancer le programme suivant:
1 int main(void) { 2 struct s { char a, b, c, d, 3 int *pi; 4 pi = (int *) &(t.a); 5 printf("pi = %p, i = %d\n", 6 pi = (int *) &(t.b); 7 printf("pi = %p, i = %d\n", 8 pi = (int *) &(t.c); 9 printf("pi = %p, i = %d\n", 10 pi = (int *) &(t.d); 11 printf("pi = %p, i = %d\n", 12 pi = (int *) &(t.e); 13 printf("pi = %p, f = %d\n", 14 pi = (int *) &(t.f); 15 printf("pi = %p, i = %d\n", 16 pi = (int *) &(t.g); 17 printf("pi = %p, i = %d\n", 18 return 0; 19 } e, f, g, h, i, j;} t;

pi, *pi); pi, *pi); pi, *pi); pi, *pi); pi, *pi); pi, *pi); pi, *pi);

Si le programme se termine normalement, alors l'architecture n'impose pas de contrainte. Dans le cas contraire, le programme s'arrtera brutalement avec un signal de type bus error et gnrera un core.

24 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Pour linux AMD Athlon, le programme tourne normalement. Sur Solaris/UltraSparc, le programme s'arrte avec un "Bus error" ligne 5. A retenir: La mmoire est adressable de plusieurs manires direntes. Lorsque l'architecture impose des contraintes d'alignement, l'adresse d'une donne est un multiple de la taille des donnes adresses si cette taille est infrieure la taille du bus mmoire, ou multiple de la taille du bus . Nous avons vu que le typage constituait un canevas d'interprtation de la mmoire. Rciproquement, n'importe quelle zone mmoire peut tre interprte par un type ou un autre pour peu que l'alignement soit respect.

(Table des matires)

Types composs
Les types composs peuvent tre dnis comme des agrgats de types simples ou/et composs. La dnition de types composs se fait l'aide du mot rserv struct, suivi de la description des dirent composants. Ces types composs dnis par struct fonctionnent comme les types simples en
5 ce qui concerne l'assignation :

1 #include <stdio.h> 2 int main(void) { 3 struct s1 {int a, b;} A, B; 4 A.a = 1, A.b = 2, B.a = 3, B.b = 4; 5 A = B; 6 printf("A.a = %d\nA.b = %d\n", A.a, A.b); 7 return 0; 8 }

donne:
A.a = 3 A.b = 4

Par contre, il est impossible de faire des comparaisons sur ces types complexes (comme par exemple A==B). La squence des composants tient un rle important dans la dnition des types composs. En eet en raison des contraintes d'alignement prcites, les trois structures suivantes n'utiliseront pas la mme quantit de mmoire:
1 #include <stdio.h> 2 struct fin { 3 char a;

25 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 char b; char c; char d; float x; float y; float z; }; struct moyen { char a; char b; float x; char c; char d; float y; float z; }; struct large { char a; float x; char b; float y; char c; float z; char d; }; int main(void) { printf("sizeof(char) = %d\n", printf("sizeof(float) = %d\n", printf("4 * sizeof(char) + 3 * printf("sizeof(fin) = %d\n", printf("sizeof(moyen) = %d\n", printf("sizeof(large = %d\n", return 0; }

http://ilay.org/yann/articles/mem/

sizeof(char)); sizeof(float)); sizeof(float) = %d\n", 4 * sizeof(char) + 3 * sizeof( sizeof(struct fin)); sizeof(struct moyen)); sizeof(struct large));

donne les valeurs suivantes (linux iX86/AMD):


sizeof(char) = 1 sizeof(float) = 4 4 * sizeof(char) + 3 * sizeof(float) = 16 sizeof(fin) = 16 sizeof(moyen) = 20 sizeof(large) = 28

Dans le cas de la structure n , la squence optimise la trace mmoire de la structure. Les 4 caractres sont contigus dans 1 case memoire de 32 bits, suivis de 3 oat dont la taille est ici de 4 octets chacuns.

Dans le cas de la structure large , la trace mmoire est maximale: pour chaque

26 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

caractre, 4 octets sont occups pour 1 seul de rellement utilis.

Dans le cas de la structure moyen , la trace mmoire n'est pas compltement optimise et les 2 couple de char sont cods sur chacun 4 octets.

A retenir: L'ordre des donnes dnies dans une structure inue sur la taille de la mmoire utilise an de respecter les contraintes d'alignement (mme si l'architecture n'en possde a priori pas). De mme que les types simples, les types complexes constituent un canevas d'interprtation de la mmoire. Rciproquement, toute zone de mmoire respectant les contraintes d'alignement peut tre interprte par une structure.
(Table des matires)

Tableaux
Les tableaux sont des zones de mmoires rserves et censes recevoir un nombre maximum prtabli de donnes d'un type prdni. Cependant, un tableau ne possde pas d'indication a priori de sa propre taille. Par exemple :
char a[4];

27 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

va rserver statiquement une zone de mmoire de la pile de 4 fois la taille d'un char . Cette zone est valide jusqu' la fermeture du bloc en cours. Elle est aussi adressable depuis des fonctions appeles par le bloc en cours:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> #include <string.h> void func2(char *string) { strcpy(string, "func2"); } char *func1() { char string[10]; strcpy(string, "func1"); printf("func1 (a): %s\n", string); func2(string); printf("func1 (b): %s\n", string); return string; } int main(void) { char *s; s = func1(); printf("main: %s\n", s); return 0; }

produira quelque chose qui doit ressembler a:


func1 (a): func1 func1 (b): func2 main: H@

Mais il se peut aussi que le programme se termine par un core dump durant l'appel au dernier printf ligne 17 sur certaines plateformes si s est NULL. En fait, la fonction "func1()" retourne un pointeur allou dans la frame 2 (frame correspondant "func1()"). Or, ds que l'on sort de la fonction func1() pour revenir dans main, la frame 2 est dpile (changement de cartographie de la mmoire virtuelle). Les valeurs qui se trouvaient dans les variables alloues sur pile sont donc remplace de manire arbitraire.
Contraitement aux types composs, il n'est pas possible d'assigner un tableau un autre tableau. En effet, le "type tableau" ne connait pas sa taille, il ne peut pas tre manipul comme une structure.

Le type tableau est incomplet. Il n'est en fait qu'une utilisation dguise du concept de pointeur. A retenir: un tableau ne connait pas sa propre taille de manire a apriori. il n'est pas possible d'assigner un tableau un autre tableau. Comme nous le verrons au chapitre suivant, le tableau est un pointeur dguis.

(Table des matires)

Notion de pointeur
28 sur 58 22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Un pointeur est une zone de mmoire qui contient ou est suceptible de contenir une adresse mmoire. Bien qu'il existe des sous types dirents de pointeurs (void *, char *, short *, int *, long *, oat *, double *, pointeurs de pointeurs, pointeurs sur fonctions), tous ces sous types de pointeurs ont la mme taille et sont intercheangeables. Il exite deux oprations de base : & et * & pourrait encore s'crie adresse de et * pourrait s'crire valeur de Il est d'ailleurs tout fait possible d'crire des macros:
#define addressof(x) &(x) #define valueof(x) *(x)

Exemple:
int i = 1; int *pi = NULL;

pi = &i;

/* pi = addressof(i) */

*pi = 2;

/* valueof(pi) = 2 */

(Table des matires)

Pointeurs et tableaux La notion de tableau est intrinsquement lie la notion de pointeur. En eet, si l'on considre la mmoire comme un tableau, le pointeur devient une manire d'adresser ce tableau de manire absolue, alors que le tableau au sens C est adress de manire relative son dbut par un indexe. Un nom de tableau est quivalent un pointeur sur le premir lment du tableau: a[0]f est quivalent *a.

29 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

On peut aussi rfrencer le ime lment d'un tableau a de deux manire: a[i] ou *(a + i). La dnition de tableaux multidimentionnelle passe aussi de manire implicite par l'utilisation des pointeurs: Un tableau bi-dimensionnel est un tableau de pointeurs sur tableaux unidimensionnels: denition statique sur la pile:
float a[10][5];

dnition dynamique et allocation:


float **b; /* allocation d'un tableau de 10 pointeurs sur (float *) */ *b = (float **) malloc(10 * sizeof(float)); for (i = 0; i < 10; i++) /* allocation de 5 float */ b[i] = (float *) malloc(5 * sizeof(float));
(Table des matires)

Pointeurs et structures Les structures peuvent elles aussi tre dsignes par des pointeurs. Il est mme possible d'accder directement un champs d'une structure partir d'un pointeur sur structure. L'oprateur de membre passe alors de . -> :
struct complex {float a; float b} c, *pc; c.a = 1., c.b = 0., pc = &c; pc->a = 2., pc->b = 1.;

Mais ce ne sont pas les seules faons de rfrencer des membres de structures. En eet, il existe une macro osetof() (dnie dans stddef.h) permettant de retrouver l'oset (dcallage) d'un champ par rapport au premier lment de la structure qui le contient. A partir de ce dcallage et en oprant les recasting qui s'imposent, il est possible d'accder tous les champs d'une structure :
#include <stddef.h> #include <stdio.h> #include <string.h> int main(void) { typedef struct { int a; char b[10]; double c; } S; int a_shift, b_shift, c_shift; S s; char *p; p = (char *) &s; a_shift = offsetof(S, a); b_shift = offsetof(S, b); c_shift = offsetof(S, c); printf("offset a = %d\noffset b = %d\noffset c = %d\n", a_shift, b_shift, c_shift);

30 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
*((int *) (p + a_shift)) = 555; strcpy(p + b_shift, "abcdef"); *((double *) (p + c_shift)) = 3.14159;

http://ilay.org/yann/articles/mem/

printf("s.a = %d\ns.b = \"%s\"\ns.c = %lf\n", s.a, s.b, s.c); printf("*(int *) *(int *) (p+a_shift) = %d\n (p+a_shift), (p+b_shift), *(double *) (p+c_shift)); return 0; }

(p+b_shift) = \"%s\"\n*(double *) (p+

donne :
offset a = 0 offset b = 4 offset c = 16 s.a = 555 s.b = "abcdef" s.c = 3.141590 *(int *) (p+a_shift) = 555 (p+b_shift) = "abcdef" *(double *) (p+c_shift) = 3.141590

Pour plus d'exemples, reportez-vous au chapitre "Exemple rcapitulatif"".


(Table des matires)

Pointeurs sur fonctions Il est possible de dnir des variable pointant sur des fonctions. Ces pointeurs sur fonctions sont la base du principe de virualisation et, de manire plus gnrale, de la rutilisation de fonctions quel que soit le type des donnes fournies. Cette rutilisation partir d'un typage faible, voire une absence de typage, constitue une implmentation plus lgante et plus concise que l'utisation des templates du C++. Il est ncessaire, lors de l'usage de pointeurs sur fonctions, de dnir un protocole spcique de passage de paramtres (nombre de ces paramtres). Le premier exemple qui vient l'esprit lorsqu'on parle de pointeur sur fonction est la fonction qsort (dont le prototype est d dans stdlib.h):
void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));

Le variable de type pointeur sur fonction s'appelle compar. Utilisons la fonction qsort:
#include <stdlib.h> #include <stdio.h>

31 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
int float_comp(float *a, float *b) { if (*a > *b) return 1; if (*a < *b) return -1; return 0; }

http://ilay.org/yann/articles/mem/

void arr_print(float *arr) { int i; for (i = 0; i < 10; i++) printf("arr[%d] = %3.1f\n", i, arr[i]); } int main(void) { float arr[10] = {5.1, 4.2, 3.3, 1.4, 7.8, 2.0, 8.9, 9.7, 0.5, 6.6}; printf("Tableau initial:\n"); arr_print(arr); qsort(arr, 10, sizeof(float), float_comp); printf("\nTableau final:\n"); arr_print(arr); return 0; }

donne:
Tableau initial: arr[0] = 5.1 arr[1] = 4.2 arr[2] = 3.3 arr[3] = 1.4 arr[4] = 7.8 arr[5] = 2.0 arr[6] = 8.9 arr[7] = 9.7 arr[8] = 0.5 arr[9] = 6.6 Tableau final: arr[0] = 0.5 arr[1] = 1.4 arr[2] = 2.0 arr[3] = 3.3 arr[4] = 4.2 arr[5] = 5.1 arr[6] = 6.6 arr[7] = 7.8 arr[8] = 8.9 arr[9] = 9.7

Dans cet exemple, la fonction qsort utilise un pointeur sur une fonction de pomparaison. Nous avons vu comment dnir la foncition de comparaison (ici oat_comp) et comment la passer en paramtre la fonction qsort. La compilation du code prcdent produit nanmoins un message d'avertissement cause de la dirence de typage entre la fonction oat_comp() et la fonction attendue par qsort. Ce message peut tre limin de plusieurs facons: en modiant la dnition de la fonction oat_comp:

32 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
int float_comp(void *a, void *b) { if (*(float *)a > *(float *)b) return 1; ...

http://ilay.org/yann/articles/mem/

en recastant la fonction oat_comp lors de l'appel qsort:


qsort(arr, 10, sizeof(float), (int(*)(const void *, const void *)) float_comp);

Il est galement possible de simplier l'criture de la seconde mthode en dnissant un type de pointeur sur fonction:
typedef int (*comp_f)(const float *, const float *);

Le recast de la fonction oat_comp s'crira alors:


qsort(arr, 10, sizeof(float), (comp_t) float_comp);

Les pointeurs sur fonctions sont aussi trs utils pour la dnition de "classes". Les meilleurs exemples de ces techniques se trouvent dans l'implmentations des systmes de chiers du noyau Linux, ou encore dans l'architecture GTK/Gnome. En ce qui concerne le noyau Linux, on pourra regarder le header linux/fs.h, et en particulier la structure address_space_operations (noyau 2.4.18):
struct address_space_operations { int (*writepage)(struct page *); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); /* * ext3 requires that a successful prepare_write() call be followed * by a commit_write() call - they must be balanced */ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ int (*bmap)(struct address_space *, long); int (*flushpage) (struct page *, unsigned long); int (*releasepage) (struct page *, int); #define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */ int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int); };

Cette structure dnit les mthodes communes tous les systmes de chiers. Pour plus d'exemples, reportez-vous au chapitre "Exemple rcapitulatif"".
(Table des matires)

Dsignation des donnes La dsignation de donnes peut s'eectuer de plusieurs manires par valeur, par adresse Dsignation par valeur La dsignation d'une donne par sa valeur se fait soit en appelant le nom de la variable, si celle-ci n'est pas un pointeur vers la donne:
int i = 1;

33 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

i est alors mis pour 1. Si la variable est un pointeur, il est ncessaire de passer par l'opratieur valueof() (*):
int i = 1, *pi; pi = &i; /* pi = addressof(i) */

Alors, *pi est mis pour 1;


(Table des matires)

Dsignation par adresse La dsignation par adresse se fait soit en prenant l'adresse d'une variable par l'oprateur addressof() (&):
float f = 2.;

&f dsigne l'adresse de la variable f. Ou encore, si la variable est un pointeur:


float f = 2., *pf; pf = &f;

pf dsigne l'adresse de f
(Table des matires)

Passages de paramtres L'appel une fonction recopie les valeurs des paramtres sur la pile. On a donc une copie locale des donnes accessibles partir de nouveaux noms de variables, ceux dnis dans le prototype d'appel la fonction. Si une modication de la valeur d'une telle variable est faite, cette modication est locale. Si une variable passe en paramtre est un pointeur et que l'on modie la valeur pointe:
*p = valeur; /*valueof(p) = valeur */

alors, la modication n'est plus locale: soit le programme:


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio.h> void func(int i, int j, int *pk) { printf("&i = %p (%u), &j = %p (%u), &pk = %p (%u)\n", &i, &i, &j, &j, &pk, &pk); *pk = i + j; i = 3, j = 4; printf("i = %d, j = %d, pk = %x (%u), *pk = %d\n", i, j, pk, pk, *pk); } int main(void) { int a = 1, b = 2, c = 0; printf("&a = %p (%u), &b = %p (%u), &c = %p (%u)\n", &a, &a, &b, &b, &c, &c); printf("a = %d, b = %d, c = %d\n", a, b, c); func(a, b, &c); printf("a = %d, b = %d, c = %d\n", a, b, c); return 0; }

&a = 0xbffff4b4 (3221222580), &b = 0xbffff4b0 (3221222576), &c = 0xbffff4ac (3221222572) a = 1, b = 2, c = 0

34 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

&i = 0xbffff490 (3221222544), &j = 0xbffff494 (3221222548), &pk = 0xbffff498 (3221222552) i = 3, j = 4, pk = bffff4ac (3221222572), *pk = 3 a = 1, b = 2, c = 3

Les variables i et j sont bien locales fonction func. La modication de leur valeur n'est que locale. Par contre, le passage d'un pointeur en argument permet la modication de la valeur pointe.
(Table des matires)

Exemple rcapitulatif
Voici un petit exemple rcapitulatif. A vous de retrouver les direntes techniques vues et d'ajouter les commentaires. (ce code compile sans erreur ni warning avec gcc -Wall -ansi -pedantic)
#include <stdlib.h> #include <stdio.h> void * object_new(); void * object_destroy(void *); typedef struct { int type; void * (*destroy)(void *); void * (*new)(); } object_t, *pobject_t; object_t object_defaults() { object_t o; o.type = 1; o.new = object_new; o.destroy = object_destroy; return o; } typedef struct { object_t o; int (*get)(void *);

35 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
int (*set)(void *, int); int i; } int_t, *pint_t; void *object_destroy(void *po) { printf("destroy object_t\n"); if (!po) return NULL; free(po); return NULL; }

http://ilay.org/yann/articles/mem/

void * object_new() { pobject_t po; printf("create object_t\n"); if (!(po = (pobject_t) malloc(sizeof(object_t)))) return NULL; *po = object_defaults(); return (void *) po; } int int_get(void *pi) { if (!pi) return -1; return ((pint_t) pi)->i; } int int_set(void *pi, int i) { if (!pi) return -1; return ((pint_t) pi)->i = i; } void * int_new() { pint_t pi; printf("create int_t\n"); if (!(pi = (pint_t) malloc(sizeof(int_t)))) return NULL; pi->o = object_defaults(); pi->o.type = 2; pi->o.new = int_new; pi->i = 0; pi->get = int_get; pi->set = int_set; return pi; } int main(void) { pobject_t po; pint_t pi; po = (pobject_t) (pi = int_new()); printf("po = %p\npi = %p\n", (void *) po, (void *) pi); printf("type de po: %d\n", po->type); printf("type de pi: %d\n", pi->o.type); pi->set((void *) pi, 555); printf("valeur de pi->i printf("valeur de pi->get(pi)

= %d\n", pi->i); = %d\n", pi->get((void *) pi));

36 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

printf("valeur de ((pint_t) po)->i = %d\n", ((pint_t) po)->i); printf("valeur de ((pint_t) po)->get((void *) po) = %d\n", ((pint_t) po)->get((void *) ((pobject_t) pi)->destroy((void *) pi); return 0; }

donne:
create int_t po = 0x8049aa0 pi = 0x8049aa0 type de po: 2 type de pi: 2 valeur de pi->i valeur de pi->get(pi) valeur de ((pint_t) po)->i valeur de ((pint_t) po)->get((void *) po) destroy object_t
(Table des matires)

= = = =

555 555 555 555

37 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Comment grer la mmoire?


Allocation sur la pile
Lorsque l'on a aaire des constantes, ou des variables bien dnies et xes en terme de taille, et a usage local seulement, l'allocation sur la pile est approprie.

Allocation dynamique
Lorsque les variables ont des tailles non xes ou encore ne sont pas usage local, il est sr d'utiliser l'allocation dynamique.
(Table des matires)

Manipulation dynamique de la mmoire Allocation de la mmoire: malloc()


Prototype:
#include <stdlib.h> void *malloc(size_t size);

Comportement: Malloc prend en argument la taille de la zone mmoire dsire et retourne le pointeur sur la zone alloue ou 0 (pointeur nul) s'il n'y a pas assez d'espace mmoire contigu. Une zone mmoire fraichement alloue par malloc n'est a priori pas initialise et peut contenir n'importe quoi (donnes alatoires provenant d'anciennes applications ayant utilis le mme espace, ou donnes alatoires). Il est donc ncessaire de l'initialiser avec des valeurs appropries (par exemple 0) en fonction du type de dones inserer dans ces zones alloues et / ou en fonction des rgles de programmation utilises. On pourra initialiser l'ensemble de la zone avec la fonction memset(), recopier des zones existantes avec memcpy(), ou encore initialiser les blocs en fonction de leur dcoupage (types, structures, tableaux, ...).

A retenir: Il est impratif de toujours vrier que le pointeur allou est valide. Plus gnralement, il est toujours ncessaire de tester un pointeur pass en argument.

38 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Il ne faut jamais prjuger du contenu d'une zone mmoire aprs son allocation par malloc Il est ncessaire d'initialiser convenablement les zones de mmoire alloues
(Table des matires)

la fonction calloc() Prototype :


#include <stdlib.h> void *calloc(size_t nmemb, size_t size);

Comportement : A la dirence de malloc(), calloc() alloue un tableau de nmemb lements ayant chacun size pour taille. La mmoire alloue est initialise 0. Pour le reste, calloc() fonctionne comme malloc(): si la mmoire a bien t rserve et initialise, calloc() retourne le pointeur sur la zone. Sinon, calloc() returne 0 (pointeur nul).
(Table des matires)

Dsallocation de la mmoire: free()


Prototype :
#include <stdlib.h> void free(void *ptr);

Comportement : La fonction free() annule la rservation d'une zone de mmoire pointe par ptr, alloue par malloc() ou calloc() ou par toute autre fonction rservant de la mmoire, comme strdup() qui duplique une chaine de caractres. Si l'on tente de librer un espace mmoire qui n'a pas t alloue par malloc() ou calloc(), directement ou par le biais d'une fonction appelant malloc() ou calloc(), la fonction free() enverra un signal 11 (SIGSEGV Invalid memory reference ) qui terminera brutalement le programme. La fonction free() n'crase pas la mmoire de la zone.

39 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Il est fortement recommand d'annuler le pointeur qui vient d'tre libr par free(), an de ne pas tenter d'adresser un espace qui pourra tre rutilis. On pourra par exemple rcrire une fonction:
void *my_free(void *ptr) { if (ptr) free(ptr); return NULL; }

et l'utiliser de la manire suivante:


ptr = my_free(ptr);

ou encore crire la macro qui s'utilise de la mme manire que free():


#define FREE(x) { if (x) free(x); x = NULL; }
(Table des matires)

Rallocation de la mmoire : realloc()


Prototype :
#include <stdlib.h> void *realloc(void *ptr, size_t size);

Comportement : La fonction realloc() prend en argument le pointeur sur la zone de mmoire (ptr) dont il faut modier la taille, et la nouvelle taille dsire (size). Si l'opration s'est bien passe, realloc() returne le pointeur sur la zone mmoire. Attention: il est fort possible que le nouveau pointeur soit dirent de l'ancien! En eet, si la zone mmoire doit tre augmente, et que la zone en cours n'est pas assez grande pour supporter la nouvelle taille, realloc() allouera une nouvelle zone de mmoire contigue et recopiera compltement l'ancienne zone. Il est donc impratif de ne pas adresser directement par un pointeur un espace mmoire dont la taille doit/peut tre modie par realloc:

Les zones en rouge sont des zones de mmoire occupes. La zone jaune est la zone de mmoire que nous avons rserv et modi par realloc. Si nous conservons un pointeur sur la zone avant le ralloc, ce pointeur ne sera plus utilisable aprs car in

40 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

adressera une zone non rserve et contenant des donnes alatoires. Si l'opration choue, realloc() retourne 0, mais ne dasalloue pas la zone d'origine. Il est impratif de ne pas rassigner le mme pointeur immdiatement avec le rsultat de realloc() au risque de perdre toutes les donnes en mmoire et de ne jamais pouvoir les librer. Ce qu'il ne faut pas faire:
ptr = realloc(ptr, newsize);

Ce qu'il faut faire:


{ void *p; if ((p = realloc(ptr, newsize))) { /* la rallocation s'est bien passe , l'affectation est sre: */ ptr = p; } else { /* la rallocation a chou, le processus ne peut pas continuer mais la mmoire est encore utilise: */ free (ptr); } return NULL; }
(Table des matires)

Fonctions annexes: memset(), memcpy(), memmove()


Initialisation d'une zone memoire: memset() Prototype:
#include <string.h> void *memset(void *s, int c, size_t n);

Comportement: memset() prend en argument le pointeur sur la zone alloue (s) initialiser, la valeur aecter toute la zone mmoire (c), et le nombre d'octets devant subir le traitement (n). Il est noter que seul le premier octet de la valeur d'initialisation est pris en compte. memset retourne le pointeur d'entre (s).
(Table des matires)

Copie de zone mmoire : memcpy() Prototype:


#include <string.h> void *memcpy(void *dest, const void *src, size_t n);

41 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Comportement: memcpy prend en entre le pointeur zone de mmoire alloue de destination, le poinrteur sur la zone de mmoire cible, et le nombre d'octets devant tre copis. memcpy retourne le pointeur de destination (dest). Attention: dest doit au minimum avoir de l'espace pour les n octets copier. Les deux zones de mmoire ne doivent pas se chevaucher (i.e. src + n < dest ou dest + n < src).
(Table des matires)

Dplacement de zone mmoire: memmove() Prototype:


#include <string.h> void *memmove(void *dest, const void *src, size_t n);

Comportement: La fonction memmove() dplace le contenu d'une zone mmoire vers une autre. Elle prend en argument le pointeur vers la zone mmoire alloue vers laquelle dplacer le contenu mmoire (dest), le pointeur vers la zone de dpart de la copie (src) et le nombre d'octets dplacer. Elle retourne le pointeur vers la zone de destination (dest). Contrairement memcpy(), il est possible que les 2 zones se supperposent.
(Table des matires)

Gestion des chaines de caractres:


La manipulation de chaines de caractres est une source de nombreux problmes dont sont victime autant les programmeurs dbutants que les chevronns. Ces quelques lignes permettrons peut tre certains d'viter quelques cueils. Rappels Une chaine de caractres est un tableau d'octets termin par un octet nul (ou caractre nul = 0 = '\0'). Si l'on veut rserver la mmoire pour la chaine bonjour, monde , il est ncessaire de penser que cette chaine doit en fait s'crire bonjour, monde\0 et rserver l'espace en consquence. La fonction strlen() retourne la taille d'une chaine de caractre sans son terminateur. L'indexe d'un tableau commence toujours par 0 et non par 1. Aussi, lorsque l'on
42 sur 58 22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

rserve 50 chars pour une chaine, le caractre nul devra se trouver au plus l'index 49. Certaines fonctions ncessitent une attention toute particulire: strcpy() Prototype:
#include <string.h> char *strcpy(char *dest, const char *src);

Comportement: La fonction strcpy recopie le contenu de la chaine src vers la chaine alloue pointe par dest et retourne le pointeur vers la chaine de destination (le caractre nul est inclus dans la copie). Mais attention: il est ncessaire au pralable de s'tre assur que la taille rserv dans dest est suprieure ou gale la taille de la chaine pointe par src. Si ce n'est pas le cas, nous risquons d'avoir un crasement d'une zone mmoire. Cet crasement peut modier des donnes stockes sur la pile, ou pire, craser une partie du programme lui mme puisque la dnition de la pile prcde le code dans la mmoire. Ce dfaut est la base de la technique de piratage la plus rpendue: le pirate fournit au programme une chaine assez longue pour empiter sur le code de la fonction et contient un autre code au format binaire qui sera excut au lieu du code de la fonction (voir Linux Mag # ...) strncpy() Prototype:
#include <string.h> char *strncpy(char *dest, const char *src, size_t n);

Comportement: strncpy() prend les mmes arguments que strcpy() plus n, le nombre maximal d'octets recopier. Mais, l encore, attention car strncpy() recopie au plus n caractres sans pour autant tester que le dernier caractre copi est bien NULL. Il est donc ncessaire de s'assurer aprs un strncpy() que le dernier caractre est bien nul:
char* mystrncpy(char *dest, char *src, size_t n) { if (!dest) return 0; if (!src || n <= 1) return *dest = 0; strncpy(dest, src, n); dest[n - 1] = 0; return dest; }

43 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

(Table des matires)

strcat() Prototype:
#include <string.h> char *strcat(char *dest, const char *src);

Comportement: strcat ajoute la chaine dest la chaine src. Il est ncessaire d'tre sr d'avoir rserv assez de place dans la chaine dest pour recevoir la chaine src en plus de son contenu. De mme que pour strncpy, il existe une variation permettant de limiter la longueur de la chaine globale:
char *strncat(char *dest, const char *src, size_t n)

strncat() ne recopie que les n premiers octets de src la n de dest et ajoute 0 la n, 0 n'tant pas pris en compte dans n. Pour ne pas faire de dbordement mmoire, il faut donc que n soit gal la taille rserve de dest, diminu de strlen(dest) et encore diminu de 1 pour le caractre nul nal.
(Table des matires)

sprintf() et snprintf() Prototype


#include <stdio.h> int sprintf(char *str, const char *format, ...);

Comportement Cette fonction imprime remplit une chaine de caractres alloue (str) partir d'un format (format) et, eventuellement, des donnes (...) et retourne le nombre de caractres de la nouvelle chaine (caractre nul nal non compris). Une fois encore, aucun test n'est eectu sur la taille maximale de la chaine de caractres de destination. Pour cette fonction aussi, il existe une parade : la fonction snprintf().
int snprintf(char *str, size_t size, const char *format, ...);

snprintf() tronque la nouvelle chaine str size caractres y compris le caractre nul nal. Dans le cas o la chaine str est infrieure size, la fonction retourne la taille de str. Sinon, la taille de str est size - 1 et la fonction retourne -1. Il existe d'autres groupes de fonctions avec des proprits similaires, telles que strcmp et strncmp, strdup et strndup, vsprintf et vsnprintf (les quivalent de sprintf et snprintf mais dont le le dernier argument est une va_list (voir man vsprintf et man stdarg).
(Table des matires)

44 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Rgles de base
Eviter au maximum les variables globales et les conits possibles sur le nommage des variables globales: Les variables globales constituent une fonctionnalit parfois indispensables, mais elles ont aussi de gros travers: Elles peuvent poser des problmes dans les programmes rentrant , Elles risquent de masquer des bugs lors de passage de paramtres, Elles risquent de rentrer en conit avec d'autres variables. Si malgr tout, l'emploi de variables globales se fait sentir, il est alors prfrable de : Dnir ces variables de manire statique (static) an de restreindre la porte de la variable au chier en cours, Nommer ces variables de manire ce qu'elles aient la plus faible probabilit de renter en conit avec d'autres variables. On pourra par exemple utiliser comme prxe un code correspondant au nom du chier, et ajouter en dbut et en n de nom des _ . Cette typologie est concise et vite d'avoir ajouter un prxe de porte sur toutes les variables (l pour local et g pour global). Exemple:
static int _mod_today_;

Eviter l'allocation statique en dehors de l'utilisation locale de donnes Eviter l'allocation statique pour des tailles variables de donnes Penser au caractre nul des chaines de caractres Utiliser de prfrence les fonctions de manipulation de chaine de caractres vriant la taille des chaines alloues (strncpy, strncat, strncmp, snprinf, vsnprintf, ...) Toujours initialiser un pointeur 0 (NULL) Tester systmatiquement les pointeurs aprs malloc Tester systmatiquement les pointeurs passs en paramtres Tester que le retour de la fonction realloc n'est pas NULL Toujours dsallouer avec free() la mmoire alloue avec malloc() Toujours remettre 0 (NULL) les pointeurs dallous par free()
(Table des matires)

45 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Erreurs lies la mauvaise utilisation de la mmoire


Drfrencement d'un pointeur null
L'erreur la plus frquente est la tentative de rrfrencement du pointeur nul. Elle se produit dans plusieurs cas : Dfaut d'allocation, Dfaut d'initialisation, Dfaut de test de valeur nulle. Ces cas ne sont ni exhaustifs, ni mutuellement exclusifs. Un pointeur null pointe vers l'adresse 0x0. Celle-ci est protge et ne peut pas tre utilise, ni en lecture, ni en criture. Si un pointeur pointe vers 0x0 et que le programme tente de drfrencer le pointeur (i.e. d'aller voir l'adresse 0x0), il s'ensuit systematiquement un erreur de segmentation mmoire :
% cat > defre0.c int main() { char *p = 0; p[0] = 1; } ^D % cc deref0.c -o deref0 % deref0 zsh: segmentation fault (core dumped) % echo $? 139 %

deref0

Pour utiliser un pointeur, il est ncessaire qu'il pointe sur une adresse correcte. Pour viter ce genre d'erreur, il est ncessaire de toujours allouer un pointeur :
char *p; p = (char *) malloc(12);

ou de lui assigner une adresse valide :


char buf[512]; char *p; p = buff;

Il est aussi ncessaire de tester la cohrence (au moins partielle) d'un pointeur lorsque l'on ne sait pas quelle valeur il peut avoir :
void myfunc(char *str) { char *p; p = (char *) malloc(12); /* check p was correctly initialized : */ if (p) { ... } else { fprintf(stderr, "p was not allocated (p = %x)\n", p); perror("reason: "); } if (str) { ... } else {

46 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/
fprintf(stderr, "str is null and therefore cannot be used!!!\n")

Il est important de noter qu'un pointeur non nul n'implique pas pour autant sa validit.

Passage d'un argument par valeur


Une autre erreur trs frquente est le passage d'un argument par sa valeur. Une fonction est suppose changer la valeur d'une variable. La variable est modie dans la fonction, mais se retrouve inchange dans juste aprs le retour :
#include <stdio.h> void set(int i) { printf("set : i = 3; printf("set : } int main(void) { int i; i = 2; printf("main: i set(i); printf("main: i return 0; }

i = %d\n", i); i = %d\n", i);

= %d\n", i); = %d\n", i);

donne :
main: set : set : main: i i i i = = = = 2 2 3 2

Le passage par valeur recopie la valeur. Il ne faut donc pas confondre la variable i l'intrieur de la fonction set avec le i l'intrieur de la fonction main! D'ailleurs pour s'en convaincre :
#include <stdio.h> void set(int i) { printf("set : printf("set : i = 3; printf("set : } int main(void) { int i; i = 2; printf("main: printf("main: i = set(i); printf("main: i = return 0; }

&i = %x\n", &i); i = %d\n", i); i = %d\n", i);

&i = %x\n", &i); %d\n", i); %d\n", i);

donne :
main: main: set : set : set : &i = ffbef4d8 i = 2 &i = ffbef4bc i = 2 i = 3

47 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
main: i = 2

http://ilay.org/yann/articles/mem/

Si l'on veut modifer une variable dans une sous-fonction, il est ncessaire de passer le pointeur sur la variable, plutt que la variable elle mme.
#include <stdio.h> void set(int *i) { if (!i) { printf("invalid pointer\n"); return; } printf("set : i = %x\n", i); printf("set : *i = %d\n", *i); *i = 3; printf("set : *i = %d\n", *i); } int main(void) { int i; i = 2; printf("main: &i = %x\n", &i); printf("main: i = %d\n", i); set(&i); printf("main: i = %d\n", i); return 0; }

donne :
main: main: set : set : set : main: &i = ffbef4d8 i = 2 i = ffbef4d8 *i = 2 *i = 3 i = 3

Utilisation d'une variable non initialise


L'utilisation d'une variable non initialise peut avoir des consquences facheuses. En eet, nous prenons souvent pour postulat que toute variable non initialise est mise 0. Dans certains cas, le postulat fonctionne. Mais ce n'ai qu'un fait du hasard car la remise zero n'est pas automatique. Il est possible que la zone fraichement alloue ait t auparavent dj utilise : pour s'en convaincre :
#include #include int main(void) { char *a = NULL; char *b = NULL; if (!(a = (char *) malloc(12))) { fprintf(stderr, "cannot reserve memory for a\n"); return 1; } strcpy(a, "0123456789A"); printf("a = \"%s\"\n", a); free(a); if (!(b = (char *) malloc(12))) { fprintf(stderr, "cannot reserve memory for b\n"); return 2;

48 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
} printf("b = \"%s\"\n", b); return 0; }

http://ilay.org/yann/articles/mem/

donne
a = "0123456789A" b = "0123456789A"

pour remdier au problme, on pourra, dans le cas d'une chaine de caractres, initialiser b de la manire suivante: *b = 0; ou b[0] = '\0'; Qui sont 2 expression rigoureusement quivalentes. En revanche memset(b, 0, 12); n'initialisera pas seulement le 1er octet de la chaine 0, mais les 12 octets rservs.

Adressage sur la pile


L'adressage sur la pile ne pose pas de problme quant on comprend comment il fonctionne. Mais il arrive de voir ce genre de choses :
#include <stdio.h> #include <string.h> char *init_string() { char buff[16]; strcpy(buff, "premire chaine"); return buff; } void print_string(char *str) { printf("string is = \"%s\"\n", str); } int main(void) { char *str; str = init_string(); print_string(str); return 0; }

donne sous Solaris :


string is = "dine"

voyons ce qui ce passe :


dbx% dis main 0x000107f0: main : 0x000107f4: main+0x0004: 0x000107f8: main+0x0008: 0x000107fc: main+0x000c: 0x00010800: main+0x0010: 0x00010804: main+0x0014: 0x00010808: main+0x0018: 0x0001080c: main+0x001c: 0x00010810: main+0x0020: 0x00010814: main+0x0024: dbx% stop in main (2) stop in main dbx% run Running: addpile save call nop st ld call or ba st ba %sp, -0x68, %sp init_string %o0, [%fp - 0x8] [%fp - 0x8], %l0 print_string %l0, %g0, %o0 main+0x2c %g0, [%fp - 0x4] main+0x2c

49 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
(process id 26360) stopped in main at line 13 in file "addpile.c" 13 str = init_string(); dbx% ex $sp/64 0xffbef3f8: 0xff33c5a8 0x00000000 0x00000000 0x00000000 0xffbef408: 0x00000000 0x00000000 0x00000000 0xff3e66b4 0xffbef418: 0x00000001 0xffbef4c4 0xffbef4cc 0x00020800 0xffbef428: 0x00000000 0x00000000 0xffbef460 0x00010738 0xffbef438: 0x00000000 0x00000000 0x00000003 0xffbef4c4 0xffbef448: 0x00000004 0xffbef4cc 0x00000005 0xffbef610 0xffbef458: 0x00000000 0x00000000 0x00000001 0xffbef4c4 0xffbef468: 0xffbef4cc 0x00020800 0xffbef4cc 0x00000000 0xffbef478: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef488: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef498: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef4a8: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef4b8: 0x00000000 0x00000000 0x00000001 0xffbef688 0xffbef4c8: 0x00000000 0xffbef6aa 0xffbef6b7 0xffbef7af 0xffbef4d8: 0xffbef7ba 0xffbef7e6 0xffbef7f1 0xffbef7fc 0xffbef4e8: 0xffbef80d 0xffbef819 0xffbef825 0xffbef846 dbx% p &str &str = 0xffbef458 dbx% step stopped in init_string at line 5 in file "addpile.c" 5 strcpy(buff, "premire chaine"); dbx% dbx% print &buff &buff = 0xffbef3e4 dbx% ex $sp/64 0xffbef380: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef390: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef3a0: 0x00000000 0xff340060 0xff33c590 0x00000300 0xffbef3b0: 0x000239b0 0xff29bb60 0xffbef3f8 0x000107f4 0xffbef3c0: 0x00000000 0xffbef4c4 0xffbef4cc 0x00010034 0xffbef3d0: 0xff3b10f0 0x000006ee 0xff3e6da4 0xff3b17de 0xffbef3e0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xff33c5a8 0x00000000 0xffbef3f0: 0xffbef400: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef410: 0x00000000 0xff3e66b4 0x00000001 0xffbef4c4 0xffbef420: 0xffbef4cc 0x00020800 0x00000000 0x00000000 0xffbef430: 0xffbef460 0x00010738 0x00000000 0x00000000 0xffbef440: 0x00000003 0xffbef4c4 0x00000004 0xffbef4cc 0xffbef450: 0x00000005 0xffbef610 0x00000000 0x00000000 0xffbef460: 0x00000001 0xffbef4c4 0xffbef4cc 0x00020800 0xffbef470: 0xffbef4cc 0x00000000 0x00000000 0x00000000 dbx% n stopped in init_string at line 6 in file "addpile.c" 6 return buff; dbx% ex $sp/64 0xffbef380: 0xffbef3e4 0x0001086c 0x00000000 0x00000000 0xffbef390: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef3a0: 0x00000000 0xff340060 0xff33c590 0x00000300 0xffbef3b0: 0x000239b0 0xff29bb60 0xffbef3f8 0x000107f4 0xffbef3c0: 0x00000000 0xffbef4c4 0xffbef4cc 0x00010034 0xffbef3d0: 0xff3b10f0 0x000006ee 0xff3e6da4 0xff3b17de 0xffbef3e0: 0x00000000 0x7072656d 0x69687265 0x20636861 0xffbef3f0: 0x696e6500 0x00000000 0xff33c5a8 0x00000000 0xffbef400: 0x00000000 0x00000000 0x00000000 0x00000000

http://ilay.org/yann/articles/mem/

str area

return address in main

buff area

return address in main();

buff area set

50 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
0xffbef410: 0x00000000 0xff3e66b4 0x00000001 0xffbef4c4 0xffbef420: 0xffbef4cc 0x00020800 0x00000000 0x00000000 0xffbef430: 0xffbef460 0x00010738 0x00000000 0x00000000 0xffbef440: 0x00000003 0xffbef4c4 0x00000004 0xffbef4cc 0xffbef450: 0x00000005 0xffbef610 0x00000000 0x00000000 0xffbef460: 0x00000001 0xffbef4c4 0xffbef4cc 0x00020800 0xffbef470: 0xffbef4cc 0x00000000 0x00000000 0x00000000 dbx% ex 0xffbef3e4 0xffbef3e4: 0x7072656d dbx% n stopped in init_string at line 7 in file "addpile.c" 7 } dbx% n stopped in main at line 14 in file "addpile.c" 14 print_string(str); dbx% print -f%x $sp $sp = ffbef3f8 dbx% ex 0xffbef380/64 0xffbef380: 0xffbef3e4 0x0001086c 0x00000000 0x00000000 0xffbef390: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef3a0: 0xffbef3e4 0xff340060 0xff33c590 0x00000300 0xffbef3b0: 0x000239b0 0xff29bb60 0xffbef3f8 0x000107f4 0xffbef3c0: 0x00000000 0xffbef4c4 0xffbef4cc 0x00010034 0xffbef3d0: 0xff3b10f0 0x000006ee 0xff3e6da4 0xff3b17de 0xffbef3e0: 0x00000000 0x7072656d 0x69687265 0x20636861 0xffbef3f0: 0x696e6500 0xffbef3e4 0xff33c5a8 0x00000000 0xffbef400: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef410: 0x00000000 0xff3e66b4 0x00000001 0xffbef4c4 0xffbef420: 0xffbef4cc 0x00020800 0x00000000 0x00000000 0xffbef430: 0xffbef460 0x00010738 0x00000000 0x00000000 0xffbef440: 0x00000003 0xffbef4c4 0x00000004 0xffbef4cc 0xffbef450: 0x00000005 0xffbef610 0xffbef3e4 0x00000000 0xffbef460: 0x00000001 0xffbef4c4 0xffbef4cc 0x00020800 0xffbef470: 0xffbef4cc 0x00000000 0x00000000 0x00000000 dbx% p str p str str = 0xffbef3e4 "premire chaine" dbx% s stopped in print_string at line 9 in file "addpile.c" 9 printf("string is = \"%s\"\n", str); dbx% print -f%x $sp $sp = ffbef398 dbx% ex 0xffbef380/64 0xffbef380: 0xffbef3e4 0xffbef390: 0x00000000 0xffbef3a0: 0x00000000 0xffbef3b0: 0x00000000 0xffbef3c0: 0xff33c590 0xffbef3d0: 0xffbef3f8 0xffbef3e0: 0x00000000 0xffbef3f0: 0x696e6500 0xffbef400: 0x00000000 0xffbef410: 0x00000000 0xffbef420: 0xffbef4cc 0xffbef430: 0xffbef460 0xffbef440: 0x00000003 0xffbef450: 0x00000005

http://ilay.org/yann/articles/mem/

stack pointer back to main's st

saved frame pointer (pointer to

str points to &buff

stack pointer for print_string(

0x0001086c 0x00000000 0x00000000 0x00000000 0x00000300 0x00010804 0x7072656d 0xffbef3e4 0x00000000 0xff3e66b4 0x00020800 0x00010738 0xffbef4c4 0xffbef610

0x00000000 0x00000000 0x00000000 0xffbef3e4 0x000239b0 0xff3e6da4 0x69687265 0xffbef3e4 0x00000000 0x00000001 0x00000000 0x00000000 0x00000004 0xffbef3e4

0x00000000 0x00000000 0x00000000 0xff340060 0xff29bb60 0xff3b17de 0x20636861 0x00000000 0x00000000 0xffbef4c4 0x00000000 0xffbef3e4 0xffbef4cc 0x00000000

saved fp and return address in string is still there!

51 sur 58

22/01/2013 22:46

Gestion de la mmoire en C
0xffbef460: 0x00000001 0xffbef4c4 0xffbef4cc 0x00020800 0xffbef470: 0xffbef4cc 0x00000000 0x00000000 0x00000000 dbx% n string is = "" stopped in print_string at line 10 in file "addpile.c" 10 } dbx% ex 0xffbef380/64 0xffbef380: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef390: 0xffbef398 0x000107c8 0x0001087c 0xffbef3e4 0xffbef3a0: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef3b0: 0x00000000 0x00000000 0xffbef3e4 0xff340060 0xffbef3c0: 0xff33c590 0x00000300 0x000239b0 0xff29bb60 0xffbef3d0: 0xffbef3f8 0x00010804 0xff3e6da4 0xff3b17de 0xffbef3e0: 0xffbef3e4 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef3e4 0xffbef3e4 0x00000000 0xffbef3f0: 0xffbef400: 0x00000000 0x00000000 0x00000000 0x00000000 0xffbef410: 0x00000000 0xff3e66b4 0x00000001 0xffbef4c4 0xffbef420: 0xffbef4cc 0x00020800 0x00000000 0x00000000 0xffbef430: 0xffbef460 0x00010738 0x00000000 0xffbef3e4 0xffbef440: 0x00000003 0xffbef4c4 0x00000004 0xffbef4cc 0xffbef450: 0x00000005 0xffbef610 0xffbef3e4 0x00000000 0xffbef460: 0x00000001 0xffbef4c4 0xffbef4cc 0x00020800 0xffbef470: 0xffbef4cc 0x00000000 0x00000000 0x00000000 dbx%

http://ilay.org/yann/articles/mem/

abracadabra...

pfffft... no more string :(

On voit trs nettement sur cet exemple que la pile est assez versatile. La frame de la fonction init_string() est rutilise, donc crase, par la frame de la fonction print_string(). Le persistance des donnes pointes par la variable str dans la fonction main() n'est que fortuite. L'utilisation de pointeur sur une variable de pile n'est possible que dans les sous fonctions de la fonction o la variable sur pile est dnie. En eet, la frame de la pile d'une fonction n'est persistante QUE tant que l'on n'est pas encore ressorti de la fonction.

Dpassement de l'espace allou (leak)


strcpy, strcat, sprintf ..., problme de pointeur (pointeur libr mais pas remis 0 Le dpassement de mmoire (leak ou fuite) peut avoir des consquences trs diverses et alatoires. Elles n'ont pas toujours les mmes consquences en fonction de l'ampleur de la fuite et de l'endroit o se trouve la mmoire. sur le tas sur le segment .bss, sur la pile!!!

fuite sur le segment .bss


fuite de petite taille Dans ce premier exemple, nous utiliserons deux variables globales statiques an de mieux mettre en valeur le problme de fuite. La pemire sera la celle utiliser pour le dbordement, et la seconde, place juste derrire dans la mmoire, servira a "ponger" le dbordement.
% cat > bss_leak.c #include <stdio.h> #include <string.h>

52 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

static char buff[5]; static char oops[5]; int main(void) { strcpy(buff, "0123"); *oops = 0; printf("buff = \"%s\"\noops strcpy(oops, "oops"); printf("buff = \"%s\"\noops strcpy(buff, "01234"); printf("buff = \"%s\"\noops strcpy(buff, "012345"); printf("buff = \"%s\"\noops return 0; } ^D % cc -g bss_leak.c -o bss_leak

= \"%s\"\n", buff, oops); = \"%s\"\n", buff, oops); = \"%s\"\n", buff, oops); = \"%s\"\n", buff, oops);

Vrions que les variables sont bien dnies dans le segment .bss :
% elfdump bss_leak | egrep "buff|oops" [11] 0x00020a5d 0x00000005 OBJT GLOB [19] 0x00020a58 0x00000005 OBJT GLOB [53] 0x00020a5d 0x00000005 OBJT GLOB [61] 0x00020a58 0x00000005 OBJT GLOB [11] $XAhCA_K7TOEBklT.oops [19] $XAhCA_K7TOEBklT.buff D D D D 0 0 0 0 .bss .bss .bss .bss $XAhCA_K7TOEBklT.oops $XAhCA_K7TOEBklT.buff $XAhCA_K7TOEBklT.oops $XAhCA_K7TOEBklT.buff

Le lancement de bss_leak donne :


bss_leak buff = "0123" oops = "" buff = "0123" oops = "oops" buff = "01234" oops = "" buff = "012345" oops = "5"

L'criture dans bu dpasse la taille dnie pour buff. Comme oops est localis la suite de buff, les octets surnumraires se retrouvent dans oops.
% dbx bss_leak Reading bss_leak Reading ld.so.1 Reading libc.so.1 Reading libdl.so.1 Reading libc_psr.so.1 dbx% stop in main (2) stop in main dbx% run Running: bss_leak (process id 12257) stopped in main at line 8 in file "bss_leak.c" 8 strcpy(buff, "0123"); dbx% p &buff &buff = 0x20a58 dbx% p &oops &oops = 0x20a5d

53 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

dbx% ex 0x20a58/3 0x00020a58: buff : 0x00000000 0x00000000 0x00000000 dbx% next stopped in main at line 9 in file "bss_leak.c" 9 *oops = 0; dbx% ex 0x20a58/3 0x00020a58: buff : 0x30313233 0x00000000 0x00000000 La chaine buff contient "0123" et est termine par un caractre nul dbx% next stopped in main at line 10 in file "bss_leak.c" 10 printf("buff = \"%s\"\noops = \"%s\"\n", buff, oops); dbx% next buff = "0123" oops = "" stopped in main at line 11 in file "bss_leak.c" 11 strcpy(oops, "oops"); dbx% next stopped in main at line 12 in file "bss_leak.c" 12 printf("buff = \"%s\"\noops = \"%s\"\n", buff, oops); dbx% ex 0x20a58/3 0x00020a58: buff : 0x30313233 0x006f6f70 0x73000000 la chaine oops contient maintenant "oops" et est terminue par un caractre nul dbx% next next buff = "0123" oops = "oops" stopped in main at line 13 in file "bss_leak.c" 13 strcpy(buff, "01234"); dbx% next stopped in main at line 14 in file "bss_leak.c" 14 printf("buff = \"%s\"\noops = \"%s\"\n", buff, oops); dbx% ex 0x20a58/3 0x00020a58: buff : 0x30313233 0x34006f70 0x73000000 le caractre nul de la chaine buff est positionn sur le premier caractre de la chaine oops, qui semble maintenant vide dbx% next buff = "01234" oops = "" stopped in main at line 15 in file "bss_leak.c" 15 strcpy(buff, "012345"); dbx% next stopped in main at line 16 in file "bss_leak.c" 16 printf("buff = \"%s\"\noops = \"%s\"\n", buff, oops); dbx% ex 0x20a58/3 0x00020a58: buff : 0x30313233 0x34350070 0x73000000 la chaine buff contient maintenant "012345", mais le 5 et le caractre nul son situs sur les 2 premiers caractres de la chaine oops dbx% next buff = "012345" oops = "5" stopped in main at line 17 in file "bss_leak.c" 17 return 0;

54 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

fuite sur le tas


Pour des fuites sur le tas, on peut avoir soir des donnes corrompues (achage de valeurs alatoires, chaines bizarres) pour des fuites de petites tailles l'intrieur de zones alloues pour des structures par exemple. Quand la taille de la fuite dpasse la taille relle du block, il faut alors s'attendre de gros ennuis. En eet, la longeur de zone alloue peut se trouver modie, ou encore, la zone suivante peut se retrouver corrompue (pointeur vers la zone suivante). Si le bloc suivant est un block libre, le pointeur sur le block libre suivant sera donc alatoire et risque de faire planter le malloc suivant. Sinon, les problmes risquent d'arriver lors du free() des blocks suivants ou en core lors de l'utilisation des donnes du block en cours, ou suivant.

fuite sur la pile free() sans malloc() malloc() sans free()


(ou allocation de mmoire par une fonction sans dsallocation -strdup()-),

Adressage d'une zone ralloue Adressage d'une zone non aligne


(pour les architectures avec contraintes fortes d'alignement). Symptomes: Achage de chaines de caractres erronns Donnes invalides, corrompues ou alatoires boucles trop longues/trop courtes Plantage sur free() Plantage sur malloc() Plantage pendant l'adressage d'un lment d'une structure Plantage un endroit donn avec ou sans dbugger Plantage un endroit donn durant l'execution et absence de plantage sous dbugger ou plantage un autre endroit sous dbugger

55 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Bus error Problme d'alignement Segmentation fault


(Table des matires)

56 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Notes
1 voir "Linux Kernel Hacker's Guide" l'url http://en.tldp.org/LDP/khg/HyperNews /get/khg.html ou encore "the Linux Kerneli" http://en.tldp.org/LDP/khg/HyperNews/get/khg.html 2Brian W. Kernigan et Dennis M. Richie, dans "The C Programming Language font tat au chapitre 2.2, page 34 de la premire dition, 1978, d'une taille de 9bits pour les char sur les machines de type Honeywell 6000 3Le type long long a t introduit dans la version ANSI C99 des spcication ANSI pour le langage C 4Ces adresses sont donnes titre d'exemple. Elle peuvent varier d'un programme un autre et d'une machine une autre. 4Cette fonctionnalit n'tait pas prsente la base, mais prvue (cf. Brian W. Kernighan & Dennis M. Richie dans The C Programming Language paragraphe 14.1 de la page 209 de premire dition 1978): Other opterations, such as assigning from or to it or passing it as a parameter, draw an error message. In the future, it is expected that these operations, but not necessarily others, will be allowed Les autres oprations, comme l'assignation depuis ou vers une structure, ou le passage d'une structure en paramtre [d'une fonction] gnrent un message d'erreur. Il est vraissemblable que ces oprations, mais pas ncessairement d'autres, viendront tre autorises Cette fonctionnalit est apparue avec le standard ANSI C89..
(Table des matires)

57 sur 58

22/01/2013 22:46

Gestion de la mmoire en C

http://ilay.org/yann/articles/mem/

Rfrences
The C Programming Language, Brian W. Kernigan et Dennis M. Richie, ISBN 0131101633, 1978, Prentice-Hall LE LANGAGE C, NORME ANSI, Brian W. Kernigan et Dennis M. Richie, ISBN 2100051164, 2me dition, 1997, Dunod.
(Table des matires)

Liens Dbugger mmoire

58 sur 58

22/01/2013 22:46

Вам также может понравиться