AddressSanitizer

Información general

Los lenguajes C y C++ son eficaces, pero pueden sufrir una clase de errores que afectan a la corrección del programa y a la seguridad del programa. A partir de la versión 16.9 de Visual Studio 2019, el compilador de Microsoft para C/C++ (MSVC) y el IDE admiten el desinfectador AddressSanitizer. AddressSanitizer (ASan) es un compilador y una tecnología en tiempo de ejecución que expone muchos errores difíciles de encontrar con cero falsos positivos:

Por qué usar AddressSanitizer

Utiliza AddressSanitizer para reducir el tiempo empleado en:

  • Corrección básica
  • Portabilidad multiplataforma
  • Seguridad
  • pruebas de esfuerzo
  • Integración de un código nuevo

AddressSanitizer, introducido originalmente por Google, proporciona tecnologías de búsqueda de errores en tiempo de ejecución que usan los sistemas de compilación existentes y los recursos de prueba existentes directamente.

Integración y compatibilidad de compilaciones

AddressSanitizer se integra con el sistema de proyectos de Visual Studio, el sistema de compilación de CMake y el IDE. Los proyectos pueden habilitar AddressSanitizer estableciendo una propiedad de proyecto o mediante una opción adicional del compilador: /fsanitize=address. Esta opción es compatible con todos los niveles de optimización y configuraciones de x86 y x64. Sin embargo, no es compatible con editar y continuar, vinculado incremental y /RTC.

Soporte para volcados de bloqueo

A partir de la versión 16.9 de Visual Studio 2019, la tecnología AddressSanitizer de Microsoft permite la integración con el IDE de Visual Studio. La funcionalidad puede opcionalmente crear un archivo de volcado de memoria cuando el saneador encuentra un error en tiempo de ejecución. Si establece la variable de entorno antes de ejecutar el programa ASAN_SAVE_DUMPS=MyFileName.dmp, se crea un archivo de volcado de sistema con metadatos adicionales para una depuración eficaz posterior de errores diagnosticados con precisión. Estos archivos de volcado facilitan el uso extendido de AddressSanitizer para:

  • Pruebas de máquinas locales
  • Pruebas distribuidas en las instalaciones
  • Flujos de trabajo basados en la nube para pruebas

Instalar AddressSanitizer

Las cargas de trabajo de C++ en el Instalador de Visual Studio instalan las bibliotecas addressSanitizer y la integración del IDE de forma predeterminada. Sin embargo, si va a actualizar desde una versión anterior de Visual Studio 2019, use el Instalador para habilitar la compatibilidad con ASan después de la actualización. Puede abrir el instalador desde el menú principal de Visual Studio seleccionando Tools>Get Tools and Features. Elija Modify en la instalación de Visual Studio existente desde el instalador de Visual Studio para ir a la siguiente pantalla.

Captura de pantalla que muestra Visual Studio Installer con el componente C++ AddressSanitizer resaltado en la sección Opcional.

Nota:

Si ejecuta Visual Studio en la nueva actualización, pero no ha instalado ASan, recibirá un error al ejecutar el código:

LNK1356: no se encuentra la biblioteca 'clang_rt.asan_dynamic-i386.lib'

Usar AddressSanitizer

Comience a compilar los ejecutables con la opción del compilador /fsanitize=address mediante cualquiera de estos métodos de desarrollo comunes:

  • Compilaciones de línea de comandos
  • Sistema de proyectos de Visual Studio
  • Integración de Visual Studio CMake

Vuelva a compilar el código y, a continuación, ejecute el programa normalmente para exponer muchos tipos de errores con diagnóstico preciso. Puede revisar los problemas en el IDE del depurador, la línea de comandos o el archivo de volcado de memoria.

Microsoft recomienda usar AddressSanitizer en estos tres flujos de trabajo estándar:

En este artículo se describe la información necesaria para habilitar los tres flujos de trabajo enumerados anteriormente. La información es específica de la implementación dependiente de la plataforma de Windows 10 (y versiones posteriores) de AddressSanitizer. Esta documentación complementa la documentación de Google, Apple y GCC.

Nota:

La compatibilidad se limita a x86 y x64 en Windows 10 y versiones posteriores. Envíenos sus comentarios sobre lo que le gustaría ver en futuras versiones. Sus comentarios nos ayudan a priorizar otros saneadores para el futuro, como /fsanitize=thread, /fsanitize=leak, /fsanitize=memory, /fsanitize=undefined o /fsanitize=hwaddress. Puede notificar errores aquí si tiene problemas.

Uso AddressSanitizer desde una línea de comandos para desarrolladores

Use la opción del compilador /fsanitize=address en un terminal de desarrollador para habilitar la compilación del entorno de ejecución de AddressSanitizer. La /fsanitize=address opción es compatible con los niveles de optimización de C++ o C existentes, por ejemplo, /Od, /O1, /O2y /O2 /GL. La opción funciona con CRT estáticos y dinámicos (por ejemplo, /MD, /MDd, /MT y /MTd). Funciona tanto si se crea un archivo EXE como un DLL. La información de depuración es necesaria para formatear óptimamente la pila de llamadas. En el ejemplo siguiente, cl /fsanitize=address /Zi se pasa en la línea de comandos.

Nota:

AddressSanitizer no admite la optimización guiada por perfiles (PGO). AddressSanitizer no se debe usar en producción.

Las bibliotecas AddressSanitizer (archivos de tipo .lib) se vinculan automáticamente. Para más información, consulte AddressSanitizer: referencia de lenguaje, compilación y depuración.

Ejemplo: desbordamiento de búfer global básico

// basic-global-overflow.cpp
#include <stdio.h>
int x[100];
int main() {
    printf("Hello!\n");
    x[100] = 5; // Boom!
    return 0;
}

Con un símbolo del sistema para desarrolladores para Visual Studio 2019, compile basic-global-overflow.cpp con /fsanitize=address /Zi.

Captura de pantalla que muestra un símbolo del sistema con el comando

Al ejecutar el resultado basic-global-overflow.exe en la línea de comandos, crea el informe de errores con formato siguiente.

Tenga en cuenta los cuadros rojos superpuestos que resaltan siete fragmentos clave de información:

Captura de pantalla del depurador que muestra un error de desbordamiento global básico.

Resaltados rojos, de arriba a abajo

  1. El error de seguridad de la memoria es un desbordamiento global de búfer.
  2. Había 4 bytes (32 bits) almacenados fuera de cualquier variable definida por el usuario.
  3. El almacenamiento tuvo lugar en la función main() definida en el archivo basic-global-overflow.cpp en la línea 7.
  4. La variable denominada x se define en basic-global-overflow.cpp en la línea 3, empezando por la columna 8.
  5. Esta variable x global tiene un tamaño de 400 bytes.
  6. El byte de sombra exacto que describe la dirección de destino del almacén tenía un valor de 0xf9.
  7. La leyenda de bytes de sombra indica que 0xf9 es un área de relleno a la derecha de int x[100].

Nota:

Cuando AddressSanitizer informa de un error, el entorno de ejecución de ASan invoca al simbolizador de LLVM para obtener los nombres de las funciones en la pila de llamadas.

Uso de AddressSanitizer en Visual Studio

AddressSanitizer se integra con el IDE de Visual Studio. Para activar AddressSanitizer para un proyecto de MSBuild, haga clic con el botón derecho en el proyecto en Explorador de soluciones y elija Propiedades. En el cuadro de diálogo Páginas de propiedades, seleccione Propiedades de configuración>C/C++>General y, a continuación, modifique la propiedad Activar AddressSanitizer. Elija Aceptar para guardar los cambios.

Captura de pantalla del diálogo de las Páginas de propiedades mostrando la propiedad Activar AddressSanitizer.

Para compilar desde el IDE, opte por no participar en las opciones incompatibles. Para un proyecto existente compilado mediante /Od (o modo de depuración), es posible que tenga que desactivar estas opciones:

Para compilar y ejecutar el depurador, presione F5. Aparece una ventana de excepción lanzada en Visual Studio.

Captura de pantalla del depurador mostrando un error de desbordamiento de búfer global.

Uso de AddressSanitizer desde Visual Studio: CMake

Para habilitar AddressSanitizer para un proyecto de CMake creado para Windows de destino, siga estos pasos:

  1. Abra el menú desplegable Configuraciones de la barra de herramientas de la parte superior del IDE y seleccione Administrar configuraciones.

    Captura de pantalla del menú desplegable de configuración de CMake, que muestra opciones como x64 Debug, x64 Release y, al final de la lista, Administrar configuraciones..., resaltado.

    Esa acción abre el editor de configuración del proyecto de CMake, que refleja el contenido del archivo CMakeSettings.json de su proyecto.

  2. Elija el vínculo Editar JSON . Esta selección cambia la vista a JSON sin formato.

  3. Para activar AddressSanitizer, añada el siguiente fragmento de código al preajuste "windows-base", dentro de "configurePresets":.

    "environment": {
      "CFLAGS": "/fsanitize=address",
      "CXXFLAGS": "/fsanitize=address"
    }
    

    "configurePresets" parece algo como esto, después:

        "configurePresets": [
          {
            "name": "windows-base",
            "hidden": true,
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "installDir": "${sourceDir}/out/install/${presetName}",
            "cacheVariables": {
              "CMAKE_C_COMPILER": "cl.exe",
              "CMAKE_CXX_COMPILER": "cl.exe"
            },
            "condition": {
              "type": "equals",
              "lhs": "${hostSystemName}",
              "rhs": "Windows"
            },
            "environment": {
              "CFLAGS": "/fsanitize=address",
              "CXXFLAGS": "/fsanitize=address"
            }
          },
    
  4. AddressSanitizer no funciona si se especifica edit-and-continue (/ZI), que está habilitado por defecto para los nuevos proyectos de CMake. En CMakeLists.txt, comente (anteponga #) la línea que comienza por set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT". Esa línea tiene un aspecto similar al siguiente:

    # set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
    
  5. Use Ctrl+S para guardar este archivo JSON.

  6. Borre el directorio de caché de CMake y vuelva a configurar eligiendo en el menú de Visual Studio: Project Delete cache (Eliminar caché del proyecto>) y Reconfigure (Volver a configurar). Elija cuando aparezca el mensaje para borrar el directorio de caché y volver a configurarlo.

  7. Reemplace el contenido del archivo de origen, por ejemplo, CMakeProject1.cpp, por el código siguiente:

    // CMakeProject1.cpp : Defines the entry point for the application
    
    #include <stdio.h>
    
    int x[100];
    
    int main()
    {
        printf("Hello!\n");
        x[100] = 5; // Boom!
        return 0;
    }
    
  8. Elija F5 para volver a compilar y ejecutar en el depurador.

    Esta captura de pantalla registra el error de la compilación de CMake.

    Captura de pantalla que muestra una excepción que dice: Error de Address Sanitizer: desbordamiento de búfer global.

Volcados de fallos de AddressSanitizer

AddressSanitizer incluye funcionalidad para su uso con flujos de trabajo distribuidos y en la nube. Esta funcionalidad permite la visualización sin conexión de un error AddressSanitizer en el IDE. El error se superpone a su origen, tal como lo experimentaría en una sesión de depuración en tiempo real.

Estos archivos de volcado de memoria pueden mejorar la eficiencia al analizar un fallo. No es necesario volver a ejecutar, buscar datos remotos ni buscar una máquina que se desconecte.

Para generar un archivo de volcado de memoria que puede ver en Visual Studio en otra máquina en una fecha posterior:

set ASAN_SAVE_DUMPS=MyFileName.dmp

A partir de Visual Studio 16.9, puede mostrar un error diagnosticado con precisión, almacenado en el archivo *.dmp, sobre el código fuente.

Esta funcionalidad de volcado de memoria permite flujos de trabajo basados en la nube o pruebas distribuidas. También se puede usar para archivar un error detallado y accionable en cualquier escenario.

Errores de ejemplo

AddressSanitizer puede detectar varios tipos de errores del uso incorrecto de memoria. Estos son muchos de los errores en runtime notificados al ejecutar los archivos binarios compilados mediante la opción del compilador AddressSanitizer (/fsanitize=address):

Para obtener más información sobre los ejemplos, consulte Ejemplos de errores de AddressSanitizer.

Diferencias con Clang 12.0

MSVC actualmente difiere de Clang 12.0 en dos áreas funcionales:

  • stack-use-after-scope: esta configuración está activada de forma predeterminada y no se puede desactivar.
  • stack-use-after-return: esta funcionalidad requiere una opción de compilador adicional, y no está disponible con solo establecer ASAN_OPTIONS.

Estas decisiones se tomaron para reducir la matriz de pruebas necesaria para entregar esta primera versión.

Las características que podrían provocar falsos positivos en Visual Studio 2019 16.9 no se incluyeron. Esa disciplina ha reforzado la integridad de las pruebas efectivas necesarias al considerar la interoperabilidad con décadas de código existente. Es posible que se consideren más funcionalidades en versiones posteriores:

Para obtener más información, consulte Building for AddressSanitizer with MSVC (Compilación de addressSanitizer con MSVC).

Documentación del sector

Existe una amplia documentación para estas implementaciones dependientes del lenguaje y la plataforma de la tecnología AddressSanitizer.

Este documento seminal sobre el AddressSanitizer (externo) describe la implementación.

Consulte también