Condividi tramite


Errore: stack-use-after-return

Errore di purificazione dell'indirizzo: uso della memoria dello stack dopo la restituzione

Questo controllo richiede la generazione del codice attivata da un'opzione del compilatore aggiuntiva, /fsanitize-address-use-after-returne impostando la variabile ASAN_OPTIONS=detect_stack_use_after_return=1di ambiente .

Questo controllo può rallentare notevolmente l'applicazione. Si consideri il riepilogo Clang dell'algoritmo che supporta l'uso dopo la restituzione e i costi di prestazioni maggiori.

Importante

Se si crea un file oggetto usando l'opzione /fsanitize-address-use-after-returndel compilatore aggiuntiva , il codice generato dal compilatore prende una decisione di runtime su come allocare uno stack frame. Se la variabile ASAN_OPTIONS di ambiente non è impostata su detect_stack_use_after_return, il codice è ancora più lento rispetto all'uso /fsanitize=address da solo. È più lento perché c'è ancora un sovraccarico aggiuntivo da alcuni stack frame che allocano spazio per parti di un frame usando alloca(). È consigliabile eliminare questi file oggetto al termine dell'elaborazione degli errori di utilizzo dopo la restituzione.

Esempio - C semplice

// 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);
}

Per compilare e testare questo esempio, eseguire questi comandi in un prompt dei comandi per sviluppatori di Visual Studio 2019 versione 16.9 o successiva:

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

Errore risultante - C semplice

Screenshot del debugger che mostra l'errore stack-use-after-return nell'esempio 1.

Esempio - C++ e modelli

// 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;
}

Per compilare e testare questo esempio, eseguire questi comandi in un prompt dei comandi per sviluppatori di Visual Studio 2019 versione 16.9 o successiva:

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 è una forma di analisi dinamica, il che significa che può rilevare solo codice non valido effettivamente eseguito. Un ottimizzatore può determinare che il valore di t[100 + Idx] o sink non viene mai usato ed elidere l'assegnazione. Di conseguenza, questo esempio richiede il /Od flag .

Errore risultante - C++ e modelli

Screenshot del debugger che mostra l'errore stack-use-after-return nell'esempio 2.

Vedi anche

Panoramica di AddressSanitizer
Problemi noti di AddressSanitizer
Riferimento alla compilazione e al linguaggio AddressSanitizer
Informazioni di riferimento sul runtime AddressSanitizer
Byte ombreggiatura AddressSanitizer
AddressSanitizer cloud o test distribuiti
Integrazione del debugger AddressSanitizer
Esempi di errore addressSanitizer