Fehler: stack-use-after-return

Adress-Sanitizer-Fehler: Verwendung des Stapelspeichers nach der Rückgabe

Diese Überprüfung erfordert die Codegenerierung, die von einer zusätzlichen Compileroption aktiviert wird, /fsanitize-address-use-after-returnund indem Sie die Umgebungsvariable ASAN_OPTIONS=detect_stack_use_after_return=1festlegen.

Diese Überprü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 mithilfe 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 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 von .alloca() Es ist am besten, diese Objektdateien zu löschen, wenn Sie die Verarbeitung von Use-after-Return-Fehlern abgeschlossen haben.

Beispiel – Einfaches C

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

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

int main() {

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

    return 0;
}

Um dieses Beispiel zu erstellen und zu testen, führen Sie diese Befehle in einer Visual Studio 2019, Version 16.9 oder einer späteren 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 of debugger displaying stack-use-after-return error in example 1.

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

Um dieses Beispiel zu erstellen und zu testen, führen Sie diese Befehle in einer Visual Studio 2019, Version 16.9 oder einer späteren Entwickler-Eingabeaufforderung, aus:

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

Resultierender Fehler – C++ und Vorlagen

Screenshot of debugger displaying stack-use-after-return error in example 2.

Siehe auch

Übersicht über AddressSanitizer
Bekannte Probleme von AddressSanitizer
Kompilierungs- und Sprachreferenz für AddressSanitizer
Runtimereferenz für AddressSanitizer
AddressSanitizer-Schattenbytes
AddressSanitizer-Tests in der Cloud oder verteilten Umgebungen
Integration des AddressSanitizer-Debuggers
AddressSanitizer-Fehlerbeispiele