[Powered by Google Translate] [Valgrind]
[Nate Hardison, Harvard University]
Este é CS50, CS50.TV]
Algúns dos erros máis difíciles de programas en C
veñen da mala xestión da memoria.
Hai un número enorme de formas de romper as cousas,
incluíndo reservar a cantidade errónea de memoria,
esquecéndose de arrincar variables,
escrito antes ou despois do final dun tapón,
e liberando manter memoria varias veces.
Os síntomas varían de erros intermitentes
para valores misteriosamente substituído,
moitas veces en lugares e horarios moi distantes do erro orixinal.
Detectar o problema observado de volta para a causa subxacente
pode ser un desafío,
pero, por sorte, existe un programa útil chamado Valgrind
que poden facer moita cousa para axudar.
>> Vostede executar un programa no Valgrind para permitir
verificación extensa de alocações de heap de memoria e accesos.
Cando Valgrind detectar un problema, dálle inmediato,
información directa que lle permite
máis facilmente atopar e resolver o problema.
Valgrind tamén informes sobre problemas de memoria menos mortais,
como vazamentos de memoria, distribución de memoria heap,
e esquecer de liberar-la.
Como o noso compilador Clang, no noso depurador, GDB,
Valgrind é software libre, e é instalado no aparello.
Valgrind é executado no seu executable,
non o seu c. ou h. ficheiros de código fonte,
por que non deixe de ter compilado unha copia actualizada do seu programa
usando Clang ou facer.
A continuación, executando o seu programa baixo Valgrind pode ser
tan sinxelo coma prefixar o mando do programa co estándar Valgrind palabra,
que inicia Valgrind e executa o programa dentro del.
Ao iniciarse, Valgrind fai algún complexo
jiggering para configurar o executable para as comprobacións de memoria,
por iso pode levar un pouco para se erguer e executar.
O programa ha entón executar normalmente, é moi máis lentamente,
e cando remata, Valgrind ha imprimir un resumo do seu uso de memoria.
Se todo funcionar ben, será coma este:
Neste caso,. / Clean_program
é o camiño para o programa que quero correr.
E mentres este non tomar calquera argumentos,
se iso acontecese eu só Tack-los para o final do mando, como de costume.
Programa limpa é só un programa un pouco parvo eu creei
que aloca espazo para un bloque de enteiros na pila,
poñer algúns valores dentro deles, e libera o bloque enteiro.
Isto é o que está tirando para, sen erros e sen vazamentos.
>> Outra métrica importante é o número total de bytes asignados.
Dependendo do programa, as súas atribucións están nas megabytes ou máis,
probablemente está facendo algo mal.
Vostede está innecesariamente almacenar duplicados?
Está a usar a pila para almacenamento, cando sería mellor usar a pila?
Así, erros de memoria poden ser verdadeiramente mal.
Os máis evidentes causar accidentes espectaculares,
pero, aínda así, el tamén pode ser difícil identificar
exactamente o que levou ao accidente.
Máis insidiosamente, un programa con un erro de memoria
Aínda pode compilar limpa
e pode parecen funcionar correctamente
porque conseguiu ter sorte na maioría das veces.
Despois de varios "bos resultados",
pode só pensar que un accidente é un golpe de sorte do ordenador,
pero o ordenador non está mal.
>> Correndo Valgrind pode axudar a rastrexar a causa de erros de memoria visibles
así como atopar espreita erros que nin sabe aínda sobre.
Cada vez Valgrind detectar un problema, el imprime información acerca do que observaron.
Cada elemento é moi concisa -
a liña da fonte da instrución ofender, cal é o problema,
Información e un pouco sobre a memoria utilizada -
pero moitas veces é suficiente información para dirixir a súa atención para o lugar seguro.
Aquí é un exemplo de execución no Valgrind un programa de buggy
que fai unha lectura incorrecta de memoria heap.
Vemos ningún erro ou aviso na compilación.
Uh-oh, un resumo de erro di que hai dous erros -
dúas lecturas válido de tamaño 4 - bytes, que é.
Tanto malos le ocorreu na función principal de invalid_read.c,
o primeiro na liña 16 e o ​​segundo na liña 19.
Imos mirar para o código.
Parece que a primeira chamada printf intenta ler un int pasado fin do noso bloque de memoria.
Se miramos cara atrás na saída do Valgrind,
vemos que Valgrind nos dixo exactamente isto.
O enderezo que estamos tentando ler comeza 0 bytes
tras o fin do bloque de 16 bytes de tamaño -
catro de 32 bits ints que alocados.
Ou sexa, o enderezo que estabamos intentando ler comeza pronto a finais do noso bloque,
así como vemos no noso chamado mal printf.
Agora, non é válida Lecturas pode non parecer tan grande dun negocio,
pero se está a usar estes datos para controlar o fluxo do seu programa -
por exemplo, como parte dunha instrución if ou loop -
entón as cousas poden ir mal en silencio.
Vexa como eu pode executar o programa invalid_read
e nada fóra do común acontece.
Asustado, non?
>> Agora, imos ollar algúns tipos de erros que pode atopar no seu código,
e imos ver como Valgrind detecta.
Nós só vimos un exemplo dun invalid_read,
entón agora imos comprobar un invalid_write.
Unha vez máis, ningún erro ou aviso na compilación.
Ok, Valgrind di que hai dous erros neste programa -
e invalid_write e un invalid_read.
Imos comprobar este código.
Parece que temos unha instancia do strlen clásico un erro.
O código non malloc un byte extra de espazo
para o personaxe / 0,
por iso, cando str copia foi para gravala-lo en ssubstrlen "CS50 rocks!"
escribiu un byte despois do final do noso bloque.
O invalid_read vén cando nós facemos a nosa chamada printf.
Printf acaba de ler memoria válido, cando le o / 0 carácter
como mira cara ao final deste corda e é impresión.
Pero nada diso escapou Valgrind.
Vemos que chamou a invalid_write como parte da copia de str
na liña 11 do principal eo invalid_read é parte do printf.
Rock en, Valgrind.
De novo, isto pode non parecer un gran negocio.
Podemos executar este programa máis e máis fóra de Valgrind
e non ver ningún síntoma de erro.
>> Con todo, imos ollar a unha pequena variación desa ver
como as cousas poden ser moi malo.
Así, concedeu, estamos abusando de cousas máis que un pouco neste código.
Estamos só a distribución de espazo na pila para dúas cordas
a lonxitude de CS50 rochas,
esta vez, lembrando o / 0 personaxe.
Pero, entón, xogar nunha secuencia super-longa no bloque de memoria
S que está apuntando.
Cal será o efecto que ten sobre o bloque de memoria que apunta a T?
Ben, se os puntos de T a memoria que é só ao lado S,
está despois,
entón podería ter escrito sobre parte T.
Imos executar este código.
Olle para o que pasou.
As cordas que almacenan nos nosos bloques de heap ambos parecían impresos correctamente.
Nada parece mal en todo.
Con todo, imos voltar para o noso código e
Comentar a liña onde copiar CS50 rochas
no bloque de memoria en segundo lugar, apuntada por t.
Agora, cando executar este código que debe
só ver o contido do primeiro bloque de memoria imprimir.
Whoa, aínda que non fixo copias str
os caracteres no bloque heap segundo, aquel apuntado por T,
temos unha impresión.
De feito, a secuencia de nós recheo no noso primeiro bloque
invadiron o primeiro bloque e para dentro do segundo bloque,
facendo que todo pareza normal.
Valgrind, porén, di-nos a historia verdadeira.
Alí imos nós.
Todos aqueles válido le e escribe.
>> Vexamos un exemplo doutro tipo de erro.
Aquí facemos algo bastante infeliz.
Nós coller espazo para un int na pila,
e arrincar un punteiro int - p - para apuntar a este espazo.
Con todo, mentres o noso punteiro é inicializar,
os datos que está a apuntar cara o que acaba de lixo é en que parte do conxunto.
Entón, cando temos de cargar eses datos int i,
que tecnicamente arrincar i,
pero facelo con datos de lixo.
A chamada para afirmar que é unha macro de depuración útil
definido no apropiadamente chamado biblioteca afirmar,
ha abortar o programa a súa condición de proba falla.
É dicir, se eu non for 0.
Dependendo do que foi no espazo de pila, apuntado por p,
este programa pode funcionar algunhas veces e non noutros momentos.
Se funciona, nós estamos só comezando sorte.
O compilador non vai pegar ese erro, pero Valgrind vontade seguro.
Hai que ver o erro que proviña do noso uso destes datos chatarra.
>> Cando aloca memoria heap, pero non desalocar-lo ou libertá-lo,
que se denomina unha fuga.
Para un pequeno programa de curta duración que corre e sae inmediatamente,
vazamentos son bastante inofensivo,
pero para un proxecto de maior porte e / ou lonxevidade,
incluso un pequeno escape pode agravar en algo máis grande.
Para CS50, esperamos que
coidar de liberar toda a memoria heap que reservar,
dende que queremos que constrúe as habilidades para manexar adecuadamente o proceso manual
esixida pola C.
Para iso, o programa debe ter unha exacta
un-para-un entre malloc e chamadas gratuítas.
Afortunadamente, Valgrind pode axudar con vazamentos de memoria tamén.
Aquí está o programa oco chamado leak.c que aloca
espazo na pila, escribe para el, pero non libertá-lo.
Nós compilar con Facer e executa-lo en Valgrind,
e vemos que, mentres temos ningún erro de memoria,
temos un escape.
Hai 16 bytes definitivamente perdidos,
o que significa que o punteiro para que a memoria non estaba no ámbito cando o programa foi encerrado.
Agora, Valgrind non nos dá unha tonelada de información sobre o baleirado,
pero se seguimos esa pequena nota que dá cara ao fondo do seu informe
executar de novo con - Leak-check = total
Para ver os detalles completos de memoria baleirada,
imos obter máis información.
Agora, no resumo heap,
Valgrind dinos onde a memoria que se perdeu foi inicialmente asignado.
Así como sabemos mirar no código fonte,
Valgrind nos informa que filtrou a memoria
alocada cunha chamada a malloc en liña 8 da leak.c
na función principal.
Moi bacana.
>> Valgrind categoriza vazamentos usando estes termos:
Definitivamente perdido - isto é memoria alocada pila
para que o programa non ten un punteiro.
Valgrind sabe que xa tivo o punteiro, pero, dende entón, perdeu a noción do mesmo.
Esta memoria é sempre filtrou.
Indirectamente perdido - isto é memoria alocada pila
a que só os enlaces para iso tamén se perde.
Por exemplo, se perdeu o punteiro para o primeiro nodo da lista ligada,
a continuación, o primeiro en si sería definitivamente perdidas,
mentres todos os nós posteriores serían indirectamente perdido.
Posiblemente perdeu - esta é a memoria alocada pila
ao cal Valgrind non pode estar seguro se existe un punteiro ou non.
Aínda accesible é a memoria alocada pila
en que o programa ten aínda un punteiro na saída,
o que normalmente significa que unha variable global puntos para el.
Para comprobar estes vazamentos, tamén ten que incluir a opción
- Aínda alcançável = yes
na súa invocación de Valgrind.
>> Estes casos poden requirir diferentes estratexias diferentes para limpa-las para arriba,
pero derrames deben ser eliminados.
Desafortunadamente, fixar vazamentos pode ser difícil de facer,
xa que as chamadas incorrectas libre pode explotar o seu programa.
Por exemplo, se olharmos para invalid_free.c,
vemos un exemplo de desalocação de memoria malo.
O que debería ser unha soa chamada para liberar todo o bloque
de memoria apuntada por int_block,
en vez diso facer un intento de liberar cada sección int porte
da memoria individual.
Isto ha falla desastrosamente.
Boom! O que un erro.
Isto definitivamente non é bo.
Se está preso con ese tipo de erro, aínda que, e non sabe onde mirar,
caer cara atrás no seu novo mellor amigo.
Vostede difícil de adiviñar - Valgrind.
Valgrind, como sempre, sabe exactamente o que está a suceder.
As contas alloc e libre non combinan.
Temos un alloc e 4 libera.
E Valgrind tamén nos di que a chamada mala primeira libre -
o que desencadeou a Blowup - está a benvida -
liña 16.
Como podes ver, as chamadas para liberar malos son moi malos,
por iso recomendamos deixar o seu programa de escape
mentres se está a traballar para lograr a funcionalidade correcta.
Comezar a buscar vazamentos soamente despois o programa está funcionando correctamente,
sen outros erros.
>> E iso é todo o que temos para este vídeo.
Agora, o que estás esperando?
Ir executar Valgrind nos seus programas agora.
O meu nome é Nate Hardison. Este é CS50. [CS50.TV]