En Chrome 92, presentamos el Inspector de memoria, una herramienta para inspeccionar los búferes de memoria lineal. En este artículo, analizaremos cómo mejoramos el Inspector para la depuración de C/C++ y los desafíos técnicos que encontramos en el camino.
Estas son algunas entradas de blog relevantes si es la primera vez que depuras código C/C++ y usas el Inspector de memoria:
- ¿Te interesa la depuración de memoria profunda? Consulta Presentación del Inspector de memoria.
- ¿Quieres obtener una introducción al paquete completo de herramientas de depuración de C/C++? Consulta Cómo depurar WASM con herramientas modernas y Cómo depurar WebAssembly más rápido.
Introducción
El Inspector de memoria te proporciona opciones de depuración más potentes para los búferes de memoria lineal. En el caso de C/C++, puedes inspeccionar los objetos de memoria de C/C++ en la memoria de WebAssembly.
Reconocer los bytes de tu objeto entre la memoria de WebAssembly circundante era un problema. Debes conocer el tamaño del objeto y contar los bytes desde el principio. En la siguiente captura de pantalla, se selecciona el primer byte de un array int32
de 10 elementos, pero no está claro de inmediato qué otros bytes pertenecen al array. ¿No sería genial si pudieras reconocer al instante todos los bytes que pertenecen al objeto?
Destacado de objetos en el Inspector de memoria
A partir de Chrome 107, el Inspector de memoria destaca todos los bytes de un objeto de memoria C/C++. Esto te ayuda a diferenciarlos de la memoria circundante.
Mira el siguiente video para ver el Inspector de memoria en acción. A medida que revelas el array x
en el Inspector de memoria, la memoria destacada aparece en el visor de memoria junto con un chip nuevo justo encima de ella. Este chip te recuerda el nombre y el tipo de la memoria destacada. Haz clic en el chip para ir a la memoria del objeto. Si colocas el cursor sobre el chip, aparecerá un ícono de cruz. Haz clic en él para quitar el elemento destacado.
Cuando seleccionas un byte fuera del objeto que inspeccionas, el elemento destacado se desenfoca para evitar que te distraiga. Para volver a enfocarlo, haz clic en cualquiera de los bytes del objeto o en el chip.
La compatibilidad con el resaltado de objetos no se limita a los arrays. También puedes inspeccionar estructuras, objetos y punteros. Estos cambios facilitan más que nunca la exploración de la memoria de tus apps de C/C++.
¿Quieres probarlo? Deberás hacer lo siguiente:
- Tener Chrome 107 o versiones posteriores
- Instala la extensión DWARF de C/C++.
- Habilita la depuración DWARF en Herramientas para desarrolladores > Configuración > Experimentos > Depuración de WebAssemble: Habilita la compatibilidad con DWARF.
- Abre esta página de demostración.
- Sigue las instrucciones que aparecen en la página.
Ejemplo de depuración
En esta sección, analizaremos un error ficticio para ilustrar cómo puedes usar el Inspector de memoria para la depuración de C/C++. En la siguiente muestra de código, un programador crea un array de números enteros y decide usar la aritmética de punteros para seleccionar el último elemento. Lamentablemente, el programador cometió un error en el cálculo del puntero y, ahora, en lugar de imprimir el último elemento, el programa imprime valores sin sentido.
#include <iostream>
int main()
{
int numbers[] = {1, 2, 3, 4};
int *ptr = numbers;
int arraySize = sizeof(numbers)/sizeof(int);
int* lastNumber = ptr + arraySize; // Can you notice the bug here?
std::cout <<../ *lastNumber <<../ '\n';
return 0;
}
El programador recurre al Inspector de memoria para depurar el problema. Puedes seguir esta demo. Primero, inspecciona el array en el Inspector de memoria y ve que el array numbers
solo contiene los números enteros 1
, 2
, 3
y 4
, como se esperaba.
A continuación, revela la variable lastNumber
del panel Alcance y observa que el puntero apunta a un número entero fuera del array. Con este conocimiento, el programador se da cuenta de que contó mal el desplazamiento del puntero en la línea 8. Debería haber sido ptr + arraySize - 1
.
Aunque este es un ejemplo de juguete, ilustra cómo el resaltado de objetos transmite de manera eficaz el tamaño y la posición de los objetos de memoria, lo que puede ayudarte a comprender mejor lo que sucede dentro de la memoria de tu app de C/C++.
Cómo DevTools determina qué destacar
En esta sección, veremos el ecosistema de herramientas que habilita la depuración de C/C++. Específicamente, aprenderás cómo DevTools, V8, la extensión DWARF de C/C++ y Emscripten hacen posible la depuración de C/C++ en Chrome.
Para aprovechar todo el poder de la depuración de C/C++ en DevTools, necesitas dos elementos:
- La extensión DWARF de C/C++ instalada en Chrome
- Archivos fuente C/C++ compilados en WebAssembly con el compilador Emscripten más reciente, como se indica en esta entrada de blog
Pero ¿por qué? V8 , el motor JavaScript y WebAssembly de Chrome, no sabe cómo ejecutar C o C++. Gracias a Emscripten, un compilador de C/C++ a WebAssembly, puedes compilar apps compiladas en C o C++ como WebAssembly y ejecutarlas en el navegador.
Durante la compilación, emscripten incorporará datos de depuración DWARF en tu archivo binario. En términos generales, estos datos ayudan a la extensión a determinar qué variables de WebAssembly corresponden a tus variables de C/C++ y mucho más. De esta manera, DevTools puede mostrarte tus variables de C++ a pesar de que V8 ejecuta WebAssembly. Si tienes curiosidad, consulta esta entrada de blog para ver un ejemplo de datos de depuración DWARF.
Entonces, ¿qué sucede cuando revelas el lastNumber
? En cuanto haces clic en el ícono de memoria, DevTools verifica qué variable deseas inspeccionar. Luego, consulta la extensión sobre el tipo de datos y la ubicación de lastNumber
. En cuanto la extensión responde con esa información, el Inspector de memoria puede mostrar la porción de memoria relevante y, conociendo su tipo, también puede mostrarte el tamaño del objeto.
Si observas lastNumber
en el ejemplo anterior, es posible que notes que inspeccionamos lastNumber: int *
, pero el chip en el Inspector de memoria dice *lastNumber: int
. ¿Qué sucede? El inspector usa la anulación de referencias de punteros de estilo C++ para indicar el tipo de objeto que se muestra. Si inspeccionas un puntero, el inspector te mostrará a qué apunta.
Cómo conservar los aspectos destacados en los pasos del depurador
Cuando revelas un objeto en el Inspector de memoria y avanzas con el depurador, el Inspector conserva el resaltado si considera que aún es aplicable. Inicialmente, no teníamos esta función en nuestro plan de desarrollo, pero rápidamente nos dimos cuenta de que esto comprometía tu experiencia de depuración. Imagina tener que volver a inspeccionar el array después de cada paso, como en el siguiente video.
Cuando el depurador alcanza un nuevo punto de interrupción, el Inspector de memoria vuelve a consultar V8 y la extensión para la variable asociada con el elemento destacado anterior. Luego, compara las ubicaciones y los tipos de los objetos. Si coinciden, el elemento destacado persiste. En el video anterior, hay un bucle for que escribe en el array x
. Estas operaciones no cambian el tipo ni la posición del array, por lo que permanece destacado.
Te preguntarás cómo esto afecta a los punteros. Si tienes un puntero destacado y lo vuelves a asignar a un objeto diferente, las posiciones anterior y nueva de los objetos destacados difieren, y el resaltado desaparece. Dado que el objeto al que se apunta recientemente puede residir en cualquier lugar de la memoria de WebAssembly y es probable que tenga poca relación con la ubicación de memoria anterior, quitar el resaltado es más claro que saltar a una nueva ubicación de memoria. Para volver a destacar el puntero, haz clic en su ícono de memoria en el panel Alcance.
Conclusión
En este artículo, se describieron nuestras mejoras en el Inspector de memoria para la depuración de C/C++. Esperamos que las nuevas funciones simplifiquen la depuración de la memoria de tus apps de C/C++. Si tienes sugerencias para mejorarlo, informa un error.
¿Qué sigue?
Para obtener más información, consulta: