1 00:00:00,000 --> 00:00:02,000 [Powered by Google Translate] [Valgrind] 2 00:00:02,000 --> 00:00:05,000 [Нейт Hardison, Харвардски университет] 3 00:00:05,000 --> 00:00:07,000 Това е CS50, CS50.TV] 4 00:00:07,000 --> 00:00:10,000 Някои от най-трудните бъгове в програмите C 5 00:00:10,000 --> 00:00:13,000 идват от неправилното управление на паметта. 6 00:00:13,000 --> 00:00:15,000 Има огромен брой начини да се притеснявам нещата, 7 00:00:15,000 --> 00:00:17,000 включително разпределянето на погрешно размера на паметта, 8 00:00:17,000 --> 00:00:20,000 забравяйки да се инициализира променлива, 9 00:00:20,000 --> 00:00:23,000 писмено преди или след края на буфер, 10 00:00:23,000 --> 00:00:25,000 и освобождаване на памет няколко пъти. 11 00:00:25,000 --> 00:00:28,000 Симптомите варират от периодични катастрофи 12 00:00:28,000 --> 00:00:30,000 мистериозно презаписани стойности, 13 00:00:30,000 --> 00:00:34,000 често на места и часове, далеч от оригиналния грешка. 14 00:00:34,000 --> 00:00:37,000 Проследяване на наблюдавания проблем до основната причина корен 15 00:00:37,000 --> 00:00:39,000 може да бъде предизвикателство, 16 00:00:39,000 --> 00:00:42,000 но за щастие е полезна програма, наречена Valgrind 17 00:00:42,000 --> 00:00:44,000 , че може да направи много, за да помогне. 18 00:00:44,000 --> 00:00:47,000 >> Можете да стартирате програмата под Valgrind, за да се даде възможност 19 00:00:47,000 --> 00:00:50,000 скъпоструваща проверка на отпуснатите натрупаш памет и достъпи. 20 00:00:50,000 --> 00:00:53,000 Когато Valgrind открие проблем, той ви дава незабавен, 21 00:00:53,000 --> 00:00:56,000 пряка информация, която ви позволява да 22 00:00:56,000 --> 00:00:58,000 по-лесно да намерите и да реши проблема. 23 00:00:58,000 --> 00:01:01,000 Valgrind и доклади за по-малко смъртоносни въпроси памет, 24 00:01:01,000 --> 00:01:04,000 като изтичане на памет, разпределяне на куп памет, 25 00:01:04,000 --> 00:01:07,000 и забравят да го освободи. 26 00:01:07,000 --> 00:01:10,000 Както компилатор, звъня в нашата дебъгер, GDB, 27 00:01:10,000 --> 00:01:14,000 Valgrind е свободен софтуер, и то се инсталира на уреда. 28 00:01:14,000 --> 00:01:16,000 Valgrind работи на двоичен, 29 00:01:16,000 --> 00:01:20,000 не си в з файлове с изходен код, 30 00:01:20,000 --> 00:01:23,000 така че да сте сигурни, че са го направили в крак с времето копие на вашата програма 31 00:01:23,000 --> 00:01:25,000 звъня или Марка 32 00:01:25,000 --> 00:01:28,000 След това, вашата програма по Valgrind може да бъде 33 00:01:28,000 --> 00:01:32,000 толкова просто като поставим стандартната команда програма с думата Valgrind, 34 00:01:32,000 --> 00:01:35,000 , която започва Valgrind и изпълнява програмата вътре в него. 35 00:01:35,000 --> 00:01:38,000 При стартиране, Valgrind прави някакъв сложен 36 00:01:38,000 --> 00:01:41,000 jiggering да конфигурирате изпълнимия файл за проверките на паметта, 37 00:01:41,000 --> 00:01:44,000 така че може да отнеме малко, за да се изправи и да работи. 38 00:01:44,000 --> 00:01:48,000 След това програмата ще бъде изпълнена, ако тя трябва да бъде много по-бавно, 39 00:01:48,000 --> 00:01:52,000 и когато тя приключи, Valgrind ще се отпечатат резюме на паметта му използване. 40 00:01:52,000 --> 00:01:58,000 Ако всичко върви добре, той ще изглежда нещо като това: 41 00:01:58,000 --> 00:02:01,000 В този случай. / Clean_program 42 00:02:01,000 --> 00:02:04,000 е път към програмата Искам да изпълня. 43 00:02:04,000 --> 00:02:06,000 И докато това не предприемат никакви аргументи, 44 00:02:06,000 --> 00:02:09,000 ако го е направил аз току-що ги привързват до края на командата, както обикновено. 45 00:02:09,000 --> 00:02:12,000 Чисто програма е просто глупава малка програма съм създал 46 00:02:12,000 --> 00:02:15,000 , която заделя място за блок от цели числа на хийпа, 47 00:02:15,000 --> 00:02:19,000 постави някои стойности вътре в тях, и освобождава целия блок. 48 00:02:19,000 --> 00:02:23,000 Това е това, което снимате, грешки и няма течове. 49 00:02:23,000 --> 00:02:27,000 >> Друг важен показател е общият брой на разпределените байта. 50 00:02:27,000 --> 00:02:32,000 В зависимост от програмата, ако отпуснатите средства са в мегабайта или по-високи, 51 00:02:32,000 --> 00:02:34,000 вие вероятно сте прави нещо нередно. 52 00:02:34,000 --> 00:02:37,000 Възможно ли е ненужно съхраняване на дубликати? 53 00:02:37,000 --> 00:02:40,000 Използвате ли куп за съхранение, когато би било добре да се използва стека? 54 00:02:40,000 --> 00:02:43,000 Така че, грешки в паметта може да бъде наистина зло. 55 00:02:43,000 --> 00:02:46,000 Колкото по-явни причини зрелищни катастрофи, 56 00:02:46,000 --> 00:02:49,000 но дори и тогава тя все още може да бъде трудно да се установят 57 00:02:49,000 --> 00:02:51,000 какво точно е довело до катастрофата. 58 00:02:51,000 --> 00:02:54,000 По-коварно, програма с памет грешка 59 00:02:54,000 --> 00:02:56,000 все още могат да съставят чисто 60 00:02:56,000 --> 00:02:58,000 и все още може да изглежда да работи правилно 61 00:02:58,000 --> 00:03:01,000 защото сте успели да получите късмет през повечето време. 62 00:03:01,000 --> 00:03:04,000 След няколко успешни резултати ", 63 00:03:04,000 --> 00:03:07,000 може би просто мисля, че катастрофата е просто случайност на компютъра, 64 00:03:07,000 --> 00:03:10,000 но компютърът никога не греши. 65 00:03:10,000 --> 00:03:13,000 >> Работещи Valgrind може да ви помогне да следите за определяне на причината видими грешки памет 66 00:03:13,000 --> 00:03:18,000 както и да открият дебнат грешки все още дори не знаят. 67 00:03:18,000 --> 00:03:22,000 Всеки път, Valgrind открие проблем, той ще отпечатва информация за това, което наблюдава. 68 00:03:22,000 --> 00:03:24,000 Всеки елемент е доста лаконични - 69 00:03:24,000 --> 00:03:27,000 източник на на нарушител инструкции, какъв е проблемът, 70 00:03:27,000 --> 00:03:30,000 и малко информация за въпросната памет - 71 00:03:30,000 --> 00:03:34,000 но често това е достатъчно информация, за да насоча вниманието ви на правилното място. 72 00:03:34,000 --> 00:03:37,000 Ето един пример за Valgrind на бъги програма 73 00:03:37,000 --> 00:03:40,000 , който прави невалиден четене на куп памет. 74 00:03:40,000 --> 00:03:49,000 Виждаме няма грешки или предупреждения в съставянето. 75 00:03:49,000 --> 00:03:53,000 О-о, грешката резюме казва, че има две грешки - 76 00:03:53,000 --> 00:03:56,000 невалиден прочитания с размер 4 - байта, е това. 77 00:03:56,000 --> 00:04:01,000 Както лошо прочитания, настъпили в основната функция на invalid_read.c, 78 00:04:01,000 --> 00:04:04,000 първо по линия 16 и второ на линия 19. 79 00:04:04,000 --> 00:04:06,000 Нека да погледнем в кода. 80 00:04:06,000 --> 00:04:11,000 Изглежда, че първата покана за ФОРМАТ опитва да чете един вътр миналото края на нашата памет блок. 81 00:04:11,000 --> 00:04:13,000 Ако погледнем назад към изход Valgrind 82 00:04:13,000 --> 00:04:16,000 ние виждаме, че Valgrind ни каза точно това. 83 00:04:16,000 --> 00:04:19,000 Адресът, на който ние се опитваме да прочетете започва 0 байта 84 00:04:19,000 --> 00:04:22,000 след края на блока с размер 16 байта - 85 00:04:22,000 --> 00:04:25,000 четири 32-битови цели числа, които ние разпределени. 86 00:04:25,000 --> 00:04:29,000 Това означава, че на адреса, ние се опитваме да прочетете започва точно в края на нашия блок, 87 00:04:29,000 --> 00:04:32,000 точно както виждаме в лошо ФОРМАТ повикване. 88 00:04:32,000 --> 00:04:36,000 Сега, невалидни прочитания може да не изглежда, че голяма сделка, 89 00:04:36,000 --> 00:04:39,000 но ако използвате, че данните, за да се контролира потока на вашата програма - 90 00:04:39,000 --> 00:04:42,000 Например, като част от, ако изявление или контур - 91 00:04:42,000 --> 00:04:45,000 тогава нещата може безшумно да отидете лошо. 92 00:04:45,000 --> 00:04:47,000 Гледай как мога да тичам invalid_read програма 93 00:04:47,000 --> 00:04:50,000 и нищо необичайно не се случва. 94 00:04:50,000 --> 00:04:52,000 Страшно, нали? 95 00:04:52,000 --> 00:04:56,000 >> Сега, нека да разгледаме още няколко вида грешки, които можете да срещнете в кода си, 96 00:04:56,000 --> 00:04:59,000 и ще видим колко Valgrind ги открива. 97 00:04:59,000 --> 00:05:01,000 Току-що видях пример на invalid_read, 98 00:05:01,000 --> 00:05:04,000 така че сега нека проверим на invalid_write. 99 00:05:04,000 --> 00:05:09,000 Отново, няма грешки или предупреждения в съставянето. 100 00:05:09,000 --> 00:05:12,000 Добре, Valgrind казва, че има две грешки в тази програма - 101 00:05:12,000 --> 00:05:15,000 и invalid_write и invalid_read. 102 00:05:15,000 --> 00:05:18,000 Да проверим този код. 103 00:05:18,000 --> 00:05:21,000 Изглежда, че имаме копие на класическия strlen плюс един бъг. 104 00:05:21,000 --> 00:05:24,000 Кодексът не изчистване допълнително байт на пространството 105 00:05:24,000 --> 00:05:26,000 за характер / 0 106 00:05:26,000 --> 00:05:30,000 така че, когато ул. копие отидох да го пишете на ssubstrlen "cs50 скали!" 107 00:05:30,000 --> 00:05:33,000 го е написал 1 байт след края на нашия блок. 108 00:05:33,000 --> 00:05:36,000 На invalid_read идва, когато ние правим нашия призив да ФОРМАТ. 109 00:05:36,000 --> 00:05:40,000 ФОРМАТ завършва четене невалидна памет, когато се чете / 0 характер 110 00:05:40,000 --> 00:05:43,000 , колкото изглежда в края на тази струна печат. 111 00:05:43,000 --> 00:05:45,000 Но нищо от това не е избягал Valgrind. 112 00:05:45,000 --> 00:05:48,000 Ние виждаме, че я хвана invalid_write като част от ул. копие 113 00:05:48,000 --> 00:05:51,000 по линия 11 на основния и invalid_read е част от ФОРМАТ. 114 00:05:51,000 --> 00:05:54,000 Rock, Valgrind. 115 00:05:54,000 --> 00:05:57,000 Отново, това може да не изглежда като една голяма сделка. 116 00:05:57,000 --> 00:06:00,000 Да стартирате тази програма отново и отново извън Valgrind 117 00:06:00,000 --> 00:06:03,000 и не виждам грешки симптоми. 118 00:06:03,000 --> 00:06:06,000 >> Все пак, нека погледнем в лек вариант на това, за да се види 119 00:06:06,000 --> 00:06:09,000 как нещата могат да се получат наистина лошо. 120 00:06:09,000 --> 00:06:14,000 Така че, даденост, ние се злоупотребява неща повече, отколкото само за малко в този кодекс. 121 00:06:14,000 --> 00:06:17,000 Ние сме само разпределението на място на куп за две струни 122 00:06:17,000 --> 00:06:19,000 дължината на cs50 скали, 123 00:06:19,000 --> 00:06:22,000 този път, спомняйки си / 0 характер. 124 00:06:22,000 --> 00:06:25,000 Но тогава ние се хвърлят в супер-дълъг низ в паметта блок 125 00:06:25,000 --> 00:06:27,000 че S е насочена. 126 00:06:27,000 --> 00:06:30,000 Какъв ефект ще има това върху паметта блок, че T точки? 127 00:06:30,000 --> 00:06:34,000 Е, ако T точки за памет, която е в непосредствена близост до S, 128 00:06:34,000 --> 00:06:37,000 идващи след него, 129 00:06:37,000 --> 00:06:39,000 тогава бихме могли да напише част на Т. 130 00:06:39,000 --> 00:06:41,000 Нека да изпълните този код. 131 00:06:41,000 --> 00:06:43,000 Виж какво се е случило. 132 00:06:43,000 --> 00:06:47,000 Низове, съхранявани в нашите натрупаш блокове двете да са отпечатани правилно. 133 00:06:47,000 --> 00:06:49,000 Нищо не изглежда наред на всички. 134 00:06:49,000 --> 00:06:52,000 Все пак, нека се върнем в нашия код и 135 00:06:52,000 --> 00:06:55,000 коментар на линията, където копирате cs50 скали 136 00:06:55,000 --> 00:06:59,000 във втория блок от паметта, посочи от тон. 137 00:06:59,000 --> 00:07:02,000 Сега, когато стартирате този код трябва да 138 00:07:02,000 --> 00:07:06,000 само съдържанието на първия блок на паметта разпечатате. 139 00:07:06,000 --> 00:07:09,000 Уау, въпреки че не сме ул. копие 140 00:07:09,000 --> 00:07:12,000 герой във втората купчина блок, посочи от T, 141 00:07:12,000 --> 00:07:15,000 за печат. 142 00:07:15,000 --> 00:07:18,000 Всъщност, низ пъхна в първата нашия блок 143 00:07:18,000 --> 00:07:21,000 опустошава първи блок и във втория блок, 144 00:07:21,000 --> 00:07:23,000 всичко изглежда нормално. 145 00:07:23,000 --> 00:07:26,000 Valgrind, обаче, ни разказва истинската история. 146 00:07:26,000 --> 00:07:28,000 Точно така. 147 00:07:28,000 --> 00:07:32,000 Всички тези невалиден чете и пише. 148 00:07:32,000 --> 00:07:36,000 >> Нека разгледаме един пример от друг вид грешка. 149 00:07:36,000 --> 00:07:39,000 Тук правим нещо доста жалко. 150 00:07:39,000 --> 00:07:41,000 Ние вземете пространство за вътр на куп, 151 00:07:41,000 --> 00:07:45,000 и ние се инициализира INT показалеца - стр. - да се отбележи, че пространството. 152 00:07:45,000 --> 00:07:48,000 Въпреки това, докато ни показалеца се инициализира, 153 00:07:48,000 --> 00:07:52,000 данните, сочещи към каквото и боклуци е в тази част на куп. 154 00:07:52,000 --> 00:07:55,000 Така че, когато се зареди, че данните в Int аз, 155 00:07:55,000 --> 00:07:57,000 технически и инициализира, 156 00:07:57,000 --> 00:08:00,000 но го правим с боклуци данни. 157 00:08:00,000 --> 00:08:03,000 Поканата да се твърди, който е удобен макро отстраняване на грешки 158 00:08:03,000 --> 00:08:06,000 определени в подходящо име, се твърди, библиотека, 159 00:08:06,000 --> 00:08:09,000 ще приключи програмата, ако не успее своя тест състояние. 160 00:08:09,000 --> 00:08:11,000 Това е, ако не е 0. 161 00:08:11,000 --> 00:08:14,000 В зависимост от това, което е в купчината пространство, посочи от стр. 162 00:08:14,000 --> 00:08:18,000 тази програма може да работи понякога и не в други времена. 163 00:08:18,000 --> 00:08:20,000 Ако тя работи, ние просто късмет. 164 00:08:20,000 --> 00:08:24,000 Компилаторът няма да хване тази грешка, но Valgrind сигурен, че ще. 165 00:08:24,000 --> 00:08:28,000 Там виждаме грешка, произтичащи от използването на данните, че боклуци. 166 00:08:28,000 --> 00:08:32,000 >> Когато разпределят куп памет, но не го преразпредели или да го освободи, 167 00:08:32,000 --> 00:08:34,000 , което се нарича изтичане на информация. 168 00:08:34,000 --> 00:08:37,000 За една малка, краткотрайна програма, която работи и веднага изходи, 169 00:08:37,000 --> 00:08:39,000 течове са сравнително безобидни, 170 00:08:39,000 --> 00:08:42,000 но за проект на по-голям размер и / или дълголетие, 171 00:08:42,000 --> 00:08:46,000 дори малък теч може да утежни в нещо голямо. 172 00:08:46,000 --> 00:08:49,000 За CS50, ние очакваме да 173 00:08:49,000 --> 00:08:51,000 да се грижи за освобождаването на всички на куп памет, която разпределя, 174 00:08:51,000 --> 00:08:54,000 тъй като ние искаме да изградят умения правилно да се справят с ръчен процес 175 00:08:54,000 --> 00:08:56,000 изисква от C. 176 00:08:56,000 --> 00:08:59,000 За да направите това, вашата програма трябва да има точно 177 00:08:59,000 --> 00:09:03,000 едно-към-едно кореспонденция между изчистване и безплатни разговори. 178 00:09:03,000 --> 00:09:06,000 За щастие, Valgrind може да ви помогне с изтичане на памет. 179 00:09:06,000 --> 00:09:09,000 Тук е спукан програма, наречена leak.c, че заделя 180 00:09:09,000 --> 00:09:13,000 пространство на куп, пише за него, но не го освободи. 181 00:09:13,000 --> 00:09:16,000 Ние го компилирате с грим и да го стартирате под Valgrind, 182 00:09:16,000 --> 00:09:18,000 и виждаме, че, докато ние нямаме грешки в паметта, 183 00:09:18,000 --> 00:09:20,000 ние имаме един теч. 184 00:09:20,000 --> 00:09:23,000 Има 16 байта определено изгубени, 185 00:09:23,000 --> 00:09:27,000 което означава, че показалецът, че паметта не е в обхвата, когато излезе програмата. 186 00:09:27,000 --> 00:09:30,000 Сега, Valgrind не ни даде тон на информация за теча, 187 00:09:30,000 --> 00:09:35,000 но ако следваме тази малка бележка, че тя дава надолу към дъното на доклада си 188 00:09:35,000 --> 00:09:38,000 да поднови с изтичане на проверка = пълно 189 00:09:38,000 --> 00:09:41,000 За да видите пълна информация за протекли памет, 190 00:09:41,000 --> 00:09:44,000 ще получите повече информация. 191 00:09:44,000 --> 00:09:46,000 Сега, в резюме на куп, 192 00:09:46,000 --> 00:09:50,000 Valgrind ни казва къде паметта, която е била загубена, разпределена първоначално. 193 00:09:50,000 --> 00:09:52,000 Точно както знаем в изходния код, 194 00:09:52,000 --> 00:09:55,000 Valgrind ни информира, че пропускам паметта 195 00:09:55,000 --> 00:09:58,000 разпределени с призив за изчистване на линия 8 на leak.c 196 00:09:58,000 --> 00:10:00,000 основната функция. 197 00:10:00,000 --> 00:10:02,000 Доста готин. 198 00:10:02,000 --> 00:10:04,000 >> Valgrind категоризира течове, използващи тези условия: 199 00:10:04,000 --> 00:10:07,000 Определено губи - това е куп заделената памет 200 00:10:07,000 --> 00:10:10,000 , до която програмата вече няма показалеца. 201 00:10:10,000 --> 00:10:14,000 Valgrind знае, че някога е имал показалеца, но тъй като са изгубили следите от него. 202 00:10:14,000 --> 00:10:17,000 Тази памет определено е изтекла информация. 203 00:10:17,000 --> 00:10:20,000 Индиректно губи - това е куп заделената памет 204 00:10:20,000 --> 00:10:24,000 които само указатели към него също така се губят. 205 00:10:24,000 --> 00:10:27,000 Например, ако сте загубили показалеца на първия възел на свързан списък, 206 00:10:27,000 --> 00:10:30,000 след първата възел определено ще бъде загубен, 207 00:10:30,000 --> 00:10:34,000 докато всички последващи възли ще бъдат косвено загубени. 208 00:10:34,000 --> 00:10:37,000 Възможно е загубил - това е куп заделената памет 209 00:10:37,000 --> 00:10:41,000 , в която Valgrind не може да бъде сигурен дали има указател или не. 210 00:10:41,000 --> 00:10:44,000 Все пак достъпен е купчина заделената памет 211 00:10:44,000 --> 00:10:47,000 , до която програмата все още има указател на изход, 212 00:10:47,000 --> 00:10:50,000 което обикновено означава, че глобална променлива точки към него. 213 00:10:50,000 --> 00:10:53,000 За да проверите за тези течове, вие също така ще трябва да включите опцията 214 00:10:53,000 --> 00:10:55,000 - Все още достижим = да 215 00:10:55,000 --> 00:10:58,000 в позоваването на Valgrind. 216 00:10:58,000 --> 00:11:01,000 >> Тези различни случаи могат да изискват различни стратегии за почистването им, 217 00:11:01,000 --> 00:11:05,000 но течове трябва да бъдат премахнати. 218 00:11:05,000 --> 00:11:08,000 За съжаление, определяне на течове може да бъде трудно да се направи, 219 00:11:08,000 --> 00:11:11,000 тъй като неверни повиквания към свободен могат да взривят вашата програма. 220 00:11:11,000 --> 00:11:14,000 Например, ако погледнем в invalid_free.c 221 00:11:14,000 --> 00:11:18,000 виждаме пример за лоша памет deallocation. 222 00:11:18,000 --> 00:11:21,000 Каква трябва да бъде едно обаждане, за да се освободи целия блок 223 00:11:21,000 --> 00:11:24,000 на паметта, посочи от int_block, 224 00:11:24,000 --> 00:11:27,000 вместо това се превърна в опит да се освободи всеки INT-голяма част 225 00:11:27,000 --> 00:11:29,000 на паметта индивидуално. 226 00:11:29,000 --> 00:11:32,000 Това ще се провали катастрофално. 227 00:11:32,000 --> 00:11:34,000 Boom! Каква грешка. 228 00:11:34,000 --> 00:11:36,000 Това определено не е добре. 229 00:11:36,000 --> 00:11:39,000 Ако сте остана с този вид грешка, макар и не знаете къде да търсите, 230 00:11:39,000 --> 00:11:41,000 падне обратно на новия си най-добър приятел. 231 00:11:41,000 --> 00:11:44,000 Вие познахте - Valgrind. 232 00:11:44,000 --> 00:11:47,000 Valgrind, както винаги, знае точно какво става. 233 00:11:47,000 --> 00:11:50,000 Заделянето на памет и безплатен брой не съвпадат. 234 00:11:50,000 --> 00:11:52,000 Имаме един заделянето на памет и 4 освобождава. 235 00:11:52,000 --> 00:11:55,000 И Valgrind също така ни казва къде първото лошо безплатно обаждане 236 00:11:55,000 --> 00:11:58,000 идва от този, който предизвика скандал - 237 00:11:58,000 --> 00:12:00,000 линия 16. 238 00:12:00,000 --> 00:12:03,000 Както виждате, лошите разговори, за да освободите са наистина лоши, 239 00:12:03,000 --> 00:12:05,000 затова ви препоръчваме отдаване под наем на вашата програма теч 240 00:12:05,000 --> 00:12:08,000 докато работите върху функционалността правилно. 241 00:12:08,000 --> 00:12:12,000 Започнете да търсите за течове само след вашата програма работи правилно, 242 00:12:12,000 --> 00:12:14,000 без никакви други грешки. 243 00:12:14,000 --> 00:12:16,000 >> И това е всичко, което имам за това клипче. 244 00:12:16,000 --> 00:12:18,000 Сега, какво чакате? 245 00:12:18,000 --> 00:12:21,000 Тичам Valgrind на програмите си точно сега. 246 00:12:21,000 --> 00:12:25,000 Моето име е Нейт Hardison. Това е CS50. [CS50.TV]