[Powered by Google Translate] [Valgrind] [Nate Hardison, Harvard University] Dette er CS50, CS50.TV] Noen av de vanskeligste feil i C-programmer kommer fra vanstyre av minnet. Det er et stort antall måter å skru opp ting, inkludert tildeling feil mengde minne, glemme å initialisere variabler, skriftlig før eller etter slutten av en buffer, og frigjøre holde minne flere ganger. Symptomene varierer fra intermitterende krasj til mystisk overskrevet verdier, ofte på steder og tider fjernt fra den opprinnelige feilen. Tracing den observerte problemet tilbake til den underliggende årsaken kan være utfordrende, men heldigvis er det en nyttig program som heter Valgrind som kan gjøre mye for å hjelpe. Du kjører et program under Valgrind å aktivere omfattende kontroll av heap minnetildelinger og tilganger. Når Valgrind oppdager et problem, det gir deg umiddelbar, direkte informasjon som gjør det mulig å enklere å finne og løse problemet. Valgrind også rapporter om mindre dødelige minneproblemer, som minnelekkasjer, fordele heap minne, og glemmer å frigjøre den. Liker vår kompilator, Clang i debugger vår, GDB, Valgrind er fri programvare, og det er installert på maskinen. Valgrind kjører på binær kjørbar, ikke din. c eller. h kildekodefiler, så vær sikker på at du har satt sammen en up-to-date kopi av programmet bruker Clang eller Make. Deretter kan kjøre program under Valgrind være så enkelt som bare prefixing standard programkommando med ordet Valgrind, som starter opp Valgrind og kjører programmet på innsiden av det. Når du starter, gjør Valgrind noen komplekse jiggering å konfigurere den kjørbare for minne sjekker, så det kan ta litt for å få opp og kjører. Programmet vil da kjøre normalt, det være seg mye saktere, og når den er ferdig, vil Valgrind skrive ut et sammendrag av sin minnebruk. Hvis alt går bra, vil det se omtrent slik ut: I dette tilfellet,. / Clean_program er banen til det programmet jeg ønsker å kjøre. Og mens dette ikke tar noen argumenter, hvis det gjorde jeg ville bare tack dem videre til slutten av kommandoen som vanlig. Ren programmet er bare en dum liten program jeg har laget som tildeler plass for en blokk med ints på haugen, sette noen tall inne i dem, og frigjør hele blokken. Dette er hva du fotograferer for, ingen feil og ingen lekkasjer. En annen viktig faktor er det totale antall byte tildelt. Avhengig av programmet, hvis bevilgningene er i megabyte eller høyere, du sannsynligvis har gjort noe galt. Er du unødvendig lagring duplikater? Bruker du haugen for lagring, da det ville være bedre å bruke stabelen? Så kan minnefeil være virkelig onde. De mer synlige som forårsaker spektakulære krasj, men selv da kan det likevel være vanskelig å finne hva førte til ulykken. Mer snikende, et program med en minne feil kan fortsatt kompilere ren og kan fortsatt synes å fungere riktig fordi du klarte å få heldige mesteparten av tiden. Etter flere "vellykkede resultater," du kan bare tenke at en krasj er en fluke av datamaskinen, men datamaskinen er aldri feil. Kjører Valgrind kan hjelpe deg med å spore årsaken til synlige minne feil samt finne lurking feil du ikke selv ennå vet om. Hver gang Valgrind oppdager et problem, skriver den informasjon om hva det observert. Hvert element er ganske konsis - kilden linjen av den fornærmende instruksjon, hva problemet er, og litt info om minnet involvert - men ofte er det nok informasjon til å rette oppmerksomheten din til rett sted. Her er et eksempel på Valgrind kjører på en buggy program som gjør en ugyldig lese av heap minne. Vi ser ingen feil eller advarsler i samlingen. Uh-oh, sier Feillisten at det er to feil - to ugyldig lesninger av størrelse 4 - bytes, som er. Både dårlig leser skjedde i den viktigste funksjonen til invalid_read.c, først på linje 16 og den andre på linje 19. La oss se på koden. Ser ut som den første samtalen til printf forsøker å lese en int forbi slutten av vår hukommelse blokk. Hvis vi ser tilbake på Valgrind utgang, Vi ser at Valgrind fortalte oss akkurat det. Adressen vi prøver å lese starter 0 byte forbi enden av blokken av størrelse 16 byte - fire 32-bits ints som vi tildelt. Det vil si, begynner adressen vi prøvde å lese helt på slutten av blokken vår, akkurat som vi ser i vår dårlig printf samtale. Nå kan ugyldig reads ikke virke som den store av en avtale, men hvis du bruker disse dataene til å kontrollere flyten av programmet - for eksempel som en del av en hvis setningen eller sløyfe - så ting kan stille gå dårlig. Se hvordan jeg kan kjøre invalid_read program og ingenting utenom det vanlige skjer. Skremmende, ikke sant? Nå, la oss se på noen flere typer feil som kan oppstå i koden, og vi får se hvordan Valgrind oppdager dem. Vi så et eksempel på en invalid_read, så nå la oss sjekke ut en invalid_write. Igjen, ingen feil eller advarsler i samlingen. Ok, sier Valgrind at det er to feil i dette programmet - og invalid_write og en invalid_read. La oss sjekke ut denne koden. Ser ut som vi har fått en forekomst av den klassiske strlen pluss en bug. Koden ikke malloc en ekstra byte plass for / 0 karakter, så når str kopi gikk for å skrive det på ssubstrlen "CS50 rocks!" det skrev en byte forbi slutten av blokken vår. Den invalid_read kommer når vi gjør vår oppfordring til printf. Printf ender opp med å lese ugyldig minne når den leser / 0 karakter som det ser ut på slutten av denne E strengen er det utskrift. Men ingenting av dette rømte Valgrind. Vi ser at det fanget invalid_write som en del av str kopi on line 11 av main og invalid_read er en del av printf. Rock on, Valgrind. Igjen, dette kan ikke virke som en stor avtale. Vi kan kjøre dette programmet og om igjen utenfor Valgrind og ikke se noen feil symptomer. Men la oss se på en liten variant av dette for å se hvordan ting kan bli virkelig ille. Så, gitt, er vi misbruker ting mer enn bare litt i denne koden. Vi bare tildeles plass på haugen for to strenger lengden på CS50 bergarter, denne gangen, husker / 0 karakter. Men da vi kaste i en super-lang streng inn i minnet blokk at S peker til. Hvilken effekt vil det ha på minnet blokken T peker på? Vel, hvis T peker på minne det er bare ved siden av S, kommer rett etter det, så vi kan ha skrevet over en del av T. La oss kjøre denne koden. Se på hva som skjedde. Strengene vi lagret i våre heap blokker både syntes å ha skrevet ut riktig. Ingenting virker galt i det hele tatt. Men la oss gå tilbake til koden vår og kommentere ut linjen der vi kopierer CS50 bergarter inn i andre minneblokk, pekte på av t. Nå, når vi kjører denne koden vi bør bare se innholdet i den første minneblokk skrive ut. Jøss, selv om vi ikke str kopi noen tegn til den andre haugen blokken, pekte en til av T, vi får en utskrift. Faktisk strengen vi fylt inn i vår første kvartal overkjørte den første blokken og inn i den andre blokka, gjør alt synes normalt. Valgrind, men forteller oss den sanne historien. Det vi går. Alle disse ugyldig leser og skriver. La oss se på et eksempel på en annen type feil. Her har vi å gjøre noe ganske uheldig. Vi grip plass til en int på haugen, og vi initialisere en int spisser - p - å peke på det rommet. Men mens våre pekeren er initialisert, dataene at det peker til bare har uansett junk ligger i den delen av haugen. Så når vi laster dataene inn int i, vi teknisk initialisere i, Men vi gjør det med søppel data. Kallet til å hevde, som er en hendig debugging makro definert i det treffende navnet hevde bibliotek, vil avbryte programmet hvis det testbetingelse mislykkes. Det vil si, hvis jeg ikke er 0. Avhengig av hva var i haugen plass, peker til p, dette programmet kan fungere noen ganger og mislykkes på andre tidspunkter. Hvis det fungerer, vi bare få heldige. Kompilatoren vil ikke fange denne feilen, men Valgrind sikker vilje. Der ser vi feilen stammer fra vår bruk av som useriøs data. Når du tildeler heap minne, men ikke deallocate det eller frigjøre det, som kalles en lekkasje. For en liten, kortvarig program som kjører og umiddelbart kommer ut, lekkasjer er ganske ufarlig, men for et prosjekt av større størrelse og / eller levetid, selv en liten lekkasje kan forverre seg til noe større. For CS50, forventer vi at du ta vare på frigjøre alle av haugen minne som du fordele, siden vi ønsker å bygge kompetanse til å riktig håndtere den manuelle prosessen kreves av C. Å gjøre det, bør programmet ha en eksakt en-til-en-forhold mellom malloc og gratis samtaler. Heldigvis kan Valgrind hjelpe deg med minnelekkasjer også. Her er en lekk program som heter leak.c som tildeler plass på haugen, skriver til den, men frigjøre ikke det. Vi kompilere den med Lag og kjøre den under Valgrind, og vi ser at mens vi har ingen minnefeil, Vi har en lekkasje. Det er 16 byte definitivt tapt, noe som betyr at pekeren til at minnet var ikke i omfang når programmet avsluttes. Nå, Valgrind ikke gi oss massevis av informasjon om lekkasjen, men hvis vi følger denne lille oppmerksom på at det gir ned mot bunnen av rapporten å kjøre med - lekkasje-sjekk = full å se detaljer lekket minne, vi får mer informasjon. Nå, i haugen sammendraget, Valgrind forteller oss hvor minnet som gikk tapt var opprinnelig tildelt. Akkurat som vi vet fra å se i kildekoden, Valgrind forteller oss at vi lekket minnet fordeles med en oppfordring til malloc på linje 8 av leak.c i den viktigste funksjonen. Ganske kjekk liten. Valgrind kategoriserer lekkasjer ved hjelp av disse begrepene: Definitivt mistet - dette er heap allokert minne som programmet ikke lenger har en peker. Valgrind vet at du en gang hadde pekeren, men har siden mistet oversikten over det. Dette minnet er definitivt lekket. Indirekte tapt - dette er heap allokert minne som de eneste pekere til det også går tapt. For eksempel, hvis du har mistet pekeren til den første noden en lenket liste, da den første noden selv ville være definitivt tapt, mens eventuelle etterfølgende noder vil bli indirekte tapt. Muligens tapt - dette er heap allokert minne som Valgrind ikke kan være sikker på om det er en peker eller ikke. Fortsatt kan nås er heap allokert minne som programmet fortsatt har en peker på exit, som betyr vanligvis at en global variabel poeng til det. For å se etter disse lekkasjene, vil du også nødt til å inkludere muligheten - Fortsatt-nås = yes i påkallelse av Valgrind. Disse ulike tilfeller kan kreve ulike strategier for å rense dem opp, men lekkasjer bør elimineres. Dessverre kan fikse lekkasjer være vanskelig å gjøre, siden feil samtaler til gratis kan blåse opp programmet. For eksempel, hvis vi ser på invalid_free.c, ser vi et eksempel på dårlig hukommelse deallocation. Hva bør være en enkel samtale for å frigjøre hele blokken minne peker til int_block, har i stedet blitt et forsøk på å frigjøre hver int størrelse seksjon av minnet individuelt. Dette vil mislykkes katastrofalt. Boom! Hva en feil. Dette er definitivt ikke bra. Hvis du sitter fast med denne typen feil, skjønt, og du vet ikke hvor du skal lete, falle tilbake på din nye bestevenn. Du gjettet det - Valgrind. Valgrind, som alltid, vet nøyaktig hva som skjer. Alloc og gratis teller ikke samsvarer. Vi har en Alloc og 4 frigjør. Og Valgrind forteller oss også hvor den første dårlig gratis samtale - den som utløste blowup - kommer fra - linje 16. Som du ser, dårlige samtaler til gratis er virkelig ille, så vi anbefaler å la programmet lekkasje mens du jobber med å få funksjonaliteten riktig. Begynne å lete etter lekkasjer etter at programmet fungerer som det skal, uten andre feil. Og det er alt vi har for denne videoen. Nå hva venter du på? Gå kjøre Valgrind i dine programmer akkurat nå. Mitt navn er Nate Hardison. Dette er CS50. [CS50.TV]