Extensión del Inspector de memoria para la depuración de C/C++

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:

Introducción

El Inspector de memoria te ofrece opciones de depuración más potentes para búferes de memoria lineales. 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 su inicio. En la siguiente captura de pantalla, se seleccionó el primer byte de un array int32 de 10 elementos, pero no es 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?

Captura de pantalla del inspector de memoria original con un solo byte destacado

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.

Captura de pantalla del inspector de memoria actualizado con un array destacado con colores intensos

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 enfoque se quita para evitar distraerte. Para volver a enfocarlo, haz clic en cualquiera de los bytes del objeto o en el chip.

La compatibilidad con el resalte 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. 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.

Captura de pantalla del inspector de memoria abierto con un array int32 inspeccionado. Todos los elementos del array están destacados.

A continuación, revela la variable lastNumber del panel Scope 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.

Captura de pantalla del inspector de memoria abierto que muestra la memoria destacada a la que apunta un puntero llamado &quot;lastNumber&quot;. La memoria destacada se encuentra justo después del último byte del array destacado anteriormente.

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 permiten la depuración con 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 C/C++ y mucho más. De esta manera, DevTools puede mostrarte tus variables de C++ a pesar de que V8 ejecuta WebAssembly. Si te interesa, consulta esta entrada de blog para ver un ejemplo de datos de depuración de DWARF.

Entonces, ¿qué sucede cuando revelas el lastNumber? En cuanto haces clic en el ícono de memoria, Herramientas para desarrolladores verificará qué variable quieres 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 del Inspector de memoria dice *lastNumber: int, ¿qué proporciona? 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 que tienes 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 elemento destacado 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 las mejoras que realizamos en el Inspector de memoria para la depuración 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: