[Powered by Google Translate] [Valgrind] [Nate Hardison, Harvard University] To je CS50, CS50.TV] Některé z nejtěžších chyb v programech C pocházejí z nezvládnutí paměti. Existuje obrovské množství způsobů, jak šroub věci do pořádku, včetně rozdělení nesprávné množství paměti, zapomněl inicializovat proměnné, psaní před nebo po skončení pufru, a uvolnění udržet paměť vícekrát. Tyto příznaky se pohybují od přerušovaných pády k záhadně přepsaných hodnot, často v místech a časech daleko vzdálených od původního chyby. Trasování sledované problematiky zpět na základní příčinu může být náročné, ale naštěstí je tu užitečné program nazvaný Valgrind které může udělat hodně pomoci. Spuštění programu pod Valgrind k tomu, aby Rozsáhlá kontrola přidělení haldy paměti a přístupy. Při Valgrind zjistí problém, to vám dává bezprostřední, přímé informace, které vám umožní snáze najít a opravit problém. Valgrind také zprávy o méně smrtící problémy s pamětí, jako úniky paměti, přidělování paměti haldy, a zapomněl uvolnit ji. Stejně jako náš překladač, klap, v našem debuggeru GDB, Valgrind je svobodný software, a je instalován na zařízení. Valgrind běží na binární spustitelný soubor, není vaše. c nebo. h soubory zdrojových kódů, takže se ujistěte, jste kompiloval up-to-date kopii vašeho programu pomocí řinčet nebo Make. Pak může spuštěním programu podle Valgrind být tak jednoduché, jak jen zkratky standardní programu příkaz se slovem Valgrind, který se spustí Valgrind a spustí program, uvnitř ní. Při spuštění, Valgrind se některé složité jiggering nastavit spustitelný pro paměťové kontroly, tak to může trvat trochu se dostat nahoru a běží. Program pak bude provádět normálně, ať už je to mnohem pomaleji, a když to skončí, bude Valgrind vytisknout souhrn jeho využití paměti. Pokud vše půjde dobře, bude to vypadat nějak takto: V tomto případě,. / Clean_program je cesta k programu chci spustit. A i když to člověk nemá žádné argumenty, pokud se to jsem právě připínáček je na konci tohoto příkazu jako obvykle. Clean program je jen hloupá program, který jsem vytvořil , která rozděluje prostor pro blok ints na haldě, dát nějaké hodnoty uvnitř nich, a uvolní celý blok. To je to, co natáčíte pro, bez chyb a bez úniku. Dalším důležitým metrika je celkový počet přidělených bytů. V závislosti na programu, pokud vaše přidělení jsou v MB nebo vyšší, jste pravděpodobně děláte něco špatně. Jste zbytečně ukládání duplicitní? Používáte haldy pro skladování, kdy by bylo lepší použít zásobník? Takže, chyby paměti je opravdu zlý. Čím více zjevné ty způsobují velkolepé zhroucení, ale i pak to může ještě být těžké určit co přesně vedlo k havárii. Více zákeřně, program s pamětí chybou může ještě sestavit čistě a může stále zdá pracovat správně protože se podařilo získat štěstí většinu času. Po několika "úspěšných výsledků," můžete jen myslet, že srážka je náhoda v počítači, ale počítač se nikdy nemýlí. Běh Valgrind vám může pomoci vystopovat příčinu viditelných chyb paměti stejně jako najít číhá chyby, které nejsou ještě ani vědět. Pokaždé, když Valgrind zjistí problém, vytiskne informace o tom, co to pozorováno. Každá položka je poměrně stručná - řádka zdrojového protiprávního pokynu, co je problém, a trochu info o zapojených paměti - ale často je to dost informací nasměrovat pozornost na správném místě. Zde je příklad Valgrind běží na kočárku programu , který dělá neplatný čtení haldy paměti. Vidíme žádné chyby nebo varování v kompilaci. Uh-oh, chyba shrnutí říká, že tam jsou dvě chyby - dva neplatné čte velikosti 4 - bytů, že je. Oba špatné čte došlo v hlavní funkce invalid_read.c, první na řádku 16 a druhý na řádku 19. Pojďme se podívat na kód. Vypadá to, že první výzvy k printf se snaží přečíst jednu int za koncem našeho bloku paměti. Pokud se podíváme zpět na výstupu Valgrind je, vidíme, že Valgrind nám řekl přesně to. Adresa snažíme číst začne 0 bajtů za koncem bloku o velikosti 16 bajtů - čtyři 32-bitové ints že přidělené. To znamená, že adresa jsme se snažili přečíst začíná na samém konci našeho bloku, stejně jako vidíme v našem špatném printf hovoru. Nyní by neplatná čtenářů zdát, že velký problém, ale pokud používáte tato data pro řízení toku programu - Například jako součást if nebo loop - pak se věci mohou tiše pokazí. Podívejte se, jak mohu spustit invalid_read programu a nic neobvyklého děje. Scary, co? Nyní se pojďme podívat na některé další druhy chyb, které se mohou vyskytnout v kódu, a uvidíme, jak Valgrind detekuje. Právě jsme viděli příklad s invalid_read, takže teď pojďme podívat o invalid_write. Opět platí, že žádné chyby nebo varování v kompilaci. Dobře, Valgrind říká, že tam jsou dvě chyby v tomto programu - a invalid_write a invalid_read. Pojďme se podívat na tento kód. Vypadá to, že máme instanci klasické strlen plus jeden bug. Kód není malloc navíc bajt prostoru pro / 0 charakteru, takže když str kopie šla psát to na ssubstrlen "cs50 skály!" to napsal 1 byte za koncem našeho bloku. Invalid_read přichází, když uděláme naši výzvu printf. Printf skončí čtení neplatné paměti při čtení / 0 znak jak to vypadá na konci tohoto E řetězec je tisk. Ale nic z toho unikl Valgrind. Je vidět, že to zachytil invalid_write jako součást str kopie na řádku 11 hlavní, a invalid_read je součástí printf. Rock on, Valgrind. Opět, mohlo by to vypadat jako velký problém. Můžeme spustit tento program znovu a znovu mimo Valgrind a není vidět žádné chybové příznaky. Nicméně, pojďme se podívat na nepatrnou variací tohoto vidět jak se věci mohou opravdu špatné. Takže, uděleno, jsme zneužívají věci víc než jen trochu v tomto kódu. Jsme jen přidělování prostor na haldě pro dva řetězce délka cs50 hornin, Tentokrát, když si vzpomněl / 0 znak. Ale pak jsme se hodit v super-dlouhé řetězce do paměťového bloku že S je ukazuje. Jaký dopad bude to mít na paměti, že blok T odkazuje na? No, pokud T poukazuje na paměti, že to prostě vedle S, přichází těsně po ní, pak bychom mohli přepsat část T. Pojďme spuštěním tohoto kódu. Podívejte se na to, co se stalo. Řetězce jsme uložené v našich haldy blocích obou zřejmě tištěny správně. Nic se zdá v pořádku vůbec. Nicméně, vraťme se do našeho kódu a komentář mimo řádek, kde jsme kopírovat cs50 skály do druhého bloku paměti, který by ukazoval t. Teď, když jsme se spustit tento kód, který jsme měli zobrazit pouze obsah prvního bloku paměti vytisknout. Whoa, i když jsme neměli str kopie všechny znaky do druhého bloku haldy, ten, na který ukazuje T, dostaneme vytiskněte. Opravdu, string jsme nacpal do našeho prvního bloku obsadil první blok a do druhého bloku, Díky všechno zdá normální. Valgrind, když nám říká skutečný příběh. Tam jdeme. Všechny ty neplatné čte a zapisuje. Pojďme se podívat na příklad jiného druhu chyby. Zde uděláme něco poněkud nešťastným. Jsme chytit prostor pro int na haldě, a my inicializaci int ukazatel - p - přejděte na tomto prostoru. Nicméně, zatímco naše ukazatel je inicializován, údaje, které to poukazují jen se co nevyžádané je v této části haldy. Takže když jsme se načíst tato data do int i, jsme technicky inicializovat i, ale my to s nevyžádanou dat. Výzva k uplatnění, což je šikovný ladění makra definovány v výstižně pojmenované uplatnit knihovny, přeruší program, pokud jeho zkušební stav se nezdaří. To znamená, že pokud je i není 0. V závislosti na tom, co bylo v haldy prostoru, který by ukazoval p, tento program může fungovat někdy i selhání jindy. Pokud to funguje, jsme jen dostat štěstí. Kompilátor nebude chytit tuto chybu, ale Valgrind jisti, že. Zde vidíme chybu vyplývající z naší použití tohoto nevyžádané údajů. Když přidělit haldy paměti, ale to není navrátit, nebo uvolnit jej, , která se nazývá únik. Pro malé, krátkotrvající program, který běží a okamžitě východy, úniky jsou poměrně neškodné, ale pro projekt větší velikosti a / nebo dlouhověkost, i malá netěsnost může zhoršit do něčeho hlavní. Pro CS50, my očekáváme, že postarat o uvolnění všech haldy paměti, které přidělit, protože chceme, abyste vybudovat dovednosti správně zvládnout ruční proces vyžaduje C. Chcete-li tak učinit, musí váš program mít přesné one-to-one korespondence mezi malloc a bezplatná volání. Naštěstí, může Valgrind pomůže s úniky paměti taky. Zde je děravý program s názvem leak.c, že ​​přiděluje prostor na haldě, píše, ale není to uvolnit. Jsme jej zkompilovat s Make a spusťte jej pod Valgrind, a vidíme, že, zatímco my máme žádné chyby paměti, máme jednu díru. K dispozici je 16 bytů definitivně ztratil, což znamená, že ukazatel na tuto paměť nebyla v rozsahu, když program skončil. Nyní, Valgrind nedává tuny informací o úniku, ale pokud se budeme řídit tímto malou poznámku, že to dává dolů směrem ke spodní části své zprávy znovu spustit s - leak-check = full Pro zobrazení detailních informací o unikly paměti, dostaneme další informace. Nyní, v haldy shrnutí, Valgrind nám říká, kde se paměť, která byla ztracena původně přiděleny. Stejně jako známe z pohledu ve zdrojovém kódu, Valgrind nás informuje, že jsme unikly paměti přiděleny s výzvou k malloc na lince 8 leak.c v hlavní funkci. Docela šikovný. Valgrind kategorizuje úniky pomocí tyto pojmy: Definitivně ztratil - to je halda přidělené paměti na které je program již má ukazatel. Valgrind ví, že jsi kdysi měl ukazatel, ale od té doby ztratil přehled o tom. Tato paměť je určitě unikly. Nepřímo ztratil - to je halda přidělené paměti , na které se jen ukazatele na ní jsou také ztraceny. Například, pokud jste ztratili svůj ukazatel na první uzel propojeného seznamu, pak první uzel samo o sobě by být definitivně ztratil, zatímco jakékoli následné uzly by se nepřímo ztracena. Možná ztratil - to je halda přidělené paměti na které Valgrind nemůže být jist, zda je ukazatel, nebo ne. Stále dosažitelný je haldy přidělené paměti na které je program ještě má ukazatel na výstupu, což obvykle znamená, že globální proměnná na něj ukazuje. Chcete-li zkontrolovat tyto úniky, budete muset zadat i možnost - Stále dosažitelné = yes v vyvolání Valgrind. Tyto různé případy mohou vyžadovat různé strategie pro jejich čištění up, ale úniky by měly být odstraněny. Bohužel, kterým se stanoví úniky být těžké udělat, protože nesprávné volání zdarma může vyhodit svůj program. Například, když se podíváme na invalid_free.c, vidíme příklad špatného paměti deallocation. Co by mělo být jedno volání uvolnit celý blok paměti, na který ukazuje int_block, místo toho se snaží osvobodit každý int velikosti sekci z paměti individuálně. To se nezdaří katastrofálně. Boom! Co chybě. To rozhodně není dobré. Pokud nevíte jak dál s tímto druhem chyby, i když, a nevíte, kam se dívat, opřít o svého nového nejlepšího přítele. Uhodli jste - Valgrind. Valgrind, jako vždy, přesně ví, co se děje. V Alloc a volný počty neodpovídají. Máme 1 Alloc a 4 osvobozuje. A Valgrind nám také říká, kde se první špatné volání zdarma - ten, který spustil explozi - přichází z - linka 16. Jak vidíte, špatné volání zdarma jsou opravdu špatné, takže doporučujeme nechat vašeho programu únik , zatímco vy pracujete na získání funkce správné. Začít hledat únik až po váš program pracuje správně, bez dalších chyb. A to je vše, co jsme dostali za toto video. Tak co ještě čekáte? Přejít běží Valgrind na vašich programů právě teď. Mé jméno je Nate Hardison. To je CS50. [CS50.TV]