[Powered by Google Translate] [Valgrind] [Nate Hardison, Harvard University] Detta är CS50, CS50.TV] Några av de svåraste buggar i C-program kommer från misskötsel av minnet. Det finns ett stort antal sätt att skruva upp saker, inklusive fördelning fel mängd minne, glömmer att initiera variabler, skriver före eller efter slutet av en buffert, och frigör hålla minnet flera gånger. Symptomen varierar från återkommande krascher att mystiskt överskrivna värden, ofta på platser och tider långt bort från den ursprungliga felet. Spåra den observerade problemet tillbaka till den underliggande orsaken kan vara en utmaning, men lyckligtvis finns det en bra program som heter Valgrind som kan göra mycket för att hjälpa. Du kör ett program under Valgrind att aktivera omfattande kontroller av anslagen heap minne och accesser. När Valgrind upptäcker ett problem, det ger dig omedelbar, direkt information som tillåter dig att lättare hitta och åtgärda problemet. Valgrind också rapporter om mindre dödliga minnesproblem, såsom minnesläckor, fördela hög minne, och glömmer att befria den. Liksom vår kompilator, klang, i vår debugger, GDB, Valgrind är fri programvara, och det är installerat på apparaten. Valgrind körs på binära körbara, inte din. c eller. h källfiler kod, så se till att du har sammanställt en up-to-date kopia av ditt program med klang och Make. Sedan kan köra ditt program enligt Valgrind vara så enkelt som att bara prefix standardprogrammet kommandot med ordet Valgrind, som startar Valgrind och kör programmet i den. Vid start, gör Valgrind vissa komplexa jiggering att konfigurera den körbara för minnet kontroller, så det kan ta lite för att få igång. Programmet kommer sedan exekvera normalt, kan det mycket långsammare, och när den är klar, kommer Valgrind ut en sammanfattning av dess minnesanvändning. Om allt går bra kommer det att se ut ungefär så här: I det här fallet. / Clean_program är sökvägen till det program jag vill köra. Och medan detta inte tar några argument, Om det gjorde jag skulle bara tack dem till slutet av kommandot som vanligt. Rent program är bara en dum litet program jag skapade som allokerar utrymme för ett block av ints i stacken, sätta vissa värden inne i dem, och frigör hela blocket. Detta är vad du fotograferar för, inga fel och inga läckor. En annan viktig variabel är det totala antalet tilldelade bytes. Beroende på vilket program, om dina anslag är i megabyte eller högre, du förmodligen gör något fel. Är du lagra onödan dubbletter? Använder du högen för lagring, när det skulle vara bättre att använda stacken? Så kan minnesfel vara riktigt ond. De mer uppenbara dem orsakar spektakulära krascher, men även då kan det ändå vara svårt att sätta fingret på vad som ledde exakt kraschen. Mer lömskt, ett program med en minnesfel kan fortfarande kompilera rent och kan fortfarande verkar fungera korrekt eftersom du lyckats få tur för det mesta. Efter flera "lyckade resultat", du kanske bara tror att en krasch är en lyckträff av datorn, men datorn är aldrig fel. Köra Valgrind kan hjälpa dig att spåra orsaken till synliga minnesfel samt hitta lurar fel du inte ens ännu känner till. Varje gång Valgrind upptäcker ett problem, skriver det information om vad den observerade. Varje objekt är ganska bryskt - källan raden felande instruktionen, vad frågan är, och lite info om de inblandade minne - men ofta är det tillräckligt med information för att rikta er uppmärksamhet på rätt plats. Här är ett exempel på Valgrind körs på en buggy program som gör en ogiltig läsning av heap-minne. Vi ser inga fel eller varningar i sammanställningen. Uh-oh, säger felet sammanfattningen att det finns två fel - två ogiltig läsningar av storlek 4 - byte, alltså. Både dåliga läser inträffade i huvudfunktion invalid_read.c, den första på ledningen 16 och den andra på ledningen 19. Låt oss titta på koden. Ser ut som det första samtalet till printf försöker läsa en int förbi i slutet av vårt minne block. Om vi ​​ser tillbaka på Valgrind produktion, Vi ser att Valgrind berättade just detta. Adressen vi försöker läsa startar 0 byte förbi änden av blocket av storlek 16 byte - fyra 32-bitars Ints som vi tilldelade. Det är, börjar den adress vi försökte läsa rätt i slutet av vår blocket, precis som vi ser i våra dåliga printf samtal. Nu kanske ogiltiga läsningar verkar inte som att stor grej, men om du använder dessa data för att styra flödet av ditt program - till exempel som en del av en if-sats eller loop - då saker kan tyst gå illa. Se hur jag kan köra invalid_read programmet och ingenting av det vanliga händer. Skrämmande, eller hur? Nu ska vi titta på några fler typer av fel som kan uppstå i din kod, och vi får se hur Valgrind upptäcker dem. Vi såg bara ett exempel på en invalid_read, så nu ska vi kolla en invalid_write. Återigen, inga fel eller varningar i sammanställningen. Okej, säger Valgrind att det finns två fel i detta program - och invalid_write och invalid_read. Låt oss kolla in denna kod. Ser ut som vi har fått en instans av den klassiska strlen plus en bugg. Koden inte malloc ett extra byte av utrymme för / 0 tecken, så när str kopia gick att skriva det på ssubstrlen "CS50 rocks!" Det skrev 1 byte förbi i slutet av vår blocket. Den invalid_read kommer när vi gör vår uppmaning till printf. Printf hamnar läsning ogiltig minne när den läser / 0 tecken som det ser ut i slutet av denna E-strängen är det utskrift. Men inget av detta flydde Valgrind. Vi ser att det fångade invalid_write som en del av str kopian på linje 11 i huvud och invalid_read är en del av printf. Rock på, Valgrind. Återigen kan detta verka inte som en stor sak. Vi kan köra programmet om och om igen utanför Valgrind och inte ser några fel symptom. Men låt oss titta på en liten variation av detta att se hur saker och ting kan bli riktigt illa. Så beviljats, vi missbrukar saker mer än bara lite i denna kod. Vi bara fördela utrymme på högen för två strängar längden CS50 stenar, den här gången, komma ihåg / 0 tecken. Men sedan vi slänga in en super-lång sträng i minnet blocket att S pekar på. Vilken effekt kommer att ha på minnet blocket att T pekar på? Tja, om T pekar på minnet det är precis intill S, kommer precis efter det, då vi kanske har skrivit över en del av T. Låt oss köra denna kod. Titta på vad som hände. Strängarna vi lagrade i våra heap blockerar både tycktes ha skrivits ut korrekt. Ingenting verkar fel alls. Men låt oss gå tillbaka till vår kod och kommentera ut raden där vi kopierar CS50 stenar in i det andra minnesblocket, utpekas av t.. Nu, när vi kör den här koden bör vi bara se innehållet i det första minnet blocket skriva ut. Whoa, även om vi inte Str kopia alla tecken i det andra högen blocket pekade en till av T, vi får en utskrift. Faktum strängen vi stoppade i vår första blocket överskred det första blocket och in i den andra blocket, gör allt verkar normalt. Valgrind Men berättar den sanna historien. Där kör vi. Alla dessa ogiltiga läser och skriver. Låt oss titta på ett exempel på en annan typ av fel. Här gör vi något ganska olyckligt. Vi ta plats för en int på högen, och vi initiera en int pekare - p - att peka på det utrymmet. Men medan vår pekare initieras, de data som det pekar på just vad skräp är den delen av högen. Så när vi laddar dessa uppgifter till int i, vi initiera tekniskt jag, men vi gör det med skräp data. Uppmaningen att hävda, vilket är en praktisk felsökning makro definieras i det passande namnet hävda bibliotek, kommer att avbryta programmet om dess prov tillstånd misslyckas. Det är, om i är inte 0. Beroende på vad som var i högen rymden pekas ut av p, detta program kan fungera ibland och misslyckas vid andra tillfällen. Om det fungerar, vi får bara tur. Kompilatorn kommer inte fånga detta fel, men Valgrind att vilja. Där ser vi felet härrör från vår användning av att skräp data. När du tilldela heap minne men inte deallokera det eller frigöra det, som kallas en läcka. För ett litet, kortlivad program som körs och omedelbart avslutas, läckor är ganska ofarliga, men för ett projekt av större storlek och / eller livslängd, även en liten läcka kan förvärra till något större. För CS50, förväntar vi att du ta hand om att befria hela högen minne som du fördela, eftersom vi vill att du ska bygga kompetens att korrekt hantera den manuella processen krävs av C. För att göra detta bör programmet ha en exakt en-till-en korrespondens mellan malloc och gratis samtal. Lyckligtvis kan Valgrind hjälpa dig med minnesläckor också. Här är en läckande program som heter leak.c som fördelar utrymme på högen, skriver till det, men inte befria den. Vi sammanställer det med Make och köra den under Valgrind, och vi ser att även vi har inget minne fel, Vi har en läcka. Det finns 16 byte definitivt förlorade, vilket innebär att pekaren till att minnet inte i omfattning när programmet avslutas. Nu ger Valgrind oss ​​inte en ton av information om läckan, men om vi följer den här lilla notera att det ger ner mot botten av sin rapport att köra med - läckage-check = full för att se alla detaljer om läckt minne, vi kommer att få mer information. Nu, i stacken sammanfattningen, Valgrind berättar om minnet som förlorades ursprungligen tilldelades. Precis som vi vet från att titta i källkoden, Valgrind informerar oss om att vi läckt minnet fördelas med en uppmaning till malloc på rad 8 i leak.c i huvudfunktionen. Ganska tjusig. Valgrind kategoriserar läckor med dessa termer: Definitivt förlorat - detta är hög allokerat minne som programmet inte längre har en pekare. Valgrind vet att du en gång hade pekaren, men har sedan förlorat kontakten med den. Detta minne är definitivt läckt. Indirekt förlorade - detta är hög allokerat minne som de enda pekare till den också går förlorade. Till exempel, om du förlorat din pekare till första noden i en länkad lista, då den första noden själv skulle definitivt förlorat, medan efterföljande noder skulle indirekt förlorad. Möjligen förlorade - detta är hög allokerat minne där Valgrind inte kan vara säker på huruvida det är en pekare eller inte. Fortfarande nås är hög allokerat minne som programmet fortfarande har en pekare vid avfart, vilket innebär oftast att en global variabel pekar på den. För att kontrollera om dessa läckor har du också omfatta möjligheten - Fortfarande-nås = ja i åkallan av Valgrind. Dessa olika ärenden kan kräva olika strategier för rengöring upp dem, men läckage bör undanröjas. Tyvärr kan fastställa läckage vara svårt att göra, eftersom felaktiga samtal till fri kan spränga ditt program. Till exempel, om vi tittar på invalid_free.c, Vi ser ett exempel på dåligt minne avallokering. Vad som borde vara ett enda samtal för att frigöra hela blocket minne utpekas av int_block, har i stället blivit ett försök att befria varje int storlek sektionen av minnet individuellt. Detta kommer att misslyckas katastrofalt. Boom! Vad ett fel. Detta är definitivt inte bra. Om du har fastnat med denna typ av fel, dock, och du vet inte var du ska leta, falla tillbaka på din nya bästa vän. Du gissade det - Valgrind. Valgrind, som alltid, vet exakt vad som händer. Alloc och fria räknas stämmer inte. Vi har 1 Alloc och 4 frigör. Och Valgrind berättar också om den första dåliga fri samtal - den som utlöste blowup - kommer från - linje 16. Som ni ser, dåliga samtal gratis är verkligen dåligt, så vi rekommenderar att låta ditt program läcka medan du arbetar på att få den funktionalitet korrekt. Börja leta efter läckor först efter ditt program fungerar, utan några andra fel. Och det är allt vi har för den här videon. Nu vad väntar du på? Gå köras Valgrind på dina program just nu. Mitt namn är Nate Hardison. Detta är CS50. [CS50.TV]