错误:stack-use-after-return
地址擦除器错误:在返回后使用堆栈内存
此检查需要通过额外的编译器选项 /fsanitize-address-use-after-return
并通过设置环境变量 ASAN_OPTIONS=detect_stack_use_after_return=1
激活的代码生成。
此检查会大幅降低应用程序速度。 请考虑支持返回后使用的算法的 Clang 摘要,以及更大的性能成本。
重要
如果使用额外的编译器选项 /fsanitize-address-use-after-return
创建对象文件,编译器生成的代码会关于如何分配堆栈帧做出运行时决策。 如果环境变量 ASAN_OPTIONS
未设置为 detect_stack_use_after_return
,则代码的速度仍然比单独使用 /fsanitize=address
慢。 速度较慢是因为某些堆栈帧仍会产生额外的开销,这些帧通过使用 alloca()
为帧的某些部分分配空间。 在处理完 use-after-return 错误时,最好删除这些对象文件。
示例 - 简单 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);
}
若要生成并测试此示例,请在 Visual Studio 2019 版本 16.9 或更高版本的开发人员命令提示符中运行以下命令:
cl example1.cpp /fsanitize=address /fsanitize-address-use-after-return /Zi
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example1.exe
生成的错误 - 简单 C
示例 - C++ 和模板
// 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;
}
若要生成并测试此示例,请在 Visual Studio 2019 版本 16.9 或更高版本的开发人员命令提示符中运行以下命令:
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 是动态分析的一种形式,这意味着它只能检测实际执行的错误代码。 优化器可以确定从未使用过 t[100 + Idx]
或 sink
的值,并省略赋值。 因此,此示例需要 /Od
标志。
生成的错误 - C++ 和模板
另请参阅
AddressSanitizer 概述
AddressSanitizer 已知问题
AddressSanitizer 生成和语言参考
AddressSanitizer 运行时参考
AddressSanitizer 阴影字节
AddressSanitizer 云或分布式测试
AddressSanitizer 调试程序集成
AddressSanitizer 错误示例