Freigeben über


Fehler: stack-use-after-return

Adressbereinigungsfehler: Verwendung des Stapelspeichers nach der Rückgabe

Für diese Überprüfung ist die Codegenerierung erforderlich, die von einer zusätzlichen Compileroption aktiviert wird, /fsanitize-address-use-after-returnund durch Festlegen der Umgebungsvariable ASAN_OPTIONS=detect_stack_use_after_return=1.

Diese Prüfung kann Ihre Anwendung erheblich verlangsamen. Betrachten Sie die Clang-Zusammenfassung des Algorithmus, der die Verwendung nach der Rückgabe unterstützt, und die größeren Leistungskosten.

Wichtig

Wenn Sie eine Objektdatei mit der zusätzlichen Compileroption /fsanitize-address-use-after-returnerstellen, trifft der vom Compiler generierte Code eine Laufzeitentscheidung darüber, wie ein Stapelframe zugewiesen werden soll. Wenn die Umgebungsvariable ASAN_OPTIONS nicht auf festgelegt detect_stack_use_after_returnist, ist der Code immer noch langsamer als die Verwendung /fsanitize=address selbst. Es ist langsamer, da es noch zusätzlichen Aufwand von einigen Stapelframes gibt, die Platz für Teile eines Frames mithilfe alloca()von . Es ist am besten, diese Objektdateien zu löschen, wenn Sie die Verarbeitung von Verwendungsfehlern nach dem Zurückgeben abgeschlossen haben.

Beispiel – Einfaches C

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

Führen Sie zum Erstellen und Testen dieses Beispiels die folgenden Befehle in einer Visual Studio 2019,16.9- oder höher-Entwickler-Eingabeaufforderung aus:

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

Resultierender Fehler - Einfaches C

Screenshot des Debuggers, der stack-use-after-return-Fehler in Beispiel 1 anzeigt.

Beispiel : C++ und Vorlagen

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

Führen Sie zum Erstellen und Testen dieses Beispiels die folgenden Befehle in einer Visual Studio 2019,16.9- oder höher-Entwickler-Eingabeaufforderung aus:

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 ist eine Form der dynamischen Analyse, was bedeutet, dass nur fehlerhaften Code erkannt werden kann, der tatsächlich ausgeführt wird. Ein Optimierer kann bestimmen, dass der Wert der t[100 + Idx] Zuordnung verwendet oder sink nie verwendet wird. Daher erfordert dieses Beispiel die /Od Kennzeichnung.

Resultierender Fehler – C++ und Vorlagen

Screenshot des Debuggers, der stack-use-after-return-Fehler in Beispiel 2 anzeigt.

Siehe auch

AddressSanitizer -Übersicht
Beheben bekannter Probleme mit demSanitizer
AddressSanitizer Build- und Sprachreferenz
AddressSanitizer-Laufzeitreferenz
AddressSanitizer-Schattenbytes
AddressSanitizer-Cloud oder verteilte Tests
AddressSanitizer Debugger-Integration
Beispiele für AddressSanitizer-Fehler