Sdílet prostřednictvím


Chyba: stack-use-after-return

Chyba sanitizátoru adresy: Použití paměti zásobníku po vrácení

Tato kontrola vyžaduje generování kódu aktivované další možností /fsanitize-address-use-after-returnkompilátoru a nastavením proměnné ASAN_OPTIONS=detect_stack_use_after_return=1prostředí .

Tato kontrola může aplikaci podstatně zpomalit. Představte si souhrn jazyka Clang algoritmu, který podporuje použití po vrácení, a větší náklady na výkon.

Důležité

Pokud vytvoříte soubor objektu pomocí další možnosti /fsanitize-address-use-after-returnkompilátoru, kód vygenerovaný kompilátorem provede rozhodnutí o přidělení rámce zásobníku za běhu. Pokud proměnná ASAN_OPTIONS prostředí není nastavená na detect_stack_use_after_return, je kód stále pomalejší než použití /fsanitize=address samotné. Je pomalejší, protože některé rámečky zásobníku, které přidělují místo pro části rámce pomocí alloca(). Tyto soubory objektů je nejlepší odstranit, když dokončíte zpracování chyb použití po vrácení.

Příklad – Simple 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);
}

Pokud chcete tento příklad sestavit a otestovat, spusťte tyto příkazy v sadě Visual Studio 2019 verze 16.9 nebo novějším vývojářském příkazovém řádku:

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

Výsledná chyba – Simple C

Snímek obrazovky ladicího programu zobrazující chybu po vrácení zásobníku v příkladu 1

Příklad – C++ a šablony

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

Pokud chcete tento příklad sestavit a otestovat, spusťte tyto příkazy v sadě Visual Studio 2019 verze 16.9 nebo novějším vývojářském příkazovém řádku:

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 je forma dynamické analýzy, což znamená, že dokáže rozpoznat pouze chybný kód, který je skutečně proveden. Optimalizátor může určit, že se hodnota t[100 + Idx] přiřazení nepoužívá nebo sink se nikdy nepoužívá a že je přiřazeno. V důsledku toho tento příklad vyžaduje /Od příznak.

Výsledná chyba – C++ a šablony

Snímek obrazovky ladicího programu zobrazující chybu po vrácení zásobníku v příkladu 2

Viz také

Přehled AddressSanitizer
Známé problémy s addressSanitizerem
Referenční dokumentace k sestavení a jazyku AddressSanitizer
Referenční informace k modulu runtime AddressSanitizer
Stínové bajty AddressSanitizer
AddressSanitizer – cloud nebo distribuované testování
Integrace ladicího programu AddressSanitizer
Příklady chyb AddressSanitizer