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 búferes de memoria lineales. En este artículo, analizaremos cómo mejoramos el Inspector para la depuración de C/C++ y los desafíos técnicos que enfrentamos durante el proceso.

Estas son algunas entradas de blog relevantes si no estás familiarizado con la depuración C/C++ y el Inspector de memoria:

Introducción

El Inspector de memoria te proporciona opciones de depuración más potentes para búferes de memoria lineales. En el caso de C/C++, puedes inspeccionar objetos de memoria C/C++ en la memoria WebAssembly.

Reconocer los bytes de tu objeto entre la memoria circundante de WebAssembly era un problema. Debes conocer el tamaño del objeto y contar bytes desde su inicio. En la siguiente captura de pantalla, se selecciona el primer byte de un array int32 de 10 elementos, pero no queda claro de inmediato qué otros bytes pertenecen al array. ¿No sería genial si pudieras reconocer de inmediato todos los bytes que pertenecen al objeto?

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

Cómo destacar 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 del recuerdo que los rodea.

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

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. Este chip te recuerda el nombre y tipo de la memoria destacada. Haz clic en el chip para saltar a la memoria del objeto. Si colocas el cursor sobre el chip, aparecerá un ícono de cruz. Haz clic en él para quitar el destacado.

Cuando seleccionas un byte fuera del objeto que inspeccionas, el resaltado se desenfoca para evitar distraerte. Para volver a enfocarlo, vuelve a hacer clic en cualquiera de los bytes del objeto o en el chip.

La compatibilidad del resaltado de objetos no se limita a los arrays. También puedes inspeccionar structs, objetos y punteros. Estos cambios hacen que explorar la memoria de tus apps de C/C++ sea más fácil que nunca.

¿Quieres probarla? Deberás hacer lo siguiente:

  • Tener Chrome 107 o una versión posterior
  • Instala la extensión DWARF de C/C++.
  • Habilita la depuración de DWARF en DevTools > Configuración. Settings > Experiments > WebAssemble Debugging: Enable DWARF support.
  • Abre esta página de demostración.
  • Sigue las instrucciones de la página.

Ejemplo de depuración

En esta sección, analizaremos un error de juguete a fin de 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 enteros y decide usar la aritmética de puntero para seleccionar el último elemento. Lamentablemente, el programador cometió un error al calcular el 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 demostración. Primero, inspeccionan el array en el Inspector de memoria y observan que el array numbers contiene solo 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. Se destacaron todos los elementos del array.

A continuación, revelan la variable lastNumber del panel Scope y observan que el puntero apunta a un número entero fuera del array. Equipado con este conocimiento, el programador se da cuenta de que cuentan 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 al que apunta un puntero llamado &quot;lastNumber&quot;. La memoria destacada se encuentra justo después del último byte del array previamente destacado.

Si bien este es un ejemplo de juguete, ilustra la manera en que el resaltado de objetos transmite de manera efectiva 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 C/C++.

Cómo las Herramientas para desarrolladores determinan qué destacar

En esta sección, analizaremos el ecosistema de herramientas que habilita la depuración de C/C++. Específicamente, aprenderás cómo Herramientas para desarrolladores, V8, la extensión C/C++ de DWARF y Emscripten permiten la depuración en C/C++ en Chrome.

Para aprovechar toda la potencia de la depuración C/C++ en Herramientas para desarrolladores, necesitas dos cosas:

  • 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 de DWARF a tu objeto binario. En general, estos datos ayudan a la extensión a descubrir qué variables de WebAssembly corresponden a tus variables C/C++ y mucho más. De esta manera, Herramientas para desarrolladores puede mostrarte tus variables C++ a pesar de que V8 ejecute WebAssembly. Si te interesa, consulta esta entrada de blog para ver un ejemplo de datos de depuración de DWARF.

Entonces, ¿qué sucede en realidad cuando revelas el lastNumber? Cuando haces clic en el ícono de memoria, Herramientas para desarrolladores verifica 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 conocer su tipo, y 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 muestra *lastNumber: int. ¿Qué proporciona? El inspector usa la desreferencia de puntero de estilo C++ para indicar el tipo de objeto que se te muestra. Si inspeccionas un puntero, el inspector te mostrará a qué apunta.

Aspectos destacados persistentes de los pasos del depurador

Cuando revelas un objeto en el Inspector de memoria y usas el depurador, el Inspector conserva el resaltado si cree que es aplicable. Al principio, no teníamos esta función en nuestra hoja de ruta, pero rápidamente nos dimos cuenta de que 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 de la variable asociada con el destacado anterior. Luego, compara las ubicaciones y los tipos de los objetos. Si coinciden, se destacará el texto destacado. 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.

Quizás te preguntes cómo esto afecta a los punteros. Si tienes un puntero destacado y lo reasignas a otro objeto, la posición anterior y la nueva de los objetos destacados serán diferentes, y el resaltado desaparecerá. Dado que el objeto recién apuntado puede alojarse en cualquier lugar de la memoria de WebAssembly y es probable que tenga poca relación con la ubicación de la 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 el ícono de memoria en el panel Scope.

Conclusión

En este artículo, se describen las mejoras que implementamos 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 mejorarla, informa un error.

¿Qué sigue?

Para obtener más información, consulta: