[Powered by Google Translate] [Valgrind]
[Nate Хардисон, Гарвардскі універсітэт]
Гэта CS50, CS50.TV]
Некаторыя з найбольш цяжкіх памылак у праграмах C
прыходзяць ад няправільнага кіравання памяццю.
Ёсць вялікая колькасць спосабаў, каб ўкруціць рэчы,
у тым ліку вылучаючы няправільны аб'ём памяці,
забываючы пры ініцыялізацыі зменных,
пісьмовай форме да або пасля заканчэння буфера,
і вызваленне захаваць памяць некалькі разоў.
Сімптомы вар'іруюцца ад збоі
таямніча перазапісаны значэннямі,
Часта на месцах і часах далёкіх ад першапачатковай памылкі.
Адсочванне назіранага праблемы зваротна ў асноўны першапрычыны
можа быць складанай задачай,
але, на шчасце, ёсць карысны праграму пад назвай Valgrind
што можа зрабіць многае, каб дапамагчы.
>> Вы запускаеце праграму пад Valgrind каб
шырокія праверкі дынамічнай памяці асігнаванняў і доступаў.
Калі Valgrind выяўляе праблему, ён дае вам неадкладны,
прамой інфармацыі, якая дазваляе
лягчэй знайсці і выправіць памылку.
Valgrind таксама паведамленні пра менш небяспечныя праблем з памяццю,
такіх як ўцечкі памяці, вылучэнне дынамічнай памяці,
і забыць, каб вызваліць яго.
Падабаецца наш кампілятар, Clang, на наш адладчык, GDB,
Valgrind з'яўляецца свабодным праграмным забеспячэннем, і яна ўсталяваная на прыбор.
Valgrind працуе на вашым выкананы файл,
не ваш. або з. ч. файлаў зыходнага кода,
так што вы сабралі апошнюю дату копіі вашай праграмы
выкарыстаннем Clang або зрабіць.
Затым запусціць праграму пад Valgrind можа быць
так просты, як толькі прэфікс стандартнай каманды праграмы са словам Valgrind,
які запускае Valgrind і запускае праграму ўнутры яго.
Пры запуску Valgrind робіць некаторыя складаныя
перетасовывает наладзіць выкананы файл для праверкі памяці,
так што гэта можа заняць крыху, каб устаць і бегчы.
Праграма будзе выконваць нармальна, няхай гэта будзе значна павольней,
і калі ён скончыцца, Valgrind будзе друкаваць справаздачу аб сваёй памяці.
Калі ўсё пойдзе добра, то яна будзе выглядаць прыкладна так:
У гэтым выпадку,. / Clean_program
гэта шлях да праграмы, я хачу бегчы.
І хоць гэта не прымаць ніякіх аргументаў,
калі гэта так я б проста трэка іх у канцы каманды, як звычайна.
Чысты праграма проста дурная маленькая праграма, якую я стварыў
што вылучае месца для блока цэлымі ў кучы,
паставіць некаторыя значэння ў іх, і вызваляе ўвесь блок.
Гэта тое, што вы здымаеце для, без памылак і без уцечак.
>> Іншым важным паказчыкам з'яўляецца агульная колькасць байт вылучаецца.
У залежнасці ад праграмы, калі асігнаванні ў мегабайтах або вышэй,
Вы, верагодна, робіце нешта няправільна.
Вы залішне захоўвання дублікатаў?
Выкарыстоўваеце Ці вы кучу для захоўвання, калі гэта было б лепш выкарыстоўваць стэк?
Такім чынам, памылкі памяці можа быць па-сапраўднаму зло.
Больш за адкрытыя з іх выклікаюць захапляльныя аварыі,
але нават тады яна можа быць цяжка вызначыць
што менавіта прывяло да аварыі.
Больш за падступна, праграма з памяццю памылкі
усё яшчэ можа скампілявана
і ўсё яшчэ можа здавацца правільнай працы
таму што ў вас атрымалася злавіць поспех вялікую частку часу.
Пасля некалькіх "паспяховых вынікаў"
Вы маглі б проста думаю, што крах шчаслівай выпадковасці на кампутары,
але кампутар ніколі не памыляецца.
>> Запуск Valgrind можа дапамагчы вам адсачыць прычыну бачных памылак памяці
а таксама знайсці хаваюцца памылак, якія вы нават не ведалі яшчэ кс.
Кожны раз, калі Valgrind выяўляе праблему, ён выводзіць інфармацыю аб тым, што ён назіраў.
Кожны элемент з'яўляецца даволі кароткім -
Крыніца лінія парушальніка інструкцый, у чым справа,
і трохі інфармацыі аб памяці ўдзельнічаюць -
але часта гэта дастаткова інфармацыі, каб звярнуць вашу ўвагу на правільнае месца.
Вось прыклад з Valgrind працуе на багі праграмы
, Што робіць несапраўдным чытання дынамічнай памяці.
Мы не бачым ніякіх памылак або папярэджанняў ў кампіляцыю.
Ой-ой, памылка Агульны кажа, што ёсць дзве памылкі -
2 несапраўдным чытанняў памерам 4 - байт, то ёсць.
Абодва дрэнна чытае адбылася ў асноўнай функцыяй invalid_read.c,
першым на лініі 16, а другі на лініі 19.
Давайце паглядзім на код.
Падобна на тое, што першы выклік Printf спрабуе прачытаць адну Int мінулым канца нашага блока памяці.
Калі мы азірнемся на выхадзе Valgrind, у
мы бачым, што Valgrind сказаў нам менавіта гэта.
Адрас мы спрабуем чытаць пачынае 0 байт
у канцы мінулага блок памерам 16 байта -
4 32-разрадных цэлых лікаў, што мы далі.
Гэта значыць, адрасы мы спрабавалі прачытаць пачынаецца ў самым канцы нашага блока,
гэтак жа, як мы бачым у нашых дрэнных Printf выкліку.
Цяпер, несапраўднымі чытанняў не здаецца, што буйныя здзелкі,
Але калі вы выкарыстоўваеце гэтыя дадзеныя для кіравання патокам ваша праграма -
Напрыклад, як частка, калі заява або пятля -
Затым рэчы могуць моўчкі ідуць дрэнна.
Глядзіце, як я магу запусціць праграму invalid_read
і нічога незвычайнага не адбываецца.
Страшна, так?
>> Цяпер, давайце паглядзім на некалькі відаў памылак, якія могуць паўстаць у кодзе,
і мы ўбачым, як Valgrind выяўляе іх.
Мы толькі што бачылі прыклад invalid_read,
так што цяпер давайце паглядзім invalid_write.
Зноў жа, ніякіх памылак або папярэджанняў ў кампіляцыю.
Добра, Valgrind кажа, што ёсць дзве памылкі ў гэтай праграме -
і invalid_write і invalid_read.
Давайце праверым гэты код.
Падобна на тое, што ў нас ёсць асобнік класічнага StrLen плюс адна памылка.
Кодэкс не таНос дадатковы байт прасторы
для / 0 характару,
таму, калі копія вул пайшла пісаць на ssubstrlen "CS50 камяні!"
ён напісаў 1 байт ў канцы мінулага нашага блока.
Invalid_read прыходзіць тады, калі мы звяртаемся да Printf.
Printf сканчаецца чытаннем несапраўдным памяці пры чытанні / 0 сімвалаў
як гэта выглядае ў канцы гэтай струны гэта друк.
Але ўсё гэта не пазбег Valgrind.
Мы бачым, што ён злоўлены invalid_write як частка вул копію
у радку 11 асноўных і invalid_read з'яўляецца часткай Printf.
Rock On, Valgrind.
Зноў жа, гэта можа здацца не мае вялікага значэння.
Мы можам запусціць гэтую праграму зноў і зноў па-за Valgrind
і не бачу ніякай памылкі сімптомаў.
>> Тым не менш, давайце паглядзім на невялікае змяненне гэтага, каб убачыць
як рэчы могуць стаць вельмі дрэнна.
Так што, праўда, мы злоўжыванне рэчаў больш, чым проста трохі ў гэтым кодзе.
Мы толькі выдзялення месца ў дынамічнай памяці для двух радкоў
Даўжыня CS50 парод,
на гэты раз, памятаючы / 0 характару.
Але тады мы кідаем ў супер-доўгая радок у блоку памяці
што S вызначае.
Які эфект будзе, што ёсць на блок памяці, што T паказвае на?
Ну, калі T паказвае на памяць, што проста побач з S,
наступныя толькі пасля гэтага,
Затым мы маглі б напісана над часткай T.
Давайце запусцім гэты код.
Паглядзіце, што адбылося.
Мы радкоў захоўваецца ў нашай кучы блокаў як уяўляецца, належным чынам не друкуецца.
Нішто, здаецца, у корані памылковая.
Тым не менш, давайце вернемся ў наш код і
закомментируйте радок, дзе мы капіяваны CS50 парод
ў другой блок памяці, на які паказвае тон.
Цяпер, калі мы запусцім гэты код, мы павінны
Толькі ўбачыць змесціва першага блока памяці раздрукаваць.
Ух ты, нават калі мы гэтага не зрабілі, вул копію
любыя сімвалы, у другім блоку куча, на якую паказвае T,
мы атрымліваем друк.
Сапраўды, радок, якую мы запраўленыя ў нашым першым блоку
захапілі першы блок, а ў другім блоку,
робіць усё здаецца нармальным.
Valgrind, аднак, кажа нам праўду.
Там мы ідзем.
Усе гэтыя несапраўдным чытае і піша.
>> Давайце паглядзім на прыклад іншага роду памылкі.
Тут мы робім нешта даволі няўдала.
Мы захапіць прастору для Int ў кучы,
і мы ініцыялізуем паказальнік Int - P - паказаць на гэта прастора.
Тым не менш, у той час як наш паказальнік ініцыялізуецца,
дадзеныя, якія ён паказвае толькі мае ўсе барахло знаходзіцца ў той частцы кучы.
Таму, калі мы загрузіць дадзеныя ў Int я,
Мы тэхнічна ініцыялізацыі я,
але мы робім гэта з непажаданых дадзеных.
Выклік сцвярджаюць, што гэта зручны макрас адладкі
вызначаны ў трапна назваў сцвярджаюць, бібліятэкі,
перапыніць праграму, калі яе тэст ўмова не выконваецца.
Гэта значыць, калі я не роўна 0.
У залежнасці ад таго, што было ў кучы прастору, на якое паказвае р,
гэтая праграма можа працаваць часам і не ў іншы час.
Калі гэта працуе, мы проста пашанцавала.
Кампілятар не будзе лавіць гэтую памылку, але ўпэўнены, Valgrind волі.
Там мы бачым памылкі, якія вынікаюць з нашага выкарыстання, што непажаданыя дадзеныя.
>> Пры выдзяленні дынамічнай памяці, але не вызваляе яго ці вызваліць яго,
што называецца ўцечка.
Для невялікі, нядоўгай праграма, якая запускаецца і тут жа выходзіць,
Уцечкі даволі бясшкодныя,
але для праектаў большага памеру і / або даўгавечнасць,
нават невялікія уцечкі могуць скласці ў нешта маёра.
Для CS50, мы чакаем, што вы
клапаціцца аб вызваляючы ўсе кучы памяці, якія вы вылучаеце,
так як мы хочам, каб вы развіваць навыкі правільна звяртацца з ручной працэс
патрабуецца C.
Каб зрабіць гэта, ваша праграма павінна мець дакладную
адно-адназначнае адпаведнасць паміж таНос і бясплатныя званкі.
На шчасце, Valgrind можа дапамагчы вам з уцечкамі памяці таксама.
Вось вынікаючай праграму пад назвай leak.c, што вылучае
прасторы ў кучы, піша ён, але не вызваліць яго.
Мы скампіляваць яго з Марка і запусціць яго пад Valgrind,
і мы бачым, што, хоць у нас няма ніякіх памылак памяці,
у нас ёсць адна ўцечка.
Ёсць 16 байт вызначана страціў,
Гэта азначае, што паказальнік на гэтую памяць не была ў рамкі, калі праграма завершыцца.
Цяпер, Valgrind не дае нам масу інфармацыі аб уцечцы,
Але калі мы будзем прытрымлівацца гэтай невялікай запісцы, што ён дае ўніз, да ніжняй часткі яго дакладу
перазапусціць з - уцечка праверыць = поўны
, Каб убачыць поўную інфармацыю аб ўцечка памяці,
мы атрымаем больш інфармацыі.
Зараз, у кучу рэзюмэ,
Valgrind кажа нам, дзе памяць, што было страчана было першапачаткова выдзелена.
Гэтак жа, як мы ведаем, ад пошуку ў зыходным кодзе,
Valgrind паведамляе нам, што мы ўцечка памяці
вылучаецца з заклікам таНос на лініі 8 з leak.c
У асноўныя функцыі.
Даволі выдатны.
>> Valgrind класіфікуе уцечак з дапамогай гэтых тэрмінаў:
Вызначана страцілі - гэта дынамічнай памяці
у якім праграма не мае паказальніка.
Valgrind ведае, што ты калісьці быў паказальнік, але з тых часоў страціў яго.
Гэтая памяць вызначана ўцечка.
Ускосна страцілі - гэта дынамічнай памяці
да якой толькі паказальнікі да яго таксама будуць страчаныя.
Напрыклад, калі вы страцілі ваш паказальнік на першы вузел звязанага спісу,
Затым першае вузел сам бы вызначана страціў,
у той час як ва ўсіх вузлах будзе ўскосна страціў.
Магчыма, страціў - гэта дынамічнай памяці
да якой Valgrind не можа быць упэўнены, ці ёсць паказальнік ці не.
Тым не менш дасягальным з'яўляецца дынамічнай памяці
да якога праграма па-ранейшаму мае паказальнік на выхадзе,
Звычайна гэта азначае, што глабальная пераменная паказвае на гэта.
Каб праверыць гэтыя ўцечкі, вы таксама павінны ўключыць опцыю
- Усё яшчэ дасягальная = ды
У вашым выкліку Valgrind.
>> Гэтыя розныя выпадкі могуць спатрэбіцца розныя стратэгіі для ачысткі іх,
але ўцечкі павінны быць ліквідаваны.
На жаль, фіксуючы уцечкі можа быць цяжка зрабіць,
З няправільныя выклікі бясплатна можна падарваць вашу праграму.
Напрыклад, калі мы паглядзім на invalid_free.c,
мы бачым прыклад дрэннага вызвалення памяці.
Якім павінна быць ні аднаго званка, каб вызваліць ўвесь блок
памяці, на якую паказвае int_block,
замест гэтага стала спроба вызваліць кожны Int памеру падзелу
ў памяці асобна.
Гэта катастрафічна не атрымаецца.
Boom! Якія памылкі.
Гэта, безумоўна, не ёсць добра.
Калі вы затрымаліся з такой памылкай, хоць, і вы не ведаеце, дзе шукаць,
падаць назад на ваш новы лепшы сябар.
Вы ўжо здагадаліся - Valgrind.
Valgrind, як заўсёды, дакладна ведае, у чым справа.
Ідэнтыфікатар і бясплатна разлічвае не супадаюць.
Мы атрымалі 1 ідэнтыфікатар і 4 вызваляе.
І Valgrind таксама кажа нам, дзе першы званок бясплатны дрэнна -
той, які выклікаў разбурэння - ідзе ад -
радок 16.
Як бачыце, дрэнна званкоў, каб вызваліць сапраўды дрэнныя,
таму мы рэкамендуем дазваляючы вашай праграме ўцечкі
у той час як вы працуеце на атрыманне функцыянальных правільна.
Пачніце шукаць уцечку толькі пасля таго, як ваша праграма працуе правільна,
без якіх-небудзь іншых памылак.
>> І гэта ўсё, што ў нас ёсць для гэтага відэа.
Цяпер, што ж вы чакаеце?
Перайсці запусціць Valgrind вашых праграм прама цяпер.
Мяне клічуць Нейт Хардисон. Гэта CS50. [CS50.TV]