Delen via


Fout: stack-use-after-return

AddressSanitizer-fout: Gebruik van stackgeheugen na retournering

Opmerkingen

Voor deze controle is het genereren van code vereist die wordt geactiveerd door een extra compileroptie /fsanitize-address-use-after-return, en door de omgevingsvariabele ASAN_OPTIONS=detect_stack_use_after_return=1in te stellen.

Deze controle kan uw toepassing aanzienlijk vertragen. Bekijk de Clang-samenvatting van het algoritme dat ondersteuning biedt voor gebruik na het retourneren en de grotere prestatiekosten.

Belangrijk

Als u een objectbestand maakt met behulp van de extra compileroptie /fsanitize-address-use-after-return, maakt de code die door de compiler wordt gegenereerd een runtimebeslissing over het toewijzen van een stackframe. Als de omgevingsvariabele ASAN_OPTIONS niet is ingesteld detect_stack_use_after_returnop, is de code nog steeds trager dan door zichzelf te gebruiken /fsanitize=address . Het is langzamer omdat er nog steeds extra overhead is van sommige stackframes die ruimte toewijzen voor delen van een frame met behulp van alloca(). U kunt deze objectbestanden het beste verwijderen wanneer u klaar bent met het verwerken van gebruiks-na-retourfouten.

Voorbeeld - Eenvoudig 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);
}

Als u dit voorbeeld wilt bouwen en testen, voert u deze opdrachten uit in een Opdrachtprompt voor ontwikkelaars van Visual Studio 2019 versie 16.9 of hoger:

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

Resulterende fout - Eenvoudige C

Schermopname van foutopsporingsprogramma met stack-use-after-return-fout in voorbeeld 1.

Voorbeeld : C++ en sjablonen

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

Als u dit voorbeeld wilt bouwen en testen, voert u deze opdrachten uit in een Opdrachtprompt voor ontwikkelaars van Visual Studio 2019 versie 16.9 of hoger:

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 is een vorm van dynamische analyse, wat betekent dat alleen slechte code kan worden gedetecteerd die daadwerkelijk wordt uitgevoerd. Een optimizer kan bepalen of de waarde van t[100 + Idx] of sink nooit wordt gebruikt en de toewijzing kan worden verwijderd. Als gevolg hiervan vereist dit voorbeeld de /Od vlag.

Resulterende fout - C++ en sjablonen

Schermopname van foutopsporingsprogramma met stack-use-after-return-fout in voorbeeld 2.

Zie ook

Overzicht van AddressSanitizer
AddressSanitizer bekende problemen
AddressSanitizer-build- en taalreferenties
naslaginformatie over AddressSanitizer-runtime
addressSanitizer schaduwbytes
AddressSanitizer-cloud of gedistribueerde tests
integratie van AddressSanitizer-foutopsporingsprogramma's
voorbeelden van AddressSanitizer-fouten