Runtime AddressSanitizer

La biblioteca de runtime AddressSanitizer intercepta las funciones y las operaciones comunes de asignación de memoria para habilitar la inspección de los accesos a la memoria. Hay varias bibliotecas de runtime diferentes que admiten los distintos tipos de ejecutables que el compilador puede generar. El compilador y el enlazador vinculan automáticamente las bibliotecas runtime adecuadas, siempre y cuando pase la opción /fsanitize=address en el tiempo de compilación. Se puede invalidar este comportamiento predeterminado mediante la opción /NODEFAULTLIB en tiempo de vínculo. Para obtener más información, consulte la sección sobre la vinculación en la referencia sobre lenguaje, compilación y depuración de AddressSanitizer.

Al compilar con cl /fsanitize=address, el compilador genera instrucciones para administrar y comprobar bytes de sombra. El programa usa esta instrumentación para comprobar los accesos a la memoria en la pila, en el montón o en el ámbito global. El compilador también genera metadatos que describen variables globales y de pila. Estos metadatos permiten que el runtime genere diagnósticos de errores precisos: nombres de función, líneas y columnas en el código fuente. En combinación, las comprobaciones del compilador y las bibliotecas del runtime pueden diagnosticar con precisión muchos tipos de errores de seguridad de memoria si se encuentran en el runtime.

A continuación se muestra la lista de bibliotecas en tiempo de ejecución para vincular al entorno de ejecución addressSanitizer, a partir de Visual Studio 17.7 Preview 3. Para obtener más información sobre las /MT opciones (vincular estáticamente el tiempo de ejecución) y /MD (vincular dinámicamente el redist at runtime), vea /MD, /MT, /LD (Usar biblioteca en tiempo de ejecución).

Nota:

En la tabla siguiente, {arch} es i386 o x86_64. Estas bibliotecas usan convenciones de Clang para los nombres de arquitectura. Las convenciones de MSVC son normalmente x86 y x64 en lugar i386 de y x86_64, pero hacen referencia a las mismas arquitecturas.

Opción de CRT Biblioteca en tiempo de ejecución addressSanitizer (.lib) Binario de tiempo de ejecución de direcciones (.dll)
/MT o /MTd clang_rt.asan_dynamic-{arch}, clang_rt.asan_static_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MD o /MDd clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}

En el diagrama siguiente se muestra cómo se vinculan las bibliotecas de Language Runtime para las /MTopciones del compilador , /MTd, /MDy /MDd :

Diagrama de cómo se vinculan las bibliotecas en tiempo de ejecución para varias opciones del compilador.

La imagen muestra tres escenarios para vincular la biblioteca en tiempo de ejecución. La primera es /MT o /MTd. My_exe.exe y my_dll.dll se muestran con sus propias copias de los entornos de ejecución vcRuntime, Universal CRT y C++ vinculados estáticamente. Los escenarios muestran /MD en los que my_exe.exe y my_dll.dll comparten vcruntime140.dll, ucrtbase.dll y msvcp140.dll. El último escenario muestra /MDd en el que tanto my_exe.exe como my_dll.dll comparten las versiones de depuración de los entornos de ejecución: vcruntime140d.dll, ucrtbased.dll y msvcp140d.dll

En el diagrama siguiente se muestra cómo está vinculada la biblioteca de ASan para varias opciones del compilador:

Diagrama de cómo está vinculado el archivo DLL del entorno de ejecución de ASan.

La imagen muestra cuatro escenarios para vincular la biblioteca en tiempo de ejecución de ASan. Los escenarios son para /MT (vincular estáticamente el tiempo de ejecución), /MTd (vincular estáticamente el tiempo de ejecución de depuración), /MD (vincular dinámicamente el redist en tiempo de ejecución), /MDd (vincular dinámicamente el redist de depuración en tiempo de ejecución). En todos los casos, my_exe.exe vínculos y sus asociados my_dll.dll vínculo a una sola instancia de clang-rt.asan-dynamix-x86_64.dll.

Incluso cuando se vincula estáticamente, el archivo DLL del entorno de ejecución de ASan debe estar presente en tiempo de ejecución, a diferencia de otros componentes de C Runtime.

Versiones anteriores

Antes de Visual Studio 17.7 Preview 3, las compilaciones vinculadas estáticamente (/MT o /MTd) no usaron una dependencia dll. En su lugar, el tiempo de ejecución addressSanitizer se vinculó estáticamente al EXE del usuario. A continuación, los proyectos DLL cargarían exportaciones desde el EXE del usuario para acceder a la funcionalidad de ASan.

Los proyectos vinculados dinámicamente (/MD o /MDd) usaron bibliotecas y archivos DLL diferentes en función de si el proyecto se configuró para depurar o liberar. Para obtener más información sobre estos cambios y sus motivaciones, consulte MSVC Address Sanitizer : un archivo DLL para todas las configuraciones en tiempo de ejecución.

En la tabla siguiente se describe el comportamiento anterior de la vinculación de la biblioteca en tiempo de ejecución AddressSanitizer antes de Visual Studio 17.7 Preview 3:

Opción de CRT DLL o EXE DEBUG? Biblioteca ASan (.lib) Binario en tiempo de ejecución de ASan (.dll)
/MT EXE No clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch} None
/MT Archivo DLL No clang_rt.asan_dll_thunk-{arch} Ninguno
/MD O bien No clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch} clang_rt.asan_dynamic-{arch}
/MT EXE clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch} None
/MT Archivo DLL clang_rt.asan_dbg_dll_thunk-{arch} None
/MD Es posible usar el clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch} clang_rt.asan_dbg_dynamic-{arch}

En el diagrama siguiente se muestra cómo se vinculó la biblioteca de ASan para varias opciones del compilador antes de Visual Studio 2022 17.7 Preview 3:

Diagrama de cómo se vinculó el archivo DLL del entorno de ejecución de ASan antes de Visual Studio 2022 Preview 3.

La imagen muestra cuatro escenarios para vincular la biblioteca en tiempo de ejecución de ASan. Los escenarios son para /MT (vincular estáticamente el tiempo de ejecución), /MTd (vincular estáticamente el tiempo de ejecución de depuración), /MD (vincular dinámicamente el redist en tiempo de ejecución), /MDd (vincular dinámicamente el redist de depuración en tiempo de ejecución). Para /MT, my_exe.exe tiene una copia vinculada estáticamente del entorno de ejecución de ASan. my_dll.dll vínculos al entorno de ejecución de ASan en my_exe.exe. Para /MTd, el diagrama es el mismo, excepto que usa el entorno de ejecución de ASan vinculado estáticamente. Para /MD, tanto my_exe.exe como my_dll.dll vínculo al entorno de ejecución de ASan vinculado dinámicamente denominado clang_rt.asan_dynamic-x86_64.dll. Para /MDd, el diagrama es el mismo, excepto my_exe.exe y my_dll.dll vínculo al entorno de ejecución de ASan de depuración denominado clang_rt.asan_dbg_dynamic-x86_64.dll.

Interceptación de funciones

AddressSanitizer logra la interceptación de funciones a través de muchas técnicas de almacenamiento en caliente. Estas técnicas se documentan mejor dentro del propio código fuente.

Las bibliotecas de runtime interceptan muchas funciones comunes de administración de memoria y manipulación de memoria. Para obtener una lista, consulte Lista de funciones interceptadas de AddressSanitizer. Los interceptores de asignación administran metadatos y bytes paralelos relacionados con cada llamada de asignación. Cada vez que se llama a una función de CRT, como malloc o delete, los interceptores establecen valores específicos en la región de memoria paralela de AddressSanitizer para indicar si esas ubicaciones del montón están actualmente accesibles y cuáles son los límites de la asignación. Estos bytes paralelos permiten que las comprobaciones generadas por el compilador de los bytes paralelos determinen si una carga o almacén es válida.

No se garantiza que la interceptación se realice correctamente. Si un prólogo de función es demasiado corto para que se escriba un jmp, se puede producir un error en la intercepción. Si se produce un error de interceptación, el programa arroja un debugbreak y se detiene. Si adjunta un depurador, este permite que la causa de la incidencia de interceptación sea clara. Si tiene este problema, informe que hay un error.

Nota:

Opcionalmente, los usuarios pueden intentar continuar después de una interceptación errónea estableciendo la variable de entorno ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE en cualquier valor. Continuar después de un error de interceptación puede dar lugar a informes de errores perdidos para esa función.

Asignadores personalizados y runtime de AddressSanitizer

El runtime de AddressSanitizer proporciona interceptores para interfaces comunes de asignador, malloc/free, new/delete,HeapAlloc/HeapFree(a través de RtlAllocateHeap/RtlFreeHeap). Muchos programas usan asignadores personalizados por un motivo u otro; un ejemplo sería cualquier programa que use dlmalloc o una solución mediante la interfaz de std::allocator y VirtualAlloc(). El compilador no puede agregar automáticamente llamadas de administración de memoria paralela a un asignador personalizado. Es responsabilidad del usuario usar la interfaz contra "poisoning" manual proporcionada. Esta API permite que estos asignadores funcionen correctamente con las convenciones existentes de runtime de AddressSanitizer y bytes paralelos.

Interfaz manual contra "poisoning" de AddressSanitizer

La interfaz para la optimización es sencilla, pero impone restricciones de alineación al usuario. Los usuarios pueden importar estos prototipos al importar sanitizer/asan_interface.h. Estos son los prototipos de función de interfaz:

void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);

Para mayor comodidad, el archivo de encabezado de interfaz de AddressSanitizer proporciona macros contenedoras. Estas macros comprueban si la funcionalidad AddressSanitizer está habilitada durante la compilación. Permiten que el código fuente omita las llamadas de la función de "poisoning" cuando no sean necesarias. Estas macros se deben preferir en vez de llamar directamente a las funciones anteriores:

#define ASAN_POISON_MEMORY_REGION(addr, size)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)

Requisitos de alineación para "poisoning" de AddressSanitizer

Cualquier "poisoning" manual de bytes paralelos debe tener en cuenta los requisitos de alineación. El usuario debe agregar relleno si es necesario para que los bytes paralelos finalicen en un límite de bytes en la memoria paralela. Cada bit de la memoria paralela de AddressSanitizer codifica el estado de un solo byte en la memoria de la aplicación. Esta codificación significa que el tamaño total de cada asignación, incluido cualquier relleno, debe alinearse con un límite de 8 bytes. Si no se cumple el requisito de alineación, puede provocar informes de errores incorrectos. Los informes incorrectos podrían manifestarse como informes que faltan (falsos negativos) o informes sobre falsos errores (falsos positivos).

Para obtener una ilustración del requisito de alineación y los posibles problemas, consulte los ejemplos de alineación de ASan proporcionados. Uno es un pequeño programa para mostrar lo que puede salir mal con el "poisoning" manual de la memoria paralela. El segundo es una implementación de ejemplo de "poisoning" manual mediante la interfaz de std::allocator.

Opciones de runtime

Microsoft C/C++ (MSVC) usa un runtime basado en el runtime de Clang AddressSanitizer desde el repositorio llvm-project. Por este motivo, la mayoría de las opciones de runtime se comparten entre las dos versiones. Aquí encontrará una lista completa de las opciones públicas del runtime de Clang. Documentamos algunas diferencias en las secciones siguientes. Si detecta opciones que no funcionan según lo previsto, informe sobre un error.

Opciones de AddressSanitizer no admitidas

  • detect_container_overflow
  • unmap_shadow_on_exit

Nota:

La opción de runtime halt_on_error de AddressSanitizer no funciona de la manera esperada. En las bibliotecas de runtime de Clang y de MSVC, muchos tipos de error se consideran no continuables, incluidos la mayoría de los errores de daños en la memoria.

Para obtener más información, consulte la sección Diferencias con Clang 12.0.

Opciones de runtime de AddressSanitizer específicas de MSVC

  • windows_hook_legacy_allocators Boolean, establecido en false para deshabilitar la interceptación de GlobalAlloc los asignadores y LocalAlloc .

    Nota:

    La opción windows_hook_legacy_allocators no estaba disponible en el runtime público de llvm-project cuando se escribió este artículo. La opción puede contribuir finalmente al proyecto público; sin embargo, depende de la revisión de código y la aceptación de la comunidad.

    La opción windows_hook_rtl_allocators, anteriormente una característica de participación opcional mientras AddressSanitizer era experimental, ahora está habilitada de forma predeterminada. En versiones anteriores a la versión 17.4.6 de Visual Studio 2022, el valor de opción predeterminado es false. En Visual Studio 2022, versión 17.4.6 y versiones posteriores, la opción windows_hook_rtl_allocators tiene truecomo valor predeterminado .

  • iat_overwrite Cadena, establecida en "error" de forma predeterminada. Otros valores posibles son "protect" y "ignore". Algunos módulos pueden sobrescribir los import address table de otros módulos para personalizar las implementaciones de determinadas funciones. Por ejemplo, los controladores suelen proporcionar implementaciones personalizadas para hardware específico. La iat_overwrite opción administra la protección del entorno de ejecución addressSanitizer frente a sobrescrituras para funciones específicas memoryapi.h . Actualmente, el tiempo de ejecución realiza un seguimiento de las VirtualAllocfunciones , VirtualProtecty VirtualQuery para la protección. Esta opción está disponible en Visual Studio 2022, versión 17.5, versión preliminar 1 y versiones posteriores. Los valores siguientes iat_overwrite controlan cómo reacciona el tiempo de ejecución cuando se sobrescriben las funciones protegidas:

    • Si se establece en "error" (valor predeterminado), el tiempo de ejecución notifica un error cada vez que se detecta una sobrescritura.
    • Si se establece en "protect", el tiempo de ejecución intenta evitar el uso de la definición sobrescrita y continúa. De hecho, la definición original memoryapi de la función se usa desde dentro del tiempo de ejecución para evitar la recursividad infinita. Otros módulos del proceso siguen usando la definición sobrescrita.
    • Si se establece en "ignore", el tiempo de ejecución no intenta corregir ninguna función sobrescrita y continúa con la ejecución.
  • windows_fast_fail_on_error Boolean (false de forma predeterminada), se establece en true para permitir que el proceso finalice con un __fastfail(71) después de imprimir el informe de errores.

Nota:

Cuando abort_on_error valor se establece en true, en Windows el programa finaliza con una salida(3). Para no cambiar el comportamiento actual, decidimos introducir esta nueva opción en su lugar. Si tanto abort_on_error como windows_fast_fail_on_error son true, el programa se cerrará con el __fastfail.

Lista de funciones interceptadas de AddressSanitizer (Windows)

El tiempo de ejecución addressSanitizer admite muchas funciones para habilitar las comprobaciones de seguridad de memoria en tiempo de ejecución. Esta es una lista no exhaustiva de las funciones que supervisa el runtime de AddressSanitizer.

Interceptores predeterminados

Interceptores opcionales

Los interceptores que se enumeran aquí solo se instalan cuando está habilitada una opción de runtime de AddressSanitizer. Establézcalo windows_hook_legacy_allocators en false para deshabilitar la interceptación del asignador heredado. set ASAN_OPTIONS=windows_hook_legacy_allocators=false

Consulte también

Introducción a AddressSanitizer
Problemas conocidos de AddressSanitizer
Referencia de lenguaje y compilación de AddressSanitizer
Bytes de sombra addressSanitizer
Pruebas distribuidas o en la nube addressSanitizer
Integración del depurador AddressSanitizer
Ejemplos de errores addressSanitizer