[Powered by Google Translate] [Valgrind]
[Nate Hardison, Harvard University]
Dit is CS50, CS50.TV]
Enkele van de meest moeilijke bugs in C-programma's
komen uit het wanbeheer van het geheugen.
Er zijn een groot aantal manieren om dingen te verknallen,
inclusief de toewijzing van de verkeerde hoeveelheid geheugen,
vergeten om variabelen te initialiseren,
schrijven voor of na het einde van een buffer,
en het vrijmaken van de herinnering te meerdere keren.
De symptomen variëren van intermitterende crashes
op mysterieuze wijze overschreven waarden,
vaak op plaatsen en tijden ver verwijderd van de oorspronkelijke fout.
Het opsporen van de waargenomen probleem terug naar de onderliggende oorzaak
kan lastig zijn,
maar gelukkig is er een handige programma genaamd Valgrind
dat kan veel doen om te helpen.
>> U voert een programma onder Valgrind in staat te stellen
uitgebreide controle van heap geheugen toewijzingen en toegangen.
Wanneer Valgrind een probleem vindt, het geeft je directe,
directe informatie die u toelaat om
gemakkelijker te vinden en het probleem oplossen.
Valgrind ook rapporten over minder dodelijke geheugenproblemen,
zoals geheugenlekken, toewijzen heap geheugen,
en vergeten om het te bevrijden.
Net als onze compiler, Clang, in onze debugger, GDB,
Valgrind is vrije software, en het is geïnstalleerd op het apparaat.
Valgrind draait op uw binaire, uitvoerbare,
niet uw. c of. h broncode-bestanden,
dus zorg ervoor dat u een up-to-date kopie van uw programma samengesteld
met behulp van Clang Of Bod.
Dan kan u het programma onder Valgrind worden
zo eenvoudig als gewoon door aan de standaard programma-opdracht met het woord Valgrind,
die begint op Valgrind en loopt het programma binnenkant van het.
Bij het starten van, Valgrind doet een aantal complexe
jiggering naar het uitvoerbare configureren voor het geheugen controles,
dus het kan wel een beetje te krijgen up and running.
Het programma zal dan normaal uitgevoerd, zij het veel langzamer,
en wanneer het klaar is, zal Valgrind drukt u een overzicht van het geheugen gebruik.
Als alles goed gaat, zal het er ongeveer zo uitzien:
In dit geval. / Clean_program
is het pad naar het programma dat ik wil uitvoeren.
En terwijl deze neemt geen argumenten,
als dat wel Ik zou gewoon overstag ze op aan het einde van de opdracht zoals gewoonlijk.
Clean-programma is gewoon een dom klein programma die ik heb gemaakt
dat wijst ruimte voor een blok ints op de heap,
er wat waarden binnenkant van hen, en bevrijdt het hele blok.
Dit is wat je filmt voor, geen fouten en geen lekken.
>> Een andere belangrijke maatstaf is het totaal aantal toegewezen bytes.
Afhankelijk van het programma, als uw toewijzingen zijn in de megabytes of hoger,
ben je waarschijnlijk iets verkeerd.
Bent u onnodig opslaan van duplicaten?
Gebruikt u de hoop voor de opslag, wanneer het beter zou zijn om de stapel te gebruiken?
Dus kan geheugenfouten echt kwaad.
Hoe meer openlijke die leiden tot spectaculaire crashes,
maar zelfs dan kan het nog steeds moeilijk te lokaliseren
wat precies leidde tot de crash.
Meer verraderlijk, een programma met een geheugen fout
kan nog steeds netjes samen te stellen
en kan nog steeds lijken correct te laten werken
omdat je erin geslaagd om je geluk meeste van de tijd.
Na een aantal 'succesvolle resultaten, "
kun je net denken dat een crash is een toevalstreffer van de computer,
maar de computer is nooit verkeerd.
>> Running Valgrind kan u helpen bij het opsporen van de oorzaak van de zichtbare geheugenfouten
alsmede vinden op de loer fouten die je nog niet eens weten.
Elke keer Valgrind een probleem detecteert, drukt het informatie over wat het waargenomen.
Elk item is vrij kort -
de bron lijn van de gewraakte instructie, wat het probleem is,
en een beetje info over de betrokken geheugen -
maar vaak is het genoeg informatie om je aandacht te richten op de juiste plaats.
Hier is een voorbeeld van Valgrind draaien op een buggy programma
dat doet een ongeldige lezen van heap geheugen.
Wij zien geen fouten of waarschuwingen in compilaties.
Uh-oh, de fout samenvatting zegt dat er twee fouten -
twee ongeldige maal gelezen van maat 4 - bytes, dat is.
Beide slecht leest voorgedaan in de belangrijkste functie van invalid_read.c,
de eerste op lijn 16 en de tweede op de lijn 19.
Laten we eens kijken naar de code.
Het lijkt erop dat de eerste oproep tot printf probeert om een ​​int lezen voorbij het einde van ons geheugen blok.
Als we terugkijken aan de uitgang van Valgrind's,
zien we dat Valgrind ons verteld precies dat.
Het adres dat we proberen te lezen begint 0 bytes
voorbij het einde van het blok van 16 bytes omvang -
vier 32-bit ints dat we toegewezen.
Dat wil zeggen, het adres dat we probeerden om te lezen begint direct aan het einde van onze straat,
net zoals we zien in onze slechte printf aan te roepen.
Nu, zou ongeldig leest lijkt niet zo groot van een deal,
maar als u gebruik maakt van die gegevens aan de stroom van uw programma te controleren -
bijvoorbeeld als onderdeel van een if-statement of lus -
dan dingen kan stil gaan slecht.
Kijk hoe kan ik het invalid_read programma uit te voeren
en niets uit de gewone gebeurt.
Scary, he?
>> Laten we nu eens kijken naar enkele meer soorten fouten die zich kunnen voordoen in uw code,
en we zullen zien hoe Valgrind detecteert.
We zagen een voorbeeld van een invalid_read,
dus laten we nu eens kijken een invalid_write.
Nogmaals, geen fouten of waarschuwingen in compilaties.
Oke, Valgrind zegt dat er twee fouten in dit programma -
en invalid_write en een invalid_read.
Laten we eens kijken deze code.
Het lijkt erop dat we hebben een exemplaar van de klassieke strlen plus een bug.
De code is niet malloc een extra byte van de ruimte
voor het / 0 karakter,
dus als str kopie ging om het te schrijven op ssubstrlen "CS50 rocks!"
schreef 1 byte voorbij het einde van onze straat.
De invalid_read komt wanneer we onze oproep om printf.
Printf eindigt het lezen van ongeldig geheugen tijdens het lezen van de / 0 karakter
omdat wij naar het einde van deze E snaar het afdrukken.
Maar niets van dit alles ontsnapt Valgrind.
We zien dat het de invalid_write gevangen als onderdeel van de str kopie
on line 11 van de belangrijkste, en de invalid_read maakt deel uit van printf.
Rock op, Valgrind.
Nogmaals, kan dit niet als een groot probleem.
We kunt dit programma over en buiten Valgrind
en zie geen fout symptomen.
>> Maar laten we eens kijken naar een lichte variatie van dit te zien
hoe de dingen kunnen echt slecht.
Dus, verleend, zijn we misbruik maken van dingen meer dan alleen maar een beetje in deze code.
We zijn alleen toewijzing van ruimte op de heap voor twee strings
de lengte van CS50 rotsen,
dit keer, het onthouden van de / 0 karakter.
Maar dan gooien we in een super-lange string in het geheugen blok
dat wijst naar S.
Welk effect heeft dat op het geheugenblok dat T verwijst naar?
Nou, als T verwijst naar het geheugen dat is gewoon naast S,
komende net na het,
dan zouden we hebben geschreven over een deel van T.
Laten we deze code uitvoert.
Kijk naar wat er gebeurd is.
De snaren hebben we opgeslagen in onze hoop blokkeert zowel leek te hebben afgedrukt op de juiste wijze.
Niets lijkt verkeerd.
Maar laten we terug gaan naar onze code en
commentaar van de regel waar we kopiëren CS50 rotsen
in de tweede geheugenblok, wordt gewezen door t.
Nu, als we deze code uitvoeren moeten we
alleen de inhoud van het eerste geheugen blok uit te printen.
Whoa, ook al hebben we niet str kopie
alle tekens in de tweede hoop blok, de een wordt gewezen door T,
krijgen we een uitdraai.
Inderdaad, de string die we gevuld in onze eerste blok
overschreed het eerste blok en in het tweede blok,
het maken van alles normaal lijkt.
Valgrind, hoewel, vertelt het ware verhaal.
Daar gaan we dan.
Al die ongeldige leest en schrijft.
>> Laten we eens kijken naar een voorbeeld van een ander soort fout.
Hier hebben we iets doen nogal ongelukkig.
We grijpen ruimte voor een int op de heap,
en we initialiseren van een int pointer - p - om te wijzen op die ruimte.
Echter, terwijl onze pointer wordt geïnitialiseerd,
de gegevens die het wijzend naar zojuist wat junk is dat deel van de heap.
Dus als we die gegevens te laden in int i,
we technisch initialiseren i,
maar we doen dat met junk data.
De oproep om te beweren, dat is een handige debugging macro
gedefinieerd in de toepasselijke naam beweren bibliotheek,
zal afbreken van het programma als de testvoorwaarde mislukt.
Dat wil zeggen, als ik niet 0.
Afhankelijk van wat er in de heap-ruimte, wees door p,
dit programma kan soms werken en niet op andere momenten.
Als het werkt, we net geluk.
De compiler zal niet vangen deze fout, maar Valgrind zeker wil.
Daar zien we de fout als gevolg van ons gebruik van die troep gegevens.
>> Wanneer u heap geheugen toe te wijzen, maar niet vrijgeven het of bevrijden,
dat heet een lek.
Voor een kleine, kortstondige programma dat draait en onmiddellijk verlaat,
lekken zijn vrij onschuldig,
maar voor een project van grotere omvang en / of lange levensduur,
zelfs een klein lek kan verergeren tot iets groot.
Voor CS50, we verwachten dat u
zorgen voor het vrijmaken van alle van de berg geheugen, wat je,
omdat we willen dat u de vaardigheden op te bouwen om goed omgaan met het handmatige proces
vereist C.
Om dit te doen, moet je het programma een exacte
een-op-een correspondentie tussen malloc en gratis bellen.
Gelukkig kunt Valgrind u ook helpen met het geheugen lekken.
Hier is een lekkende programma genaamd leak.c dat toewijst
plaats op de heap, schrijft, maar niet losmaken.
We compileren met Make en voer het onder Valgrind,
en we zien dat, terwijl wij geen geheugen fouten hebben,
we hebben een lek.
Er zijn 16 bytes zeker verloren,
Dit betekent dat de pointer naar dat geheugen niet in omvang als het programma verlaten.
Nu, Valgrind ons niet een ton van informatie over het lek,
maar als we dit kleine er rekening mee dat het geeft naar beneden naar de onderkant van haar verslag
om opnieuw uit te voeren met - lek-check = vol
om de volledige details van gelekt geheugen te zien,
we krijgen meer informatie.
Nu in de heap samenvatting
Valgrind vertelt ons waar het geheugen dat werd verloren werd in eerste instantie toegewezen.
Net zoals we weten uit te kijken in de broncode,
Valgrind informeert ons dat we de herinnering gelekt
toegewezen met een oproep om malloc op lijn 8 van leak.c
in de hoofdfunctie.
Mooie handige.
>> Valgrind categoriseert lekken met behulp van deze termen:
Zeker verloren - dit is heap toegewezen geheugen
waarin het programma niet langer een pointer.
Valgrind weet dat je een keer de aanwijzer had maar sindsdien verloor het.
Dit geheugen is zeker gelekt.
Indirect verloren - dit is heap toegewezen geheugen
welke alleen pointers om ook verloren.
Bijvoorbeeld, als je verloor je pointer naar het eerste knooppunt van een gekoppelde lijst,
dan is het eerste knooppunt zelf zou zeker verloren gaan,
terwijl volgende nodes zou indirect verloren gaan.
Mogelijk verloren - dit is heap toegewezen geheugen
waarin Valgrind niet zeker of er een pointer of niet.
Nog steeds bereikbaar is heap toegewezen geheugen
waaraan nog het programma heeft een pointer bij afslag,
Dit betekent gewoonlijk dat een globale variabele punten aan.
Om te controleren of deze lekken, dan heb je ook de mogelijkheid zijn
- Nog steeds-te bereiken = yes
in uw aanroeping van Valgrind.
>> Deze verschillende gevallen kunnen vereisen verschillende strategieën voor het reinigen van hen,
maar lekken moeten worden afgeschaft.
Helaas kan de vaststelling lekken zijn moeilijk om te doen,
omdat onjuiste oproepen naar gratis kunt opblazen uw programma.
Bijvoorbeeld, als we kijken naar invalid_free.c,
zien we een voorbeeld van slecht geheugen vrijmaken.
Wat een aanroep naar de gehele blok vrij
van het geheugen wordt gewezen door int_block,
is maar als een poging om elke int-en kleinbedrijf gedeelte vrij te maken
van het geheugen afzonderlijk.
Dit zal catastrofaal falen.
Boom! Wat een fout.
Dit is zeker niet goed.
Als je vastzit met dit soort fouten, maar, en je weet niet waar je moet kijken,
terug te vallen op uw nieuwe beste vriend.
Je raadt het al - Valgrind.
Valgrind, zoals altijd, weet precies wat er is.
De Alloc en vrije telt niet met elkaar overeenkomen.
We hebben een Alloc en 4 bevrijdt.
En Valgrind vertelt ons ook waar de eerste slechte free bellen -
degene die de blowup geactiveerd - vandaan komt -
lijn 16.
Zoals u ziet, slechte calls te bevrijden zijn echt slecht,
dus we raden het verhuren van uw programma lek
terwijl je bezig om de functionaliteit correct.
Ga op zoek naar lekken pas na uw programma goed werkt,
zonder enige andere fouten.
>> En dat is alles wat we hebben voor deze video.
Nu, wat wacht je nog op?
Ga op uw programma's Valgrind nu.
Mijn naam is Nate Hardison. Dit is CS50. [CS50.TV]