Compartir vía


Error: stack-use-after-return

Error del sanitizador de direcciones: Uso de la memoria de la pila después del retorno

Esta comprobación requiere la generación del código que se activa por una opción del compilador adicional, /fsanitize-address-use-after-return y estableciendo la variable de entorno ASAN_OPTIONS=detect_stack_use_after_return=1.

Esta comprobación puede ralentizar considerablemente la aplicación. Considere el resumen de Clang del algoritmo que admite el uso después de la devolución y los mayores costos de rendimiento.

Importante

Si crea un archivo de objeto mediante la opción del compilador /fsanitize-address-use-after-return adicional, el código generado por el compilador toma una decisión en tiempo de ejecución sobre cómo asignar un marco de pila. Si la variable de entorno ASAN_OPTIONS no está establecida en detect_stack_use_after_return, el código sigue siendo más lento que al usarse /fsanitize=address por sí mismo. Es más lento porque todavía hay sobrecarga adicional de algunos marcos de pila que asignan espacio para las partes de un marco mediante alloca(). Es mejor eliminar estos archivos de objeto cuando haya terminado de procesar los errores de uso después de la devolución.

Ejemplo: C simple

// example1.cpp
// stack-use-after-return error
volatile char* x;

void foo() {
    char stack_buffer[42];
    x = &stack_buffer[13];
}

int main() {

    foo();
    *x = 42; // Boom!

    return (*x == 42);
}

Para compilar y probar este ejemplo, ejecute estos comandos en un símbolo del sistema para desarrolladores de Visual Studio 2019 versión 16.9 o posterior:

cl example1.cpp /fsanitize=address /fsanitize-address-use-after-return /Zi
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example1.exe

Error resultante: C simple

Captura de pantalla del depurador, donde se muestra el error use-after-return en el ejemplo 1.

Ejemplo: C++ y plantillas

// example2.cpp
// stack-use-after-return error
#include <stdlib.h>

enum ReadOrWrite { Read = 0, Write = 1 };

struct S32 {
    char x[32];
};

template<class T>
T* LeakStack() {
    T t[100];
    static volatile T* x;
    x = &t[0];
    return (T*)x;
}

template<class T>
void StackUseAfterReturn(int Idx, ReadOrWrite w) {
    static T sink;
    T* t = LeakStack<T>();
    if (w)
        t[100 + Idx] = T();
    else
        sink = t[100 + Idx];
}

int main(int argc, char* argv[]) {

    if (argc != 2) return 1;
    int kind = atoi(argv[1]);

    switch (kind) {
    case 1: StackUseAfterReturn<char>(0, Read); break;
    case 2: StackUseAfterReturn<S32>(0, Write); break;
    }
    return 0;
}

Para compilar y probar este ejemplo, ejecute estos comandos en un símbolo del sistema para desarrolladores de Visual Studio 2019 versión 16.9 o posterior:

cl example2.cpp /fsanitize=address /fsanitize-address-use-after-return /Zi /Od
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example2.exe 1

ASAN es una forma de análisis dinámico, lo que significa que solo puede detectar código incorrecto que realmente se ejecuta. Un optimizador puede determinar que el valor de t[100 + Idx] o sink nunca se usa y se ha elide de la asignación. Como resultado, este ejemplo requiere la /Od marca .

Error resultante: C++ y plantillas

Captura de pantalla del depurador, donde se muestra el error use-after-return en el ejemplo 2.

Consulte también

Introducción a AddressSanitizer
Problemas conocidos de AddressSanitizer
Referencia de lenguaje y compilación 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