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 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 fue un problema. Debes conocer el tamaño del objeto y contar los bytes desde su inicio. En la siguiente captura de pantalla, se selecciona el primer byte de un array int32 de 10 elementos, pero no es inmediatamente claro 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 que los rodea.

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 resaltado se desenfoca para evitar distracciones. 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 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 probarlo? Deberás hacer lo siguiente:

  • Tener Chrome 107 o versiones posteriores
  • Instala la extensión de DWARF de C/C++.
  • Habilita la depuración DWARF en DevTools > 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 de su 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 continuar con 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 destacan todos los elementos del array.

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ó de manera incorrecta 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.

Si bien este es un ejemplo práctico, ilustra cómo el resalte 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 en la memoria de tu app C/C++.

Cómo las Herramientas para desarrolladores descubren 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 desbloquear 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 integradas 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.

¿Qué sucede en realidad 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 relevante de memoria y, dado su tipo, también puede indicarte 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 realizas un paso con el depurador, el Inspector conserva el resaltado si cree que todavía es aplicable. En un principio, no teníamos esta función en nuestra hoja de ruta, pero rápidamente nos dimos cuenta de que esto pone en riesgo 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 obtener la variable asociada con el momento 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 anteriores y nuevas de los objetos destacados difieren y desaparece el resaltado. Dado que el objeto recientemente apuntado puede residir 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 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 seguir mejorando, informa un error para informarnos.

¿Qué sigue?

Para obtener más información, consulta: