[Powered by Google Translate] [Valgrind]
[Nate Hardison, Harvard University]
Dette er CS50, CS50.TV]
Nogle af de mest vanskelige fejl i C-programmer
kommer fra den dårlige forvaltning af hukommelsen.
Der er et enormt antal måder at skrue tingene op,
herunder fordelingen af ​​den forkerte mængde hukommelse,
glemmer at initialisere variabler,
skrivning før eller efter afslutningen af ​​en puffer,
og frigøre holde hukommelse flere gange.
Symptomerne spænder fra nedbrud
til mystisk overskrevne værdier,
ofte på steder og tidspunkter langt fra den oprindelige fejl.
Sporing den observerede problem tilbage til den underliggende årsag
kan være udfordrende,
men heldigvis er der en nyttig program kaldet Valgrind
der kan gøre en masse for at hjælpe.
>> Du kører et program under Valgrind at aktivere
omfattende kontrol af dynge hukommelse tildelinger og adgange.
Når Valgrind registrerer et problem, det giver dig øjeblikkelig,
direkte oplysninger, der gør det muligt at
lettere at finde og løse problemet.
Valgrind også rapporter om mindre dødbringende hukommelsesproblemer,
såsom memory leaks, fordeling dynge hukommelse
og glemmer at frigøre det.
Ligesom vores compiler, Dunk, i vores debugger, GDB,
Valgrind er fri software, og det er installeret på apparatet.
Valgrind kører på din binære eksekverbare,
ikke din. c eller. H kildekodefiler,
så vær sikker på at du har udarbejdet en up-to-date kopi af dit program
hjælp Dunk Eller Kom.
Derefter kan køre dit program under Valgrind være
så simpelt som bare at forudfastsætte standard program kommandoen med ordet Valgrind,
som starter Valgrind og kører programmet inde i den.
Ved start, Valgrind gør nogle komplekse
jiggering at konfigurere den eksekverbare for hukommelsen checks,
så det kan tage lidt at komme op og køre.
Programmet vil derefter udføre normalt, er det meget langsommere,
og når den er færdig, vil Valgrind udskrive et resumé af sin hukommelse.
Hvis alt går vel, vil det se nogenlunde sådan ud:
I dette tilfælde, /. Clean_program
er stien til det program, jeg vil køre.
Og mens denne ene ikke tager nogen argumenter,
hvis det gjorde jeg ville bare tack dem til slutningen af ​​kommandoen som sædvanlig.
Clean program er bare en dum lille program jeg har oprettet
der tildeler plads til en blok af int'er på heapen,
sætte nogle værdier indeni dem, og frigør hele blokken.
Dette er, hvad du fotograferer for, ingen fejl og ingen utætheder.
>> En anden vigtig parameter er det samlede antal tildelte bytes.
Afhængigt af programmet, hvis dine tildelinger er i megabyte eller højere,
du sikkert gør noget forkert.
Er du unødigt lagring dubletter?
Bruger du den bunke til opbevaring, når det ville være bedre at bruge stakken?
Så kan hukommelsesfejl være virkelig ond.
De mere åbenlyse dem forårsager spektakulære krak,
men selv da det kan stadig være svært at lokalisere
hvad der præcist førte til styrtet.
Mere snigende, et program med en hukommelse fejl
kan stadig indsamle rent
og kan stadig synes at arbejde korrekt
fordi du formåede at få heldige det meste af tiden.
Efter flere "positive resultater",
du kan bare tro, at en kollision er et lykketræf af computeren,
men computeren er aldrig forkert.
>> Løb Valgrind kan hjælpe dig med at spore ned årsagen til synlige hukommelsesfejl
samt finde lurer fejl, du behøver ikke engang endnu kender.
Hver gang Valgrind opdager et problem, udskriver information om, hvad det observeret.
Hvert element er temmelig kortfattet -
kildelinjen af ​​de ulovlige instruktion, hvad problemet er,
og lidt info om den pågældende hukommelse -
men ofte er det nok oplysninger til at rette din opmærksomhed mod det rigtige sted.
Her er et eksempel på Valgrind kører på en fejlbehæftet program
der gør en ugyldig læsning af bunke hukommelse.
Vi ser ingen fejl eller advarsler i opgørelsen.
Uh-oh, den fejl resumé siger, at der er to fejl -
to ugyldig læser af størrelse 4 - byte, der er.
Både dårlige læser skete i hovedfunktion invalid_read.c,
den første på linje 16 og den anden på linie 19.
Lad os se på koden.
Ligner den første indkaldelse til printf forsøger at læse en int forbi slutningen af ​​vores hukommelse blok.
Hvis vi ser tilbage på Valgrind udgang,
ser vi, at Valgrind fortalt os præcis det.
Adressen vi prøver at læse starter 0 bytes
forbi enden af ​​blokken af ​​størrelsen 16 byte -
fire 32-bit int'er at vi tildelte.
Det vil sige, den adresse, vi prøvede at læse starter lige i slutningen af ​​vores blok,
ligesom vi ser i vores dårlige printf opkald.
Nu kan ugyldig læser ikke ud som det store af en deal,
men hvis du bruger disse data til at styre strømmen af ​​dit program -
for eksempel som led i en if-sætning eller loop -
så tingene kan lydløst gå dårligt.
Se hvordan jeg kan køre invalid_read program
og intet ud over det sædvanlige sker.
Scary, hva '?
>> Nu, lad os se på nogle flere slags fejl, som du kan støde på i din kode,
og vi vil se, hvordan Valgrind registrerer dem.
Vi har lige set et eksempel på en invalid_read,
så lad os nu se en invalid_write.
Igen, ingen fejl eller advarsler i opgørelsen.
Okay, Valgrind siger, at der er to fejl i dette program -
og invalid_write og en invalid_read.
Lad os se denne kode.
Ser ud til vi har fået et tilfælde af den klassiske strlen plus én fejl.
Koden er ikke malloc en ekstra byte af plads
for / 0 karakter,
så når str kopi gik til at skrive det på ssubstrlen "CS50 rocks!"
det skrev 1 byte forbi slutningen af ​​vores blok.
Den invalid_read kommer, når vi gør vores opfordring til printf.
Printf ender op med at læse ugyldig hukommelse, når den læser / 0 tegn
som det ser ud i slutningen af ​​denne E-strengen, det er udskrivning.
Men intet af dette flygtede Valgrind.
Vi ser, at det fangede invalid_write som en del af str kopi
på linje 11 i main, den invalid_read og er en del af printf.
Rock på, Valgrind.
Igen, kan dette ikke virke som en big deal.
Vi kan køre dette program igen og igen uden for Valgrind
og ikke se nogen fejl symptomer.
>> Men lad os se på en lille variation af dette for at se
hvordan tingene kan blive rigtig slemt.
Så indrømmet, vi misbruger tingene mere end bare en smule i denne kode.
Vi er kun arealfordelingen på heapen til to strenge
længden af ​​CS50 sten,
denne gang, huske / 0 tegn.
Men derefter vi smide i en super-lang streng i hukommelsen blok
at S peger på.
Hvilken effekt vil det have på den lagerblok, at T peger på?
Tja, hvis T-point til hukommelse, der er bare støder op til S,
kommer lige efter det,
så vi kunne have skrevet over en del af T.
Lad os køre denne kode.
Se på, hvad der skete.
Strengene vi gemt i vores bunke blokke begge syntes at have udskrevet korrekt.
Intet virker forkert overhovedet.
Men lad os gå tilbage til vores kode og
udkommentere den linje, hvor vi kopierer CS50 klipper
ind i den anden hukommelse blok, der peges på af t.
Nu, når vi kører denne kode bør vi
kun indholdet af den første lagerblok printe ud.
Whoa, selvom vi ikke str kopi
alle tegn i den anden bunke blok, den ene peget på af T,
vi få en udskrift.
Faktisk strengen vi proppet ind i vores første blok
overskred den første blok og ind i den anden blok,
gør alt synes normalt.
Valgrind dog fortæller os den sande historie.
Der vi går.
Alle dem ugyldige læser og skriver.
>> Lad os se på et eksempel på en anden form for fejl.
Her gør vi noget ret uheldigt.
Vi grab plads til en int på heapen,
og vi initialisere en int pointer - p - at pege på den plads.
Men mens vores pointer er initialiseret,
de data, den peger mod netop har uanset junk er i den del af dyngen.
Så når vi indlæse disse data i int i,
vi teknisk initialisere i,
men vi gør det med junk data.
Opfordringen til at hævde, som er en praktisk debugging makro
defineret i det passende navn hævde bibliotek,
vil afbryde programmet, hvis dets testbetingelse mislykkes.
Det vil sige, hvis jeg ikke er 0.
Afhængigt af hvad der var i den bunke rummet, at ved p pegede,
dette program kan arbejde nogle gange og mislykkes på andre tidspunkter.
Hvis det virker, er vi bare at få heldige.
Compileren vil ikke fange denne fejl, men Valgrind sikker vilje.
Der ser vi den fejl som følge af vores brug af denne junk data.
>> Når du allokerer dynge hukommelse, men ikke deallocate det eller frigøre det,
, som kaldes en lækage.
For en lille, kortvarig program, der kører og straks udgange,
lækager er ret harmløs,
men for et projekt af større størrelse og / eller lang levetid,
selv en lille utæthed kan forværre til noget større.
For CS50, forventer vi at du
tage sig af at befri alle de bunke hukommelse, som du tildeler,
da vi ønsker, at du opbygge de færdigheder til korrekt håndtere den manuelle proces
kræves C.
For at gøre det, skal dit program har en eksakt
en-til-en overensstemmelse mellem allokere og gratis opkald.
Heldigvis kan Valgrind hjælpe dig med memory leaks også.
Her er en utæt program kaldet leak.c at tildeler
plads på heapen, skriver til det, men ikke frigøre det.
Vi sammensætter det med Make og køre det under Valgrind,
og vi kan se, at selv om vi ikke har nogen hukommelse fejl,
vi har en lækage.
Der er 16 bytes absolut tabt,
hvilket betyder, at markøren til at hukommelsen ikke var i rækkevidde når programmet forlades.
Nu ser Valgrind ikke give os et ton af oplysninger om lækagen,
men hvis vi følger denne lille note, at det giver ned mod bunden af ​​sin rapport
at køre med - lækage-check = fuld
at se de fulde detaljer om lækket hukommelse,
vi får mere information.
Nu, i bunke resumé,
Valgrind fortæller os, hvor den hukommelse, der blev tabt oprindeligt var tildelt.
Ligesom vi kender det fra at kigge i kildekoden,
Valgrind informerer os, at vi lækkede hukommelsen
fordelt med en opfordring til malloc på linje 8 i leak.c
i hovedfunktion.
Temmelig smart.
>> Valgrind kategoriserer utætheder ved hjælp af disse ord:
Absolut tabt - det er heap allokeret hukommelse
som programmet ikke længere har en pointer.
Valgrind ved, at du engang havde markøren, men har siden mistet styr på det.
Denne hukommelse er absolut lækket.
Indirekte tabt - det er heap allokeret hukommelse
som de eneste henvisninger til det også går tabt.
For eksempel, hvis du har mistet din pointer til den første node af en linket liste
derefter det første knudepunkt selv ville blive endeligt tabt,
mens eventuelle efterfølgende knuder ville indirekte tabt.
Muligvis tabt - det er heap allokeret hukommelse
som Valgrind ikke kan være sikker på, om der er en pegepind eller ej.
Stadig nås er heap allokeret hukommelse
som programmet stadig har en pointer på exit,
hvilket typisk betyder, at en global variabel peger på det.
At kontrollere for disse lækager, vil du også nødt til at omfatte mulighed
- Stadig-nås = yes
i din påkaldelse af Valgrind.
>> Disse forskellige tilfælde kan kræve forskellige strategier for at rense dem op,
men lækager bør fjernes.
Desværre kan fastsætte lækager være svært at gøre,
idet forkerte opkald til gratis kan sprænge dit program.
For eksempel, hvis vi ser på invalid_free.c
ser vi et eksempel på dårlig hukommelse deallokering.
Hvad bør være et enkelt opkald for at befri hele blokken
hukommelse peges på af int_block,
er i stedet blevet et forsøg på at befri hver int-sized sektion
af hukommelsen individuelt.
Dette vil svigte katastrofalt.
Boom! Hvad en fejl.
Dette er absolut ikke godt.
Hvis du sidder fast med denne form for fejl, selv om, og du behøver ikke vide hvor man skal lede,
falde tilbage på din nye bedste ven.
Du gættede det - Valgrind.
Valgrind, som altid ved præcis, hvad der sker.
Alloc og gratis tæller ikke passer sammen.
Vi har fået 1 alloc og 4 Frees.
Og Valgrind også fortæller os, hvor den første dårlige gratis opkald -
den, der udløste blowup - kommer fra -
linie 16.
Som du kan se, dårlige opkald til fri er virkelig dårlig,
så vi anbefaler at lade dit program lækage
mens du arbejder på at få funktionaliteten korrekt.
Begynder at lede efter lækager, når dit program fungerer korrekt,
uden andre fejl.
>> Og det er alt vi har for denne video.
Nu, hvad venter du på?
Go køre Valgrind på dine programmer lige nu.
Mit navn er Nate Hardison. Det er CS50. [CS50.TV]