[Powered by Google Translate] [Valgrind]
[Nate Hardison, Universitatea Harvard]
Acest lucru este CS50, CS50.TV]
Unele dintre cele mai dificile bug-uri în programele C
provin din proasta gestionare a memoriei.
Există un număr foarte mare de moduri de a șurub lucrurile,
inclusiv alocarea sumei greșit de memorie,
uitând pentru a inițializa variabile,
scris, înainte sau după încheierea unui tampon,
și eliberarea de memorie păstreze ori mai multe.
Simptomele variaza de la accidente intermitente
la valori misterios adăugiri,
de multe ori la locurile și orele foarte îndepărtate de eroare original.
Trasarea problema observată înapoi la cauza rădăcină care stau la baza
poate fi o provocare,
dar din fericire exista un program de ajutor numit Valgrind
care pot face o mulțime de a ajuta.
>> Tu conduci un program în cadrul Valgrind pentru a permite
verificarea largă de alocări de memorie heap și căi de acces.
Atunci când detectează o problemă Valgrind, îți dă imediat,
informații directe că vă permite să
mai ușor găsi și repara problema.
Valgrind, de asemenea, rapoarte privind probleme de memorie mai puțin mortale,
cum ar fi pierderi de memorie, alocarea de memorie heap,
și uitând să-l elibereze.
Vrei nostru compilator, zăngănit, în depanator noastră, GDB,
Valgrind este software liber, și este instalat pe aparat.
Valgrind rulează pe executabil binar dumneavoastră,
nu-ți c sau. h fișiere. cod sursă,
astfel încât să fie sigur că va fi compilat o copie up-to-data de programul tău
folosind zăngănit sau fac.
Apoi, execută programul în cadrul Valgrind poate fi
la fel de simplu ca și prefixarea doar comanda programul standard cu Valgrind cuvântul,
care începe Valgrind și rulează programul în interiorul său.
Atunci când începe, Valgrind face unele complexe
manipulăm pentru a configura executabil pentru controalele de memorie,
asa ca poate dura un pic să se ridice și să fie difuzate.
Programul va executa în mod normal, atunci, fie că este vorba de mult mai lent,
și când se termină, Valgrind va imprima un rezumat de utilizare a memoriei sale.
Dacă totul merge bine, va arata ceva de genul asta:
În acest caz, / clean_program.
este calea către programul vreau să fug.
Și în timp ce aceasta nu ia nici un argument,
în cazul în care a făcut-o aș doar le calul pe la sfarsitul comenzii ca de obicei.
Programul Clean este doar un program de prostuță mic am creat
care alocă spațiu pentru un bloc de Ints pe heap,
pune niste valori din interiorul ei, și eliberează tot blocul.
Aceasta este ceea ce filmarile pentru, nu există erori și fără scurgeri.
>> Un alt parametru important este numărul total de octeți alocate.
În funcție de program, în cazul în care alocările dvs. sunt în megaocteți sau mai mare,
faci, probabil, ceva gresit.
Ești stocarea inutil dubluri?
Ești folosind heap pentru depozitare, atunci când ar fi mai bine pentru a utiliza stiva?
Deci, erorile de memorie poate fi cu adevărat rău.
Cele mai vizibile provoca accidente spectaculoase,
dar chiar și atunci poate fi încă greu de identificat
exact ceea ce a dus la accident.
Mai insidios, un program cu o eroare de memorie
poate compila în continuare curat
și poate părea încă să funcționeze corect
pentru că ați reușit să obțineți noroc cele mai multe ori.
Dupa mai multe "rezultate de succes,"
s-ar putea crede că tocmai un accident este o întâmplare de calculator,
dar calculatorul nu este niciodată greșit.
>> Rularea Valgrind poate ajuta să urmăriți în jos cauza unor erori de memorie vizibile
precum și găsi ca spectatori erori pe care nici măcar nu știu încă despre.
De fiecare dată când detectează o problemă Valgrind, se imprimă informații despre ceea ce observă.
Fiecare element este destul de concis -
linia sursa de instruire ofensatoare, ceea ce este problema,
și un pic de informații despre memoria implicate -
dar de multe ori e suficiente informații pentru a direcționa atenția spre locul potrivit.
Aici este un exemplu de Valgrind rulează pe un program de buggy
care face o citire invalid de memorie heap.
Ne vedem nici o eroare sau avertismente în conturi.
Uh-oh, rezumatul eroare spune că există două erori -
două citiri invalid de marimea 4 - octeți, care este.
Atât de rău citește avut loc în funcția principală a invalid_read.c,
primul pe linia 16, iar al doilea pe linia 19.
Să ne uităm la codul.
Se pare ca primul apel pentru a printf încearcă să citească un int ultimile sfârșitul blocului memoriei noastre.
Dacă ne uităm înapoi la puterea lui Valgrind,
vom vedea că Valgrind ne-a spus exact acest lucru.
Adresa încercăm să citească începe 0 bytes
trecut la sfârșitul blocului de dimensiunea 16 bytes -
patru 32-biți Ints pe care le alocate.
Asta este, adresa am fost încercarea de a citi începe chiar de la sfârșitul blocului nostru,
așa cum vedem în nostru apel printf rău.
Acum, invalid citiri ar putea să nu pară atât de mare de o afacere,
dar dacă utilizați aceste date pentru a controla fluxul de programul dumneavoastră -
de exemplu, ca parte a unei if sau buclă -
atunci lucrurile pot merge prost în tăcere.
Uita-te la modul în care pot rula programul invalid_read
și nimic ieșit din comun se întâmplă.
Înfricoșător, nu-i asa?
>> Acum, să ne uităm la unele tipuri de erori mai multe pe care le-ar putea întâlni în cod,
și vom vedea cum Valgrind le detectează.
Am văzut doar un exemplu de invalid_read,
deci acum să verificați un invalid_write.
Din nou, nu există erori sau avertismente în conturi.
Bine, Valgrind spune că există două erori în acest program -
și invalid_write și un invalid_read.
Să verificăm acest cod.
Se pare că avem o instanță a clasic strlen plus un bug.
Codul nu malloc un octet suplimentar de spațiu
pentru caracterul / 0,
asa ca atunci cand str. copie a mers să-l scrie la ssubstrlen "CS50 pietre!"
a scris 1 octet ultimile sfârșitul blocului nostru.
Invalid_read vine atunci când vom face apelul nostru la printf.
Printf se termină citirea de memorie invalidă când se citește / 0 caractere
cum se pare, la sfârșitul acestui șir E e de imprimare.
Dar nimic din toate astea scăpat Valgrind.
Vedem că a prins-o invalid_write, ca parte a copiei str.
pe linia 11 din principal, și invalid_read este parte a printf.
Rock pe, Valgrind.
Din nou, acest lucru nu s-ar putea părea ca o afacere mare.
Ne poate rula acest program de peste si peste din afara Valgrind
și nu văd nici un simptom de eroare.
>> Cu toate acestea, să ne uităm la o ușoară variație a acestei pentru a vedea
cum lucrurile pot deveni foarte rău.
Deci, a acordat, suntem abuzează de lucruri mai mult decât doar un pic în acest cod.
Suntem doar alocarea de spațiu pe heap pentru două șiruri
lungimea CS50 roci,
de data aceasta, amintindu-/ 0 caractere.
Dar apoi am arunca într-un șir de super-lung în bloc de memorie
că S este îndreptat spre.
Ce efect va avea asupra faptul că blocul de memorie care punctele T la?
Ei bine, în cazul în care punctele de T în memoria asta e doar adiacent la S,
vine doar după ce,
apoi ne-am fi scris peste o parte din T.
Să rula acest cod.
Uită-te la ceea ce sa întâmplat.
Siruri de caractere am stocate în blocuri heap noastre ambele părea să fi imprimate corect.
Nimic nu pare deloc greșit.
Cu toate acestea, să mergem înapoi în codul nostru și
comentați linia de unde am copiat CS50 roci
în bloc a doua memorie, a subliniat de t.
Acum, când vom rula acest cod ar trebui să ne
doar vedea conținutul bloc de memorie prima imprima.
Oau, chiar dacă nu am făcut-Str copie
toate caracterele în bloc heap al doilea, cel indicat de T,
vom obține o imprimare afară.
Într-adevăr, șirul am umplute în bloc primul nostru
depășit primul bloc și în al doilea bloc,
face totul pare normal.
Valgrind, deși, ne spune povestea adevarata.
Acolo mergem.
Toți cei invalid citește și scrie.
>> Să ne uităm la un exemplu de un alt fel de eroare.
Aici facem ceva destul de nefericit.
Ne apuca spațiu pentru un int pe heap,
și am inițializa un pointer int - p - pentru a indica acel spațiu.
Cu toate acestea, în timp ce indicatorul nostru este inițializat,
datele pe care se indică doar la a tot ce este gunoi, în acea parte a heap.
Așa că atunci când am încărcați că datele în int i,
am inițializa punct de vedere tehnic i,
dar facem acest lucru cu date nesolicitate.
Apel pentru a afirma, care este un macro de depanare la îndemână
definite în aptly numit afirma bibliotecă,
va abandona programul său în cazul în care condiția de testare nu reușește.
Asta este, dacă nu este 0.
În funcție de ceea ce a fost în spațiul grămadă, indicat de p,
acest program ar putea să funcționeze, uneori, și nu în alte momente.
Dacă funcționează, suntem abia la noroc.
Compilatorul nu va prinde această eroare, dar Valgrind voința sigur.
Acolo vedem eroarea care rezultă din utilizarea de către noi a acestor date nesolicitate.
>> Când aloca memorie heap, dar nu-l dealoca sau gratuit aceasta,
care este numit o scurgere.
Pentru un mic, de scurtă durată, program care se execută imediat și ieșirile,
scurgeri sunt destul de inofensive,
dar pentru un proiect de dimensiuni mai mari și / sau de longevitate,
chiar o scurgere mica poate combinate în ceva major.
Pentru CS50, ne-aștept să
grijă de a elibera toate memorie heap pe care le aloca,
deoarece dorim să construiască abilitățile de a manevreze corect proces manual
solicitate de către C.
Pentru a face acest lucru, programul ar trebui să aibă o exacta
unu-la-unu corespondenta între malloc și apeluri gratuite.
Din fericire, Valgrind poate ajuta cu pierderi de memorie prea.
Aici este un program de scurgeri numit leak.c care alocă
spațiu pe heap, scrie el, dar nu-l elibera.
Am compila cu Marca și rulați-l sub Valgrind,
și vom vedea că, în timp ce noi nu au erori de memorie,
avem o scurgere.
Există 16 octeți cu siguranta pierdere,
ceea ce înseamnă că indicatorul pentru ca memoria nu a fost în domeniul de aplicare atunci când programul ieșit.
Acum, Valgrind nu ne oferă o tona de informatii despre scurgere,
dar dacă urmăm această notă mică pe care-l dă jos spre partea de jos a raportului său
să rulați din nou cu - scurgeri de check-= completă
pentru a vedea detaliile complete ale memoriei scurgeri,
vom obține mai multe informații.
Acum, în rezumat heap,
Valgrind ne spune în cazul în care memoria, care a fost pierdut a fost alocat inițial.
Așa cum știm din căutați în codul sursă,
Valgrind ne informează că am scurs de memorie
alocate cu un apel la malloc pe linia 8 din leak.c
în funcția de principal.
Destul de puturos.
>> Valgrind clasifică scurgeri folosind acești termeni:
Categoric pierdere - aceasta este o memorie heap alocată
la care programul nu mai are un pointer.
Valgrind știe că ați avut o dată, dar au pierdut indicatorul, deoarece pista de ea.
Această memorie este cu siguranta scurgeri.
Indirect pierdere - aceasta este o memorie heap alocată
la care indicii doar să-l, de asemenea, sunt pierdute.
De exemplu, dacă ți-ai pierdut indicatorul pentru primul nod al unei liste legate,
apoi primul nod în sine ar fi cu siguranta pierdut,
în timp ce orice noduri ulterioare ar fi în mod indirect pierdut.
Posibil pierdut - aceasta este o memorie heap alocată
la care Valgrind nu poate fi sigur dacă există un pointer sau nu.
Încă realizabil este memoria heap alocată
la care programul are încă un pointer la ieșire,
care de obicei înseamnă că o variabilă de puncte la nivel mondial la ea.
Pentru a verifica aceste scurgeri, veți avea, de asemenea, să includă opțiunea
- Încă-accesibil = da
în invocarea dvs. de Valgrind.
>> Aceste cazuri diferite ar putea necesita strategii diferite pentru curățarea le,
dar scurgeri ar trebui eliminate.
Din păcate, de stabilire scurgeri poate fi greu să facă,
deoarece apelurile către incorecte free se mai poate arunca în aer programul tău.
De exemplu, dacă ne uităm la invalid_free.c,
vom vedea un exemplu de Dealocarea memorie proasta.
Ce ar trebui să fie un singur apel pentru a elibera întregul bloc
de memorie indicat de către int_block,
în schimb a devenit o încercare de a elibera fiecare secțiune int-urilor
de memorie în mod individual.
Acest lucru va eșua catastrofal.
Boom! Ce o eroare.
Acest lucru nu este cu siguranta bine.
Dacă te-ai blocat cu acest tip de eroare, deși, și nu știi unde să te uiți,
cădea înapoi pe prietenul tau cel mai bun nou.
Ai ghicit - Valgrind.
Valgrind, ca întotdeauna, știe exact ce sa întâmplat.
Contează alloc si gratuit nu se potrivesc.
Avem 1 și 4 alloc eliberează.
Și, de asemenea, Valgrind ne spune în cazul în care primul apel gratuit rău -
cel care a declanșat Blowup - vine de la -
linia 16.
După cum vedeți, solicită să-i elibereze rele sunt într-adevăr rău,
așa că vă recomandăm închirierea scurgere de program
în timp ce lucrați pe obtinerea funcționalitatea corectă.
Începe căutarea pentru scurgeri numai după ce programul dvs. este de lucru în mod corespunzător,
fără alte erori.
>> Și asta e tot ce avem pentru acest videoclip.
Acum, ce mai aștepți?
Du-te rula Valgrind pentru programele dvs. acum.
Numele meu este Nate Hardison. Acest lucru este CS50. [CS50.TV]