Błąd: stack-use-after-return
Błąd narzędzia do oczyszczania adresu: użycie pamięci stosu po powrocie
Ta kontrola wymaga generowania kodu aktywowanego przez dodatkową opcję kompilatora, /fsanitize-address-use-after-return
i przez ustawienie zmiennej środowiskowej ASAN_OPTIONS=detect_stack_use_after_return=1
.
Ta kontrola może znacznie spowolnić działanie aplikacji. Rozważ podsumowanie języka Clang algorytmu, który obsługuje użycie po powrocie, oraz większe koszty wydajności.
Ważne
Jeśli tworzysz plik obiektu przy użyciu dodatkowej opcji /fsanitize-address-use-after-return
kompilatora , kod wygenerowany przez kompilator podejmuje decyzję w czasie wykonywania o tym, jak przydzielić ramkę stosu. Jeśli zmienna środowiskowa ASAN_OPTIONS
nie jest ustawiona na detect_stack_use_after_return
wartość , kod jest nadal wolniejszy niż sam w sobie /fsanitize=address
. Jest wolniejsza, ponieważ nadal istnieje dodatkowe obciążenie z niektórych ramek stosu, które przydzielają miejsce dla części ramki przy użyciu polecenia alloca()
. Najlepiej usunąć te pliki obiektów po zakończeniu przetwarzania błędów użycia po powrocie.
Przykład — prosty 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);
}
Aby skompilować i przetestować ten przykład, uruchom następujące polecenia w wierszu polecenia programu Visual Studio 2019 w wersji 16.9 lub nowszej:
cl example1.cpp /fsanitize=address /fsanitize-address-use-after-return /Zi
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example1.exe
Błąd wynikowy — prosty C
Przykład — C++ i szablony
// 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;
}
Aby skompilować i przetestować ten przykład, uruchom następujące polecenia w wierszu polecenia programu Visual Studio 2019 w wersji 16.9 lub nowszej:
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 jest formą analizy dynamicznej, co oznacza, że może wykrywać tylko zły kod, który jest rzeczywiście wykonywany. Optymalizator może określić, że wartość t[100 + Idx]
lub sink
nigdy nie jest używana i wychwytuje przypisanie. W związku z tym ten przykład wymaga flagi /Od
.
Błąd wynikowy — C++ i szablony
Zobacz też
AddressSanitizer — omówienie
Rozwiązywanie znanych problemów z programemSanitizer
Dokumentacja języka i kompilacji narzędzia AddressSanitizer
AddressSanitizer runtime reference (Dokumentacja środowiska uruchomieniowego AddressSanitizer)
Bajty w tle addressSanitizer
AddressSanitizer — chmura lub testowanie rozproszone
Integracja debugera AddressSanitizer
Przykłady błędów addressSanitizer