[Powered by Google Translate] [Valgrind]
[Nate Hardison, Harvard University]
Ĉi tiu estas CS50, CS50.TV]
Iuj el la plej malfacilaj erarojn en C programoj
venas de la malbona administrado de memoro.
Ekzistas grandega nombro de manieroj ŝraŭbo aĵojn,
inkludante atribui la malĝusta kvanto de memoro,
forgesi pravalorizi variabloj,
skribi antaŭ aŭ post la fino de bufro,
kaj liverante konservi memoron plurfoje.
La simptomoj iras de intermitaj frakasas
al mistere anstataŭigi valoroj,
ofte en lokoj kaj tempoj malproksimaj de la originalo eraro.
Paŭsi la observis problemo reen al la suba radiko
povas defii,
sed feliĉe tie estas helpema programo nomata Valgrind
kiu povas fari multon por helpi.
>> Vi kuras programon sub Valgrind ebligi
vastaj kontrolanta de amaso memoro atribuoj kaj aliroj.
Kiam Valgrind detektas problemo, donas al vi tujan,
rekta informo kiu permesas vin
pli facile trovi kaj ripari la problemon.
Valgrind ankaŭ informojn sur malpli mortiga memoro temoj,
kiel memoro fugoj, atribuante amaso memoro,
kaj forgesante liberigi ĝin.
Kiel nia tradukilo, Clang, en nia debugger, GDB,
Valgrind estas libera programaro, kaj ĝi estas instalita en la aparaton.
Valgrind kuras sur via duuma ruleblan,
ne estas via. c aŭ. h fontkodon dosieroj,
do esti certa vi kompilis supren-ĝis-dato kopion de via programo
uzante Clang aŭ Faru.
Tiam, kurante vian programon sub Valgrind povas esti
tiel simpla kiel ĝuste prefixing la norma programo komando kun la vorto Valgrind,
kiu funkciigas Valgrind kaj kuras la programon ene de ĝi.
Kiam startanta, Valgrind faras iujn kompleksajn
jiggering por agordi la ruleblan por la memoro ĉekoj,
tial ĝi povas preni iom ellitiĝi kaj kurante.
La programo estos tiam ekzekuti kutime, estos multe pli malrapide,
kaj kiam finas, Valgrind presos resumo de lia memoro uzado.
Se ĉiu iras bone, ĝi aspektos tiel:
En ĉi tiu kazo,. / Clean_program
estas la vojo al la programo Mi volas kuri.
Kaj dum ĉi tiu ne preni ajnan argumentoj,
se ĝi faris Mi preferas simple Tack ilin al la fino de la komando kiel kutime.
Pura programo estas nur stulta iom programo mi kreis
ke allocates spaco por bloko de ints sur la havaĵon,
meti iujn valorojn ene de ili, kaj liveras la tuta bloko.
Tio estas kion vi pafi por, neniu eraroj kaj neniu filtras.
>> Alia grava metriko estas la tuteca nombro de bajtoj asignotaj.
Depende de la programo, se via atribuoj estas en la megabajtoj aŭ pli alta,
vi probable faras ion malbonan.
Ĉu vi nenecese stokante duobligas?
Ĉu vi uzas la havaĵo por stokado, kiam estus pli bone uzi la pilo?
Do, memoro eraroj povas esti vere malbone.
La pli malkaŝan karaj kaŭzi espectacular frakasas,
sed eĉ tiam ĝi povas ankoraŭ esti malmola marki
kion ekzakte kondukis al la akcidento.
Pli inside, programo kun memoro eraron
povas ankoraŭ kompili pure
kaj povas ankoraŭ ŝajnas funkcii korekte
ĉar vi sukcesis akiri bonŝanca plejparto de la tempo.
Post pluraj "sukcesa rezultoj,"
vi eble simple pensas, ke akcidento estas hazardo de la komputilo,
sed la komputilo estas neniam malĝusta.
>> Kurante Valgrind povas helpi vin spuri la kaŭzo de videbla memoro eraroj
tiel kiel trovi kasxigxas erarojn vi eĉ ne ankoraŭ scias pri.
Ĉiufoje Valgrind detektas problemo, ĝi presas informojn pri kio observas.
Ĉiu ero estas sufiĉe konciza -
la fonto linio de la ofendi instrukcio, kion la demando estas,
kaj iom informoj pri la memoro implikita -
sed ofte ĝi estas sufiĉa informo por direkti vian atenton al la gxusta loko.
Jen ekzemplo de Valgrind kurante en kalesxo programo
kiu faras nevalidan legado de amaso memoro.
Ni ne vidas erarojn aŭ avertojn en kompilaĵo.
Uh-oh, la eraro resumo diras ke estas du eraroj -
du nevalida legas de grandeco 4 - bajtoj, kiu estas.
Ambaŭ malbona legas okazis en la ĉefa funkcio de invalid_read.c,
la unua en linio 16 kaj la dua sur linio 19.
Ni rigardu la kodon.
Aspektas kiel la unua alvoko al printf provas legi unu int preter la fino de nia memoro bloko.
Se ni retrorigardas al Valgrind la eliro,
ni vidas ke Valgrind diris al ni precize tion.
La adreso ni provas legi startas 0 bitokoj
preter la fino de la bloko de grandeco 16 bitokoj -
kvar 32-bitaj ints ke ni destinis.
Tio estas, la adreso ni provis legi komenciĝas ĝuste en la fino de nia bloko,
kiel ni vidas en nia malbona printf alvokon.
Nun, nevalida legas eble ne ŝajnas tiel granda de traktadon,
sed se vi uzas tiu datumo por kontroli la fluon de via programo -
ekzemple, kiel parto de se aserto aŭ buklo -
tiam aĵoj povas silente iri malbone.
Rigardas kiel mi povas kuri la invalid_read programo
kaj nenio el la ordinara okazas.
Timigaj, huh?
>> Nun, ni rigardu iujn pli specoj de eraroj, ke vi povus renkonti en via kodo,
kaj ni vidos kiel Valgrind detektas ilin.
Ni nur vidis ekzemplon de invalid_read,
tial nun ni rigardu la invalid_write.
Denove, ne eraroj aŭ avertojn en kompilaĵo.
Konsentite, Valgrind diras ke estas du eraroj en ĉi tiu programo -
kaj invalid_write kaj invalid_read.
Ni rigardu tiun kodon.
Aspektas kiel ni havas petskribo de la klasika strlen plus unu cimon.
La kodo ne malloc ekstra bajto de spaco
por la / 0 karaktero,
do kiam str kopion iris skribi ĝin ĉe ssubstrlen "cs50 rokoj!"
skribis 1 bajto preter la fino de nia bloko.
La invalid_read venas kiam ni faras nia alvoko al printf.
Printf finas legadon nevalida memoro kiam legas la / 0 karaktero
kiel ĝi aspektas ĉe la fino de ĉi tiu TTT kordoj estas stampita.
Sed neniu el ĉi eskapis Valgrind.
Ni vidas, ke ĝi kaptis la invalid_write kiel parto de la str kopio
on line 11 de ĉefa, kaj la invalid_read estas parto de printf.
Rock plu, Valgrind.
Denove, eble tio ne ŝajnas kiel granda interkonsento.
Ni povas kuri ĉi programo oni kaj ekster Valgrind
kaj ne vidis neniun eraron simptomojn.
>> Tamen, ni rigardu malpeza variado de ĉi por vidi
kiel la aferoj povas akiri vere malbona.
Do, donita, ni trouzi tion pli ol nur iomete en ĉi tiu kodo.
Ni nur atribui spaco sur la havaĵon por du kordoj
la longo de cs50 rokoj,
ĉi tiun fojon, memorante la / 0 karaktero.
Sed tiam ni ĵetu en la super-longa ŝnuro en la memoro bloko
ke S estas indikante.
Kio efekto kiun havas la memoro bloko kiu T punktoj al?
Nu, se T punktoj al la memoro tio estas nur najbara al S,
venas nur post tio,
tiam ni povus havi skribita sur parto de T.
Ni kuras ĉi tiu kodo.
Rigardu kio okazis.
La kordoj ni gardas en nia amaso blokas ambaŭ ŝajnis esti presita ekster ĝuste.
Nenio ŝajnas malĝusta ajn.
Tamen, ni reiru al nia kodo kaj
diri el la linio kie ni kopii cs50 rokoj
en la dua memoro bloko, montradis per t.
Nun, kiam ni kuras ĉi tiu kodo, ke ni devus
nur vidi la enhavon de la unua memoro bloko presi.
Halt, eĉ se ni ne str kopio
neniu signoj al la dua amaso bloko, la montradis per T,
ni preni print out.
Efektive, la kordoj ni plenigita en nia unua bloko
invadis la unua bloko kaj en la dua bloko,
farante cxion ŝajnas normala.
Valgrind, kvankam, diras al ni la veran historion.
Tie ni iru.
Ĉiuj el tiuj nevalida legas kaj skribas.
>> Ni rigardu ekzemplon de alia speco de eraro.
Ĉi tie ni faru ion pli malfeliĉa.
Ni kaptu spaco por int sur la havaĵon,
kaj ni pravalorizi an int puntero - p - atentigi al tiu spaco.
Tamen, dum nia puntero estas inicializada,
la datumoj kiujn ĝi estas indikante nur havas ajn rubo estas en tiu parto de la amaso.
Do kiam ni montru ke la datumoj en int i,
ni teknike pravalorizi i,
sed ni faras tion kun rubo datumoj.
La alvoko por aserti, kiu estas utila depuración macro
difinita en la _aptly_ nomis aserti biblioteko,
volo aborti la programo se ĝia provo kondiĉo maltrafas.
Tio estas, se i estas ne 0.
Depende kio estis en la havaĵo spaco, montradis per p,
tiu programo povus labori kelkfoje kaj fail je aliaj tempoj.
Se ĝi funkcias, ni nur nun bonŝanca.
La tradukilo ne kaptas tiun eraron, sed Valgrind certa volo.
Tie ni vidas la eraron devenaj el nia uzo de tiu rubaĵo datumoj.
>> Kiam vi destini amaso memoro sed ne deallocate ĝin aŭ liberigi ŝin,
kiu estas nomata fugo.
Por malgranda, mallonga programo kiu kuras kaj tuj eliroj,
fugoj estas sufiĉe simplaj,
sed por projekto de granda grandeco kaj / aŭ longevidad,
eĉ malgranda fugo povas komponaĵo en ion grandan.
Por CS50, ni atendas vin
prizorgi liberigante ĉiujn amaso memoro kiun vi destini,
ĉar ni volas ke vi konstruu la kapablecojn por taŭge trakti la manlibro procezo
postulas de C.
Por tion fari, via programo devus havi ĝusta
unu-al-unu rilato inter malloc kaj libera alvokoj.
Feliĉe, Valgrind povas helpi vin kun memoro filtras ankaŭ.
Jen leaky programo nomata leak.c ke allocates
spaco sur la havaĵon, skribas al ĝi, sed ne liberigi ĝin.
Ni kompili ĝin kun Faru kaj ruli ĝin sub Valgrind,
kaj ni vidas ke, dum ni ne havas memoron eraroj,
ni havas unu fugo.
Estas 16 bitokoj definitive perditaj,
signifante ke la montrilo al tiu memoro ne estis en amplekso kiam la programo eliris.
Nun, Valgrind ne donas al ni ton de informoj pri la fugo,
sed se ni sekvas tiun malgrandan noton kiu donas sube al la fundo de lia raporto
al rerun kun - fugon-check = plena
por vidi la plenan detaloj de filtrita memoro,
ni ricevos pli da informoj.
Nun, en la havaĵo resumon,
Valgrind diras al ni kie la memoro, la perditan estis komence asignotaj.
Kiel ni konas el rigardante en la fontkodo,
Valgrind informas nin, ke ni filtris la memoro
asignitaj kun alvoko al malloc sur linio 8 de leak.c
en la ĉefa funkcio.
Bela nifty.
>> Valgrind categoriza filtras uzante tiuj terminoj:
Definitive perdis - tiu ĉi estas amaso asignitaj memoro
al kiu la programo ne plu havas puntero.
Valgrind scias ke vi iam havis la puntero sed tiam miskalkulis ĝin.
Tiu memoro estas definitive filtris.
Nerekte perdis - tiu ĉi estas amaso asignitaj memoro
al kiu la sola punteros al tio ankaŭ estas perditaj.
Ekzemple, se vi perdis vian sagon al la unua nodo de ligitaj listo,
tiam la unua nodo mem estus definitive perditaj,
dum ajna posta nodoj estus malrekte perdita.
Eble perdita - tiu ĉi estas amaso asignitaj memoro
al kiu Valgrind ne povas esti certa ĉu estas puntero aŭ ne.
Ankoraŭ alirebla estas amaso asignitaj memoro
al kiu la programo ankoraŭ havas puntero ĉe eliro,
kiu tipe signifas ke tutmonda variablo punktoj al ĝi.
Por kontroli por tiuj fugoj, vi ankaŭ devas inkluzivi la eblon
- Ankoraŭ-alirebla = jes
en via alvoko de Valgrind.
>> Ĉi tiuj malsamaj kazoj povus postuli malsaman strategioj por purigi ilin,
sed filtras devus esti forigita.
Bedaŭrinde, riparante filtras povas esti malfacile fari,
ekde malĝusta alvokoj al libera povas blovi vian programon.
Ekzemple, se ni rigardas invalid_free.c,
ni vidas ekzemplon de malbona memoro deallocation.
Kio estu sola alvoko liberigi la tutan blokon
de memoro montradis per int_block,
tio anstataŭe fariĝis provo liberigi ĉiun int-sized sekcio
de la memoro individue.
Ĉi malsukcesos catastrophically.
Eksplodo! Kio eraron.
Tiu certe ne estas bona.
Se vi gluata kun ĉi tiu speco de eraro, kvankam, kaj vi ne scias kie serĉi,
replegarse en via nova pli bona amiko.
Vi divenis - Valgrind.
Valgrind, kiel ĉiam, scias ĝuste kio estas supre.
La alloc kaj libera grafoj ne kongruas supren.
Ni havas 1 alloc kaj 4 libera.
Kaj Valgrind ankaŭ diras al ni kie la unua malbona libera alvoko -
kiu deĉenigis la blowup - venas el -
linio 16.
Kiel vi vidas, malbona alvokoj liberigi estas vere malbona,
do ni rekomendas lasi vian programon fugo
dum vi laboras pri atingi la funcionalidad ĝentila.
Start serĉas filtras nur post via programo funkcias adekvate,
sen ajna alia eraroj.
>> Kaj tio estas ĉio ni havas por tiu video.
Nun kion vi atendas?
Iru kuri Valgrind en via programoj nun.
Mia nomo estas Nate Hardison. Ĉi tiu estas CS50. [CS50.TV]