[Powered by Google Translate] [Valgrind]
[Нейт Hardison, Харвардски университет]
Това е CS50, CS50.TV]
Някои от най-трудните бъгове в програмите C
идват от неправилното управление на паметта.
Има огромен брой начини да се притеснявам нещата,
включително разпределянето на погрешно размера на паметта,
забравяйки да се инициализира променлива,
писмено преди или след края на буфер,
и освобождаване на памет няколко пъти.
Симптомите варират от периодични катастрофи
мистериозно презаписани стойности,
често на места и часове, далеч от оригиналния грешка.
Проследяване на наблюдавания проблем до основната причина корен
може да бъде предизвикателство,
но за щастие е полезна програма, наречена Valgrind
, че може да направи много, за да помогне.
>> Можете да стартирате програмата под Valgrind, за да се даде възможност
скъпоструваща проверка на отпуснатите натрупаш памет и достъпи.
Когато Valgrind открие проблем, той ви дава незабавен,
пряка информация, която ви позволява да
по-лесно да намерите и да реши проблема.
Valgrind и доклади за по-малко смъртоносни въпроси памет,
като изтичане на памет, разпределяне на куп памет,
и забравят да го освободи.
Както компилатор, звъня в нашата дебъгер, GDB,
Valgrind е свободен софтуер, и то се инсталира на уреда.
Valgrind работи на двоичен,
не си в з файлове с изходен код,
така че да сте сигурни, че са го направили в крак с времето копие на вашата програма
звъня или Марка
След това, вашата програма по Valgrind може да бъде
толкова просто като поставим стандартната команда програма с думата Valgrind,
, която започва Valgrind и изпълнява програмата вътре в него.
При стартиране, Valgrind прави някакъв сложен
jiggering да конфигурирате изпълнимия файл за проверките на паметта,
така че може да отнеме малко, за да се изправи и да работи.
След това програмата ще бъде изпълнена, ако тя трябва да бъде много по-бавно,
и когато тя приключи, Valgrind ще се отпечатат резюме на паметта му използване.
Ако всичко върви добре, той ще изглежда нещо като това:
В този случай. / Clean_program
е път към програмата Искам да изпълня.
И докато това не предприемат никакви аргументи,
ако го е направил аз току-що ги привързват до края на командата, както обикновено.
Чисто програма е просто глупава малка програма съм създал
, която заделя място за блок от цели числа на хийпа,
постави някои стойности вътре в тях, и освобождава целия блок.
Това е това, което снимате, грешки и няма течове.
>> Друг важен показател е общият брой на разпределените байта.
В зависимост от програмата, ако отпуснатите средства са в мегабайта или по-високи,
вие вероятно сте прави нещо нередно.
Възможно ли е ненужно съхраняване на дубликати?
Използвате ли куп за съхранение, когато би било добре да се използва стека?
Така че, грешки в паметта може да бъде наистина зло.
Колкото по-явни причини зрелищни катастрофи,
но дори и тогава тя все още може да бъде трудно да се установят
какво точно е довело до катастрофата.
По-коварно, програма с памет грешка
все още могат да съставят чисто
и все още може да изглежда да работи правилно
защото сте успели да получите късмет през повечето време.
След няколко успешни резултати ",
може би просто мисля, че катастрофата е просто случайност на компютъра,
но компютърът никога не греши.
>> Работещи Valgrind може да ви помогне да следите за определяне на причината видими грешки памет
както и да открият дебнат грешки все още дори не знаят.
Всеки път, Valgrind открие проблем, той ще отпечатва информация за това, което наблюдава.
Всеки елемент е доста лаконични -
източник на на нарушител инструкции, какъв е проблемът,
и малко информация за въпросната памет -
но често това е достатъчно информация, за да насоча вниманието ви на правилното място.
Ето един пример за Valgrind на бъги програма
, който прави невалиден четене на куп памет.
Виждаме няма грешки или предупреждения в съставянето.
О-о, грешката резюме казва, че има две грешки -
невалиден прочитания с размер 4 - байта, е това.
Както лошо прочитания, настъпили в основната функция на invalid_read.c,
първо по линия 16 и второ на линия 19.
Нека да погледнем в кода.
Изглежда, че първата покана за ФОРМАТ опитва да чете един вътр миналото края на нашата памет блок.
Ако погледнем назад към изход Valgrind
ние виждаме, че Valgrind ни каза точно това.
Адресът, на който ние се опитваме да прочетете започва 0 байта
след края на блока с размер 16 байта -
четири 32-битови цели числа, които ние разпределени.
Това означава, че на адреса, ние се опитваме да прочетете започва точно в края на нашия блок,
точно както виждаме в лошо ФОРМАТ повикване.
Сега, невалидни прочитания може да не изглежда, че голяма сделка,
но ако използвате, че данните, за да се контролира потока на вашата програма -
Например, като част от, ако изявление или контур -
тогава нещата може безшумно да отидете лошо.
Гледай как мога да тичам invalid_read програма
и нищо необичайно не се случва.
Страшно, нали?
>> Сега, нека да разгледаме още няколко вида грешки, които можете да срещнете в кода си,
и ще видим колко Valgrind ги открива.
Току-що видях пример на invalid_read,
така че сега нека проверим на invalid_write.
Отново, няма грешки или предупреждения в съставянето.
Добре, Valgrind казва, че има две грешки в тази програма -
и invalid_write и invalid_read.
Да проверим този код.
Изглежда, че имаме копие на класическия strlen плюс един бъг.
Кодексът не изчистване допълнително байт на пространството
за характер / 0
така че, когато ул. копие отидох да го пишете на ssubstrlen "cs50 скали!"
го е написал 1 байт след края на нашия блок.
На invalid_read идва, когато ние правим нашия призив да ФОРМАТ.
ФОРМАТ завършва четене невалидна памет, когато се чете / 0 характер
, колкото изглежда в края на тази струна печат.
Но нищо от това не е избягал Valgrind.
Ние виждаме, че я хвана invalid_write като част от ул. копие
по линия 11 на основния и invalid_read е част от ФОРМАТ.
Rock, Valgrind.
Отново, това може да не изглежда като една голяма сделка.
Да стартирате тази програма отново и отново извън Valgrind
и не виждам грешки симптоми.
>> Все пак, нека погледнем в лек вариант на това, за да се види
как нещата могат да се получат наистина лошо.
Така че, даденост, ние се злоупотребява неща повече, отколкото само за малко в този кодекс.
Ние сме само разпределението на място на куп за две струни
дължината на cs50 скали,
този път, спомняйки си / 0 характер.
Но тогава ние се хвърлят в супер-дълъг низ в паметта блок
че S е насочена.
Какъв ефект ще има това върху паметта блок, че T точки?
Е, ако T точки за памет, която е в непосредствена близост до S,
идващи след него,
тогава бихме могли да напише част на Т.
Нека да изпълните този код.
Виж какво се е случило.
Низове, съхранявани в нашите натрупаш блокове двете да са отпечатани правилно.
Нищо не изглежда наред на всички.
Все пак, нека се върнем в нашия код и
коментар на линията, където копирате cs50 скали
във втория блок от паметта, посочи от тон.
Сега, когато стартирате този код трябва да
само съдържанието на първия блок на паметта разпечатате.
Уау, въпреки че не сме ул. копие
герой във втората купчина блок, посочи от T,
за печат.
Всъщност, низ пъхна в първата нашия блок
опустошава първи блок и във втория блок,
всичко изглежда нормално.
Valgrind, обаче, ни разказва истинската история.
Точно така.
Всички тези невалиден чете и пише.
>> Нека разгледаме един пример от друг вид грешка.
Тук правим нещо доста жалко.
Ние вземете пространство за вътр на куп,
и ние се инициализира INT показалеца - стр. - да се отбележи, че пространството.
Въпреки това, докато ни показалеца се инициализира,
данните, сочещи към каквото и боклуци е в тази част на куп.
Така че, когато се зареди, че данните в Int аз,
технически и инициализира,
но го правим с боклуци данни.
Поканата да се твърди, който е удобен макро отстраняване на грешки
определени в подходящо име, се твърди, библиотека,
ще приключи програмата, ако не успее своя тест състояние.
Това е, ако не е 0.
В зависимост от това, което е в купчината пространство, посочи от стр.
тази програма може да работи понякога и не в други времена.
Ако тя работи, ние просто късмет.
Компилаторът няма да хване тази грешка, но Valgrind сигурен, че ще.
Там виждаме грешка, произтичащи от използването на данните, че боклуци.
>> Когато разпределят куп памет, но не го преразпредели или да го освободи,
, което се нарича изтичане на информация.
За една малка, краткотрайна програма, която работи и веднага изходи,
течове са сравнително безобидни,
но за проект на по-голям размер и / или дълголетие,
дори малък теч може да утежни в нещо голямо.
За CS50, ние очакваме да
да се грижи за освобождаването на всички на куп памет, която разпределя,
тъй като ние искаме да изградят умения правилно да се справят с ръчен процес
изисква от C.
За да направите това, вашата програма трябва да има точно
едно-към-едно кореспонденция между изчистване и безплатни разговори.
За щастие, Valgrind може да ви помогне с изтичане на памет.
Тук е спукан програма, наречена leak.c, че заделя
пространство на куп, пише за него, но не го освободи.
Ние го компилирате с грим и да го стартирате под Valgrind,
и виждаме, че, докато ние нямаме грешки в паметта,
ние имаме един теч.
Има 16 байта определено изгубени,
което означава, че показалецът, че паметта не е в обхвата, когато излезе програмата.
Сега, Valgrind не ни даде тон на информация за теча,
но ако следваме тази малка бележка, че тя дава надолу към дъното на доклада си
да поднови с изтичане на проверка = пълно
За да видите пълна информация за протекли памет,
ще получите повече информация.
Сега, в резюме на куп,
Valgrind ни казва къде паметта, която е била загубена, разпределена първоначално.
Точно както знаем в изходния код,
Valgrind ни информира, че пропускам паметта
разпределени с призив за изчистване на линия 8 на leak.c
основната функция.
Доста готин.
>> Valgrind категоризира течове, използващи тези условия:
Определено губи - това е куп заделената памет
, до която програмата вече няма показалеца.
Valgrind знае, че някога е имал показалеца, но тъй като са изгубили следите от него.
Тази памет определено е изтекла информация.
Индиректно губи - това е куп заделената памет
които само указатели към него също така се губят.
Например, ако сте загубили показалеца на първия възел на свързан списък,
след първата възел определено ще бъде загубен,
докато всички последващи възли ще бъдат косвено загубени.
Възможно е загубил - това е куп заделената памет
, в която Valgrind не може да бъде сигурен дали има указател или не.
Все пак достъпен е купчина заделената памет
, до която програмата все още има указател на изход,
което обикновено означава, че глобална променлива точки към него.
За да проверите за тези течове, вие също така ще трябва да включите опцията
- Все още достижим = да
в позоваването на Valgrind.
>> Тези различни случаи могат да изискват различни стратегии за почистването им,
но течове трябва да бъдат премахнати.
За съжаление, определяне на течове може да бъде трудно да се направи,
тъй като неверни повиквания към свободен могат да взривят вашата програма.
Например, ако погледнем в invalid_free.c
виждаме пример за лоша памет deallocation.
Каква трябва да бъде едно обаждане, за да се освободи целия блок
на паметта, посочи от int_block,
вместо това се превърна в опит да се освободи всеки INT-голяма част
на паметта индивидуално.
Това ще се провали катастрофално.
Boom! Каква грешка.
Това определено не е добре.
Ако сте остана с този вид грешка, макар и не знаете къде да търсите,
падне обратно на новия си най-добър приятел.
Вие познахте - Valgrind.
Valgrind, както винаги, знае точно какво става.
Заделянето на памет и безплатен брой не съвпадат.
Имаме един заделянето на памет и 4 освобождава.
И Valgrind също така ни казва къде първото лошо безплатно обаждане
идва от този, който предизвика скандал -
линия 16.
Както виждате, лошите разговори, за да освободите са наистина лоши,
затова ви препоръчваме отдаване под наем на вашата програма теч
докато работите върху функционалността правилно.
Започнете да търсите за течове само след вашата програма работи правилно,
без никакви други грешки.
>> И това е всичко, което имам за това клипче.
Сега, какво чакате?
Тичам Valgrind на програмите си точно сега.
Моето име е Нейт Hardison. Това е CS50. [CS50.TV]