Referencia de lenguaje, compilación y depuración de AddressSanitizer

En las secciones de este artículo se describe la especificación del lenguaje de AddressSanitizer, junto con las opciones del compilador y del enlazador. También se describen las opciones que controlan la integración del depurador de Visual Studio específica de AddressSanitizer.

Para más información sobre el entorno de ejecución de AddressSanitizer, consulte la referencia del entorno de ejecución. Incluye información sobre las funciones interceptadas y cómo conectar asignadores personalizados. Para más información sobre cómo guardar volcados de memoria de errores de AddressSanitizer, consulte la referencia de volcado de memoria.

Especificación del lenguaje

__SANITIZE_ADDRESS__

La macro __SANITIZE_ADDRESS__ del preprocesador se define como 1 cuando se establece /fsanitize=address. Esta macro es útil para que los usuarios avanzados especifiquen de manera condicional el código fuente para la presencia del entorno de ejecución de AddressSanitizer.

#include <cstdio>

int main() {
    #ifdef __SANITIZE_ADDRESS__
        printf("Address sanitizer enabled");
    #else
        printf("Address sanitizer not enabled");
    #endif
    return 1;
}

__declspec(no_sanitize_address)

El especificador __declspec(no_sanitize_address) se puede usar para deshabilitar de forma selectiva el saneador en las funciones, las variables locales o las variables globales. Este elemento __declspec afecta al comportamiento del compilador, no al comportamiento del entorno de ejecución.

__declspec(no_sanitize_address)
void test1() {
    int x[100];
    x[100] = 5; // ASan exception not caught
}

void test2() {
    __declspec(no_sanitize_address) int x[100];
    x[100] = 5; // ASan exception not caught
}

__declspec(no_sanitize_address) int g[100];
void test3() {
    g[100] = 5; // ASan exception not caught
}

Compilador

Opción del compilador /fsanitize=address

La opción del compilador /fsanitize=address instrumenta las referencias a la memoria en el código para detectar errores de seguridad de memoria en tiempo de ejecución. La instrumentación conecta cargas, almacenes, ámbitos, alloca y funciones de CRT. Puede detectar errores ocultos, como out-of-bounds, use-after-free, use-after-scope, etc. Para obtener una lista no exhaustiva de errores detectados en tiempo de ejecución, consulte Ejemplos de errores de AddressSanitizer.

/fsanitize=address es compatible con todos los niveles de optimización de C++ o C existentes (por ejemplo, /Od, /O1/O2, /O2 /GL y la optimización guiada por perfiles). El código generado con esta opción funciona con CRT estáticas y dinámicas (por ejemplo, /MD, /MDd, /MT y /MTd). Esta opción del compilador se puede usar para crear un archivo .EXE o .DLL dirigido a sistemas x86 o x64. La información de depuración es necesaria para un formato óptimo de las pilas de llamadas.

Para ver ejemplos de código que muestran varios tipos de detección de errores, consulte Ejemplos de errores de AddressSanitizer.

Opción del compilador /fsanitize=fuzzer (experimental)

La opción del compilador /fsanitize=fuzzer agrega LibFuzzer a la lista de bibliotecas predeterminada. También establece las siguientes opciones de cobertura de saneamiento:

Se recomienda usar /fsanitize=address con /fsanitize=fuzzer.

Estas bibliotecas se agregan a la lista de bibliotecas predeterminada al especificar /fsanitize=fuzzer:

Opción de runtime Biblioteca LibFuzzer
/MT clang_rt.fuzzer_MT-{arch}
/MD clang_rt.fuzzer_MD-{arch}
/MTd clang_rt.fuzzer_MTd-{arch}
/MDd clang_rt.fuzzer_MDd-{arch}

También están disponibles las bibliotecas LibFuzzer que omiten la main función. Es su responsabilidad definir main y llamar a LLVMFuzzerInitialize y LLVMFuzzerTestOneInput cuando use estas bibliotecas. Para usar una de estas bibliotecas, especifique y vincule /NODEFAULTLIB explícitamente con la biblioteca siguiente que corresponde al entorno de ejecución y la arquitectura:

Opción de runtime Biblioteca no_main de LibFuzzer
/MT clang_rt.fuzzer_no_main_MT-{arch}
/MD clang_rt.fuzzer_no_main_MD-{arch}
/MTd clang_rt.fuzzer_no_main_MTd-{arch}
/MDd clang_rt.fuzzer_no_main_MDd-{arch}

Si especifica /NODEFAULTLIB y no especifica una de estas bibliotecas, obtendrá un error de vínculo de símbolo externo sin resolver.

Opción del compilador /fsanitize-address-use-after-return (experimental)

De forma predeterminada, el compilador de MSVC (a diferencia de Clang) no genera código para asignar marcos en el montón para detectar errores use-after-return. Para detectar estos errores mediante AddressSanitizer, debe hacer lo siguiente:

  1. Compilar con la opción /fsanitize-address-use-after-return.
  2. Antes de ejecutar el programa, ejecutar set ASAN_OPTIONS=detect_stack_use_after_return=1 para establecer la opción de comprobación en tiempo de ejecución.

La /fsanitize-address-use-after-return opción hace que el compilador genere código para usar un marco de pila dual en el montón cuando las variables locales se consideran "direcciones tomadas". Este código es mucho más lento que usar /fsanitize=address solo. Para más información y ver un ejemplo, consulte Error: stack-use-after-return.

El marco de pila dual del montón permanece después de la devolución de la función que lo creó. Considere un ejemplo en el que la dirección de una variable local, asignada a una ranura del montón, se usa después de la devolución. Los bytes de sombra asociados al marco de montón ficticio contienen el valor 0xF9. Ese valor 0xF9 significa un error stack-use-after-return cuando se notifica el error en tiempo de ejecución.

Los marcos de pila se asignan en el montón y permanecen después de que las funciones devuelvan resultados. El entorno de ejecución usa la recolección de elementos no utilizados para liberar de forma asincrónica estos objetos ficticios de marco de llamada, después de un intervalo de tiempo determinado. Las direcciones de las variables locales se transfieren a marcos persistentes en el montón. Así es como el sistema puede detectar cuándo se usan las variables locales después de que la función de definición devuelva resultados. Para más información, consulte el algoritmo para el uso de pila después de la devolución, tal y como se documenta en Google.

Enlazador

Opción del enlazador /INFERASANLIBS[:NO]

La /fsanitize=address opción del compilador marca los objetos para especificar la biblioteca AddressSanitizer que se va a vincular al archivo ejecutable. Las bibliotecas tienen nombres que comienza por clang_rt.asan*. La opción del enlazador /INFERASANLIBS (activada de forma predeterminada) vincula estas bibliotecas desde sus ubicaciones predeterminadas automáticamente. Estas son las bibliotecas elegidas y vinculadas automáticamente.

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 de i386 y x86_64. 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}

La opción del enlazador /INFERASANLIBS:NO impide que el enlazador vincule un archivo de biblioteca clang_rt.asan* desde la ubicación predeterminada. Si usa esta opción, agregue la ruta de acceso de la biblioteca en los scripts de compilación. De lo contrario, el enlazador notifica un error de símbolo externo sin resolver.

Versiones anteriores

Antes de Visual Studio 17.7 Preview 3, las compilaciones vinculadas estáticamente (/MT o /MTd) no usaba 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. Además, los proyectos vinculados dinámicamente (/MD o /MTd) 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.

Opción en tiempo de ejecución de CRT DLL o EXE Bibliotecas en tiempo de ejecución de AddressSanitizer
/MT EXE clang_rt.asan-{arch}, clang_rt.asan_cxx-{arch}
/MT Archivo DLL clang_rt.asan_dll_thunk-{arch}
/MD Es posible usar el clang_rt.asan_dynamic-{arch}, clang_rt.asan_dynamic_runtime_thunk-{arch}
/MTd EXE clang_rt.asan_dbg-{arch}, clang_rt.asan_dbg_cxx-{arch}
/MTd Archivo DLL clang_rt.asan_dbg_dll_thunk-{arch}
/MDd Es posible usar el clang_rt.asan_dbg_dynamic-{arch}, clang_rt.asan_dbg_dynamic_runtime_thunk-{arch}

Integración de Visual Studio

Opción del compilador /fno-sanitize-address-vcasan-lib

La opción /fsanitize=address crea vínculos en bibliotecas adicionales para una experiencia de depuración mejorada de Visual Studio cuando se produce una excepción de AddressSanitizer. Estas bibliotecas se denominan VCAsan. Las bibliotecas permiten que Visual Studio muestre los errores de AddressSanitizer en el código fuente. También permiten que el archivo ejecutable genere volcados de memoria cuando se crea un informe de errores de AddressSanitizer. Para más información, consulte Biblioteca de funcionalidades extendidas de AddressSanitizer de Visual Studio.

La biblioteca elegida depende de las opciones del compilador y se vincula automáticamente.

Opción de runtime Versión de VCAsan
/MT libvcasan.lib
/MD vcasan.lib
/MTd libvcasand.lib
/MDd vcasand.lib

Sin embargo, si compila con /Zl (omitir el nombre de biblioteca predeterminado), debe especificar manualmente la biblioteca. Si no lo hace, obtendrá un error de vínculo de símbolo externo sin resolver. A continuación se incluyen algunos ejemplos típicos:

error LNK2001: unresolved external symbol __you_must_link_with_VCAsan_lib
error LNK2001: unresolved external symbol ___you_must_link_with_VCAsan_lib

La depuración mejorada se puede deshabilitar en tiempo de compilación mediante la opción /fno-sanitize-address-vcasan-lib.

La variable de entorno ASAN_VCASAN_DEBUGGING

La opción del compilador /fsanitize=address genera un archivo binario que expone errores de seguridad de memoria en tiempo de ejecución. Cuando el archivo binario se inicia desde la línea de comandos y se notifica un error en tiempo de ejecución, imprime los detalles del error. A continuación, sale del proceso. La variable de entorno ASAN_VCASAN_DEBUGGING se puede establecer para iniciar el IDE de Visual Studio en el momento en que se notifica un error en tiempo de ejecución. Esta opción del compilador le permite ver el error, superpuesto sobre el código fuente, en la línea y columna precisas que provocaron el error.

Para habilitar este comportamiento, ejecute el comando set ASAN_VCASAN_DEBUGGING=1 antes de ejecutar la aplicación. Puede deshabilitar la experiencia de depuración mejorada mediante la ejecución de set ASAN_VCASAN_DEBUGGING=0.

Consulte también

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