Erro: stack-use-after-return
Erro na limpeza de endereço: uso da memória da pilha após o retorno
Essa verificação requer a geração de código ativada por uma opção do compilador extra, /fsanitize-address-use-after-return
, e configurando a variável de ambiente ASAN_OPTIONS=detect_stack_use_after_return=1
.
Essa verificação pode reduzir substancialmente o aplicativo. Considere o resumo de Clang do algoritmo que dá suporte ao uso após o retorno e os custos de desempenho maiores.
Importante
Se você criar um arquivo de objeto usando a opção /fsanitize-address-use-after-return
do compilador extra, o código gerado pelo compilador tomará uma decisão de runtime sobre como alocar um registro de ativação. Se a variável de ambiente ASAN_OPTIONS
não estiver definida como detect_stack_use_after_return
, o código ainda será mais lento do que o uso de /fsanitize=address
por si só. É mais lento porque ainda há sobrecarga adicional de alguns registros de ativação que alocam espaço para partes de um quadro usando alloca()
. É melhor excluir esses arquivos-objeto quando você terminar de processar erros de uso após o retorno.
Exemplo – C simples
// 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);
}
Para compilar e testar esse exemplo, execute estes comandos em um prompt de comando do desenvolvedor do Visual Studio 2019 versão 16.9 ou posterior:
cl example1.cpp /fsanitize=address /fsanitize-address-use-after-return /Zi
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example1.exe
Erro resultante – C simples
Exemplo – C++ e modelos
// 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;
}
Para compilar e testar esse exemplo, execute estes comandos em um prompt de comando do desenvolvedor do Visual Studio 2019 versão 16.9 ou posterior:
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
O ASAN é uma forma de análise dinâmica, o que significa que ele só pode detectar código ruim que é realmente executado. Um otimizador pode determinar que o valor de t[100 + Idx]
ou sink
nunca é usado e elidir a atribuição. Como resultado, este exemplo requer o /Od
sinalizador.
Erro resultante – C++ e modelos
Confira também
Visão geral do AddressSanitizer
Problemas conhecidos do AddressSanitizer
Referência de linguagem e build do AddressSanitizer
Referência de runtime do AddressSanitizer
Bytes de sombra de AddressSanitizer
Nuvem do AddressSanitizer ou teste distribuído
Integração do depurador do AddressSanitizer
Exemplos de erro do AddressSanitizer
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de