[Powered by Google Translate] [Valgrind]
[Nate Hardison, Harvard University]
Esto es CS50, CS50.TV]
Algunos de los errores más difíciles en los programas en C
provienen de la mala gestión de la memoria.
Hay un gran número de formas de enredar las cosas,
incluyendo la asignación de la cantidad incorrecta de la memoria,
olvidar inicializar variables,
escrito antes o después del final de un tampón,
y la liberación de mantener los tiempos de memoria múltiples.
Los síntomas van desde fallos intermitentes
a los valores misteriosamente sobrescritos,
a menudo en lugares y tiempos muy alejados del error original.
Rastreando el problema observado de nuevo a la causa subyacente
puede ser un reto,
pero, afortunadamente, hay un programa llamado útil Valgrind
que se puede hacer mucho para ayudar.
>> Ejecutar un programa bajo Valgrind para que
comprobación extensa de asignaciones de memoria heap y accesos.
Cuando Valgrind detecta un problema, se le da inmediata,
información directa que le permite
más fácilmente encontrar y solucionar el problema.
Valgrind también informes sobre problemas de memoria menos mortales,
tales como pérdidas de memoria, asignación de memoria heap,
y olvidarse de liberarlo.
Como nuestro compilador, Clang, en nuestro depurador GDB,
Valgrind es software libre, y se instala en el aparato.
Valgrind se ejecuta en el ejecutable binario,
no tu. co. archivos de origen h de código,
así que asegúrese de que usted haya compilado una copia actualizada al día de su programa
utilizando Clang o hacer.
A continuación, ejecuta el programa bajo Valgrind puede ser
tan simple como prefijo el símbolo del programa estándar con el Valgrind palabra,
que se inicia Valgrind y ejecuta el programa en el interior de la misma.
Al iniciar, Valgrind hace algún complejo
jiggering para configurar el ejecutable de la vigilancia a la memoria,
por lo que puede tardar un poco para ponerse en marcha.
Entonces, el programa se ejecutará normalmente, pueden ser mucho más lentamente,
y cuando termina, Valgrind imprimirá un resumen de su uso de memoria.
Si todo va bien, se verá algo como esto:
En este caso,. / Clean_program
es la ruta de acceso al programa que desea ejecutar.
Y mientras esto no se toma ningún argumento,
si lo hiciera yo acababa de ellos rumbo a la final de la orden como de costumbre.
Programa Clean es un programa poco tonto que he creado
que asigna espacio para un bloque de enteros en el montón,
poner algunos valores dentro de ellos, y libera toda la manzana.
Esto es lo que usted está tirando para, sin errores y sin fugas.
>> Otra métrica importante es el número total de bytes asignados.
Dependiendo del programa, si sus asignaciones están en megabytes o más,
usted está probablemente haciendo algo mal.
¿Estás innecesariamente almacenar duplicados?
¿Está utilizando la pila de almacenamiento, cuando sería mejor usar la pila?
Por lo tanto, los errores de memoria pueden ser verdaderamente mal.
Los más evidentes causar accidentes espectaculares,
pero aun así, todavía puede ser difícil de identificar
exactamente lo que condujo a la caída.
Peor aún, un programa con un error de memoria
todavía puede compilar limpiamente
y todavía puede parecen funcionar correctamente
porque se las arregló para tener suerte la mayor parte del tiempo.
Después de varios "resultados exitosos"
usted podría pensar que un accidente es un golpe de suerte de la computadora,
pero el equipo nunca se equivoca.
>> Ejecución de Valgrind puede ayudarle a localizar la causa de los errores de memoria visibles
así como encontrar al acecho errores que ni siquiera aún conocemos.
Cada vez Valgrind detecta un problema, se muestra información acerca de lo que observa.
Cada artículo es bastante escueto -
la línea de la fuente de la instrucción infractora, cuál es el problema,
y un poco de información acerca de la memoria involucrados -
pero a menudo es suficiente información para dirigir su atención hacia el lugar correcto.
Aquí está un ejemplo de Valgrind ejecuta en un programa defectuoso
que hace una lectura válida de la memoria heap.
No vemos los errores o advertencias de compilación.
Uh-oh, el resumen error dice que hay dos errores -
dos lecturas inválidas de tamaño 4 - bytes, es decir.
Tanto mala lee producido en la función principal de invalid_read.c,
el primero en la línea 16 y la segunda en la línea 19.
Veamos el código.
Parece que la primera llamada a printf intenta leer un int allá del final de nuestro bloque de memoria.
Si miramos hacia atrás en la salida de Valgrind,
vemos que Valgrind nos dijo exactamente eso.
La dirección que estamos tratando de leer empieza 0 bytes
más allá del extremo del bloque de tamaño 16 bytes -
cuatro enteros de 32-bit que nos asignan.
Es decir, la dirección que estábamos tratando de leer empieza justo al final de nuestro bloque,
tal como vemos en nuestra llamada printf malo.
Ahora, no es válido lecturas no parece ser tan grande de un acuerdo,
pero si usted está utilizando esos datos para controlar el flujo del programa -
por ejemplo, como parte de una sentencia if o loop -
entonces las cosas pueden ir mal en silencio.
Mira cómo puedo ejecutar el programa invalid_read
y nada fuera de lo común sucede.
Da miedo, ¿eh?
>> Ahora, echemos un vistazo a algunos tipos más de los errores que pueden surgir en el código,
y vamos a ver cómo Valgrind los detecta.
Acabamos de ver un ejemplo de un invalid_read,
por lo que ahora vamos a ver un invalid_write.
Una vez más, no hay errores o advertencias de compilación.
Bueno, Valgrind dice que hay dos errores en este programa -
y invalid_write y invalid_read un archivo.
Vamos a ver este código.
Parece que tenemos un ejemplo del clásico strlen además de un bug.
El código no malloc un byte extra de espacio
por el carácter / 0,
así que cuando str copia fue a escribir en ssubstrlen "CS50 rocks!"
lo escribió un byte más allá del final de nuestro bloque.
El invalid_read viene cuando hacemos nuestra llamada a printf.
Printf termina la lectura de memoria no válida cuando se lee la / 0 carácter
como se ve en el extremo de esta cadena E es impresión.
Pero nada de esto escapó Valgrind.
Vemos que llamó la invalid_write como parte de la copia de str
en la línea 11 de la principal, y la invalid_read es parte de printf.
Rock on, Valgrind.
De nuevo, esto no parece ser un gran problema.
Podemos ejecutar este programa una y otra vez fuera de Valgrind
y no ve ningún síntoma de error.
>> Sin embargo, vamos a ver una ligera variación de esto para ver
cómo las cosas pueden ponerse muy mal.
Así que, es cierto, estamos abusando de cosas más que sólo un poco en este código.
Sólo estamos asignando espacio en el montón de dos cadenas
la longitud de CS50 rocas,
esta vez, recordando la / 0 caracteres.
Pero luego tirar de una cadena de super-larga en el bloque de memoria
S que está apuntando.
¿Qué efecto tendrá esto en el bloque de memoria que apunta a T?
Bueno, si los puntos de T a la memoria que hay justo al lado de S,
viene justo después de ella,
entonces podríamos haber escrito sobre parte de T.
Vamos a ejecutar este código.
Mira lo que pasó.
Las cadenas se almacenan en nuestros bloques montón ambos parecían haber impreso correctamente.
Nada parece mal en absoluto.
Sin embargo, volvamos a nuestro código y
comentar la línea donde copiamos CS50 rocas
en el segundo bloque de memoria, a la que apunta t.
Ahora, cuando ejecute este código debemos
sólo ver el contenido del primer bloque de memoria imprimir.
Whoa, aunque nosotros no lo hicimos str copia
los caracteres en el bloque montón segundo, el apuntado por T,
obtenemos una impresión.
De hecho, la cadena se metió en nuestro primer bloque
invadieron el bloque primero y en el segundo bloque,
haciendo que todo parezca normal.
Valgrind, sin embargo, nos cuenta la historia real.
Ahí vamos.
Todos aquellos inválido lee y escribe.
>> Veamos un ejemplo de otro tipo de error.
Aquí hacemos algo bastante lamentable.
Cogemos el espacio para un entero en el heap,
y nos inicializar un puntero int - p - para apuntar a ese espacio.
Sin embargo, mientras que nuestro puntero se inicializa,
los datos que se está apuntando a sólo lo ha basura está en esa parte de la pila.
Así que cuando cargamos esos datos en int i,
que técnicamente i inicializar,
pero lo hacemos con datos de la chatarra.
La llamada a afirmar, que es una macro de depuración práctico
se define en el bien llamado afirmar biblioteca,
abortará el programa si su condición de prueba falla.
Es decir, si no es 0.
Dependiendo de lo que había en el espacio del montón, apuntado por p,
este programa puede trabajar a veces y no en otros momentos.
Si funciona, sólo estamos teniendo suerte.
El compilador no detectará este error, pero Valgrind voluntad segura.
Allí vemos que el error resultante de nuestro uso de esos datos no deseados.
>> Al asignar memoria del montón, pero no lo desasignar o liberarlo,
que se llama una fuga.
Para un pequeño, efímero programa que se ejecuta y sale inmediatamente,
fugas son bastante inofensivos,
pero para un proyecto de mayor tamaño y / o la longevidad,
incluso una pequeña fuga puede complicar en algo importante.
Para CS50, esperamos que
cuidar de liberar toda la memoria heap que asigne,
ya que queremos que usted construya los conocimientos necesarios para manejar adecuadamente el proceso manual
requerido por C.
Para ello, el programa debe tener un exacto
uno-a-uno correspondencia entre malloc y llamadas gratuitas.
Afortunadamente, Valgrind puede ayudar con las pérdidas de memoria también.
Aquí hay un programa llamado fugas leak.c que asigna
espacio en el montón, escribe en él, pero no lo liberará.
Nos compilarlo con make y ejecutar el programa bajo Valgrind,
y vemos que, si bien no tenemos errores de memoria,
tenemos una fuga.
Hay 16 bytes definitivamente perdidos,
lo que significa que el puntero a la memoria que no estaba en el ámbito cuando el programa se cierra.
Ahora, Valgrind no nos da un montón de información acerca de la fuga,
pero si seguimos esta pequeña nota que da hacia el fondo de su informe
volver a ejecutar con - Fuga-check = completo
para ver los detalles completos de memoria perdida,
vamos a obtener más información.
Ahora bien, en el resumen montón,
Valgrind nos dice que la memoria que se perdió fue asignado inicialmente.
Así como sabemos de mirar en el código fuente,
Valgrind nos informa que filtró la memoria
asignado con una llamada a malloc en la línea 8 de leak.c
en la función principal.
Bastante ingenioso.
>> Valgrind clasifica fugas usando estos términos:
Definitivamente perdido - esto es la pila de memoria asignada
en que el programa ya no tiene un puntero.
Valgrind sabe que una vez tuvo el puntero, pero desde entonces han perdido la pista.
Esta memoria es, sin duda filtrado.
Indirectamente perdido - esta es la pila de memoria asignada
a la que sólo los punteros a que también se pierden.
Por ejemplo, si usted perdió su puntero al primer nodo de una lista enlazada,
entonces el primer nodo en sí sería definitivamente perdido,
mientras que los nodos subsiguientes serían indirectamente perdido.
Posiblemente perdido - esta es la pila de memoria asignada
a la que Valgrind no puede estar seguro si hay un puntero o no.
Todavía es accesible la pila de memoria asignada
en que el programa todavía tiene un puntero en la salida,
que significa típicamente que apunta una variable global a la misma.
Para comprobar si estas filtraciones, usted también tendrá que incluir la opción
- Aún alcanzable = yes
en su advocación de Valgrind.
>> Estos casos pueden requerir diferentes estrategias diferentes para limpiarlas,
pero las fugas deben ser eliminados.
Por desgracia, la fijación de las fugas pueden ser difícil de hacer,
ya que las llamadas incorrectas a libre puede explotar su programa.
Por ejemplo, si nos fijamos en invalid_free.c,
vemos un ejemplo de desasignación mal recuerdo.
Lo que debería ser una sola llamada a liberar a todo el bloque
de memoria apuntada por int_block,
en cambio, ha convertido en un intento por liberar a cada sección del tamaño de int
de la memoria individualmente.
Esto fallará catastróficamente.
Boom! ¡Qué error.
Esto definitivamente no es bueno.
Si usted está atascado con este tipo de error, sin embargo, y usted no sabe dónde buscar,
recurrir a su nuevo mejor amigo.
Usted lo adivinó - Valgrind.
Valgrind, como siempre, sabe exactamente lo que pasa.
Los recuentos alloc y libre no coinciden.
Tenemos un alloc y 4 libra.
Y Valgrind también nos dice que la primera llamada gratuita malo -
la que desencadenó la explosión - se viene -
la línea 16.
Como puede ver, las llamadas malas para liberar son realmente malas,
lo que se recomienda dejar que su fuga programa
mientras que usted está trabajando en conseguir el correcto funcionamiento.
Comience a buscar fugas sólo después de que su programa está funcionando correctamente,
sin otros errores.
>> Y eso es todo lo que tenemos para este video.
Ahora, ¿qué estás esperando?
Ir ejecutar Valgrind en sus programas en estos momentos.
Mi nombre es Nate Hardison. Esto es CS50. [CS50.TV]