Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so:laboratoare:laborator-05 [2019/03/16 22:25]
ioana_elena.ciornei
so:laboratoare:laborator-05 [2020/03/24 00:28] (current)
andrei.baronescu [Exercițiul 6 - Stack overflow]
Line 9: Line 9:
  
   * TLPI - Chapter 7, ''​Memory Allocation''​   * TLPI - Chapter 7, ''​Memory Allocation''​
 +
 +===== Link-uri către secțiuni utile =====
 +
 +  * [[#​Gestiunea memoriei]]
 +  * [[#Spațiul de adresă al unui proces]]
 +  * [[#​Alocarea/​Dealocarea memoriei]]
 +  * [[#Lucru cu memoria - Probleme]]
 +    * [[#GDB - Detectarea zonei de acces nevalid de tip page fault]]
 +    * [[#mcheck - verificarea consistenței heap-ului]]
 +  * [[#Leak-uri de memorie]]
 +    * [[#​Valgrind]]
 +    * [[#mtrace]]
 +    * [[#Dublă dealocare]]
 +  ​
  ===== Gestiunea memoriei =====  ===== Gestiunea memoriei =====
  
Line 23: Line 37:
  
 Este, în consecință,​ fundamentală cunoașterea contextului în care acționează subsistemul de gestiune a memoriei și înțelegerea interfeței puse la dispoziție programatorului de către sistemul de operare. Este, în consecință,​ fundamentală cunoașterea contextului în care acționează subsistemul de gestiune a memoriei și înțelegerea interfeței puse la dispoziție programatorului de către sistemul de operare.
 +
 ===== Spațiul de adresă al unui proces ===== ===== Spațiul de adresă al unui proces =====
  
Line 841: Line 856:
  
 ====== Exerciții ====== ====== Exerciții ======
- 
-===== Exercițiul 0 - Joc interactiv (2p) ===== 
- 
-  * Detalii desfășurare [[http://​ocw.cs.pub.ro/​courses/​so/​meta/​notare#​joc_interactiv|joc]]. 
- 
- 
  
  
Line 892: Line 901:
 ==== Exercițiul 4 - Rezolvarea unei probleme de tip Segmentation Fault ==== ==== Exercițiul 4 - Rezolvarea unei probleme de tip Segmentation Fault ====
  
-Intrați în directorul ''​4-gdb''​ și inspectați sursa. Programul ar trebui să citescă un mesaj de la ''​stdin''​ și să-l afișeze. Compilați și rulați sursa. Rulați încă o dată programul din ''​gdb''​ (revedeți [[so:​laboratoare-2013:​resurse:​gdb#​rulare gdb|rularea unui program din gdb]]).+Intrați în directorul ''​4-gdb''​ și inspectați sursa. Programul ar trebui să citescă un mesaj de la ''​stdin''​, să îi transforme fiecare literă în majusculă ​și apoi să-l afișeze. Compilați și rulați sursa.
  
-Pentru a identifica exact unde crapă programul ​folosiți comanda ​[[http://​inside.mines.edu/​fs_home/​lwiencke/​elab/​gdb/​gdb_42.html ​backtrace]]. Pentru detalii despre comenzile ​din gdb folosițcomanda ''​help''​:<code bash> +Rulați încă o dată programul ​din ''​gdb''​ (revedeți [[so:​laboratoare-2013:​resurse:gdb#rulare gdb|rularea unui program ​din gdb]] ș ​[[#​acces nevalid | detectarea unui acces nevalid de tip page fault]]): 
-(gdb) help +<code bash> 
-</code>+(gdb) run 
 +Starting program: ​/home/​student/​lab05/​skel/​lin/​4-gdb/​fault  
 +Give input string:text
  
-Schimbațframe-ul curent cu frame-ul funcției ''​main''​ (revedeți [[#acces nevalid | detectarea unui acces nevalid de tip page fault]]):<code bash> +Program received signal SIGSEGV, Segmentation fault. 
-(gdb) frame main+0x0000555555554809 in upper_string (msg=0x0) at fault.c:​27 
 +27              while (msg[i] != '\0') { 
 +(gdb) bt 
 +#0  0x0000555555554809 in upper_string (msg=0x0) at fault.c:27 
 +#1  0x0000555555554835 in main (at fault.c:40 
 +(gdb) 
 </​code>​ </​code>​
  
-Inspectați valoarea variabilei ''​buf'':<​code bash> 
-(gdb) print buf 
-</​code>​ 
  
-Acum dorim să vedem de ce este ''​buf = NULL'',​ urmărind pașii:+Acum dorim să vedem de ce este ''​msg = NULL'',​ urmărind pașii:
    * Omorâți actualul proces:<​code bash>    * Omorâți actualul proces:<​code bash>
 (gdb) kill (gdb) kill
 </​code>​ </​code>​
-   * Puneți un breakpoint la începutul funcției ''​main'':<​code bash> +   * Puneți un breakpoint la începutul funcției ''​read_message'':<​code bash> 
-(gdb) break main+(gdb) break read_message
 </​code>​ </​code>​
-   ​* ​Rulați programul și inspectați valoarea lui ''​buf'' ​înainte și după apelul funcției ​''​malloc'' ​(folosiți ''​next''​ pentru a trece la instrucțiunea următoare, fără a urmări apelul ​de funcție).+   ​* ​Finalizați funcția:<​code bash> 
 +(gdb) finish 
 +Run till exit from #0  read_message () at fault.c:​14 
 +Give input string:​text 
 +0x0000555555554825 in main () at fault.c:​38 
 +38              message = read_message();​ 
 +Value returned is $1 = 0x0 
 +</​code>​ 
 + 
 +   * După cum puteți vedea, ​''​read_message'' ​returneză ''​0x0'' ​în loc de adresa mesajului citit.
    * Explicați sursa erorii, apoi rezolvați-o.    * Explicați sursa erorii, apoi rezolvați-o.
  
 +<note tip>
 +  * https://​stackoverflow.com/​questions/​40290049/​why-does-gcc-return-0-instead-of-the-address-of-a-stack-allocated-variable
 +  * https://​github.com/​gcc-mirror/​gcc/​commit/​f22a2cb7500755d69ee5965985d8621c735579c0
 +</​note>​
 ==== Exercițiul 5 - Lucru cu memoria - Valgrind ==== ==== Exercițiul 5 - Lucru cu memoria - Valgrind ====
  
Line 932: Line 958:
       * în funcția ''​take_snapshot''​ salvați în structura de date ce reține imaginea stivei câmpurile adresă și valoare.       * în funcția ''​take_snapshot''​ salvați în structura de date ce reține imaginea stivei câmpurile adresă și valoare.
  
-Ce reține structura ''​stack_elements''?​+Ce reține structura ''​stack_element''?​
  
 Funcția ''​f2''​ pune pe stivă un vector de 3 întregi. În ce ordine sunt puse elementele vectorului pe stivă? Funcția ''​f2''​ pune pe stivă un vector de 3 întregi. În ce ordine sunt puse elementele vectorului pe stivă?
Line 939: Line 965:
  
 <note tip> <note tip>
-Dezasamblați executabilul. Observați că înainte de call ''​f2''​ se pune pe stivă ''​instruction pointer-ul(eip)''​ care este adresa primului byte de după call. La intrarea în funcție controlul s-a transmis de la caller la callee. Acesta din urmă salvează vechiul ''​base pointer(ebp)''​ iar ebp va conține adresa vârfului stivei.+Dezasamblați executabilul. Observați că înainte de call ''​f2''​ se pune pe stivă ''​instruction pointer-ul(eip) / rip (x86-64)''​ care este adresa primului byte de după call. La intrarea în funcție controlul s-a transmis de la caller la callee. Acesta din urmă salvează vechiul ''​base pointer(ebp) / rbp (x86-64)''​ iar ebp va conține adresa vârfului stivei.
 </​note>​ </​note>​
  
-Folosiți gdb pentru a afla informații despre cum este pus array-ul pe stivă ​și ce index trebuie suprascris: <code bash>+Folosiți gdb pentru a afla informații despre cum este pus array-ul pe stivă: <code bash>
 (gdb) break f2 (gdb) break f2
 (gdb) run (gdb) run
Line 948: Line 974:
 </​code>​ </​code>​
  
-Aveți grijă la proctectori ​de stivă [[https://​mudongliang.github.io/​2016/​05/​24/​stack-protector.html|Stack protectors]].+Aveți grijă la protectori ​de stivă [[https://​mudongliang.github.io/​2016/​05/​24/​stack-protector.html|Stack protectors]].
  
-In funcția ''​f2''​ bufferul ''​v''​ se află pe stivă sub adresa de return a funcției (IP-ul la care se întoarce programul dupa ce execută ''​f2''​). Scriind în bufferul ''​v''​ mai multe elemente decat are acesta alocate pe stivă, vom putea suprascrie adresa de return a lui ''​f2''​ cu o alta adresă (aici, adresa funcției ''​show_message''​). Atenție, după adresa de return este salvat pe stivă base pointerul și abia apoi găsim și bufferul ''​v''​.+In funcția ''​f2''​ bufferul ''​v''​ se află pe stivă sub adresa de return a funcției (IP-ul la care se întoarce programul dupa ce execută ''​f2''​). Scriind în bufferul ''​v''​ mai multe elemente decat are acesta alocate pe stivă, vom putea suprascrie adresa de return a lui ''​f2''​ cu o altă adresă (aici, adresa funcției ''​show_message''​). Atenție, după adresa de return este salvat pe stivă base pointerul și abia apoi găsim și bufferul ''​v''​.
  
 Folosindu-vă de vectorul ''​v''​ **fortați execuția** funcției ''​show_message''​ **fără** a o apela explicit. Astfel, după apelul funcției ''​f2'',​ fluxul programului nu se va mai întoarce în funcția ''​f1'',​ ci va executa ''​show_message''​. Urmăriți comentariile marcate cu //TODO2// (revedeți partea din laborator referitoare la [[#stiva | stivă ]]) Folosindu-vă de vectorul ''​v''​ **fortați execuția** funcției ''​show_message''​ **fără** a o apela explicit. Astfel, după apelul funcției ''​f2'',​ fluxul programului nu se va mai întoarce în funcția ''​f1'',​ ci va executa ''​show_message''​. Urmăriți comentariile marcate cu //TODO2// (revedeți partea din laborator referitoare la [[#stiva | stivă ]])
 +Folosiți-vă de cum arată stiva pentru a afla indexul în cadrul vectorului ''​vv''​ la care se află IP-ul.
 +
  
 <note tip> <note tip>
Line 972: Line 1000:
  
  
-==== Exercițiul 9 - Lucrul cu stiva ====+<​hidden>​==== Exercițiul 9 - Lucrul cu stiva ====
  
 Intrați în directorul ''​9-bad_stack''​ și analizați fișierul ''​bad_stack.c''​. Compilați și rulați programul. Intrați în directorul ''​9-bad_stack''​ și analizați fișierul ''​bad_stack.c''​. Compilați și rulați programul.
Line 983: Line 1011:
  
 <note tip>​Indicație:​ Mutați variabila ''​lab_so''​ din funcția ''​my_fun()''​ într-o altă zonă de memorie.</​note>​ <note tip>​Indicație:​ Mutați variabila ''​lab_so''​ din funcția ''​my_fun()''​ într-o altă zonă de memorie.</​note>​
- +</​hidden>​ 
-===== Exerciții BONUS (3 SO Karma) ​===== +===== Exerciții BONUS ===== 
  
 ==== BONUS Windows ==== ==== BONUS Windows ====
so/laboratoare/laborator-05.1552767949.txt.gz · Last modified: 2019/03/16 22:25 by ioana_elena.ciornei
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0