当AddressSanitizer打印错误,但没有回溯,并且程序退出代码仍然是0时,这意味着什么?

问题描述 投票:0回答:1

我在 macOS 上使用 ASAN 通常会成功,但目前我遇到的问题是我的程序有时会终止并打印 ASAN 错误,但其他情况正常。我没有像平常一样得到任何痕迹。

[…] normal program output
=================================================================
==25422==ERROR: AddressSanitizer: heap-use-after-free on address 0x000105a0d918 at pc 0x000102572440 bp 0x00016dd31180 sp 0x00016dd31178
READ of size 8 at 0x000105a0d918 thread T8
[…] program exits with success

我使用

-fsanitize=address -fno-omit-frame-pointer
和调试标志编译代码,并使用
ASAN_OPTIONS=abort_on_error=true;handle_abort=true ./executable
运行它。

由于这种故障很少发生,所以我对如何调试它感到困惑。 当 ASAN 忽略通常会告诉我谁分配了有问题的内存以及在哪里释放了它的跟踪时,它告诉我什么?我可以做什么来获取这些信息?

这是苹果家族的 12.6.5 ARM MacBook

arm64-apple-darwin21.6.0

c++ debugging address-sanitizer
1个回答
0
投票

当 AddressSanitizer 打印错误,但没有回溯,并且程序退出代码仍然为 0 时,这意味着什么?

最常见的原因:一个线程退出和另一个线程遇到错误之间的竞争。

例如,假设您有一个全局

std::unique_ptr<X> a_global;
。当你调用
exit
时,这个全局将会被破坏,并且这个全局用来指向的
X
将被
delete
d。假设这发生在线程中
T0

如果另一个线程 (

T1
) 在调用
exit
后随时访问此全局变量,则该线程可能会报告
heap-use-after-free
(这可能是间歇性的 - 时机必须“恰到好处”)。

ASan 运行时检测到错误并打印第一行诊断信息后,它将尝试生成报告的rest。但它不会停止任何其他线程,并且

T0
将继续运行。

当 ASan 运行时正忙于生成报告时,

T0
可能会进展到
syscall(SYS_exit, 0);
。如果发生这种情况,所有线程,包括
T1
(正在生成 ASan 报告)都会消失得无影无踪。

最终结果:进程正常退出。


调试的一种方法:在 GDB 下运行程序,并使用

catch syscall exit
(在 Linux 上也捕获
exit_group
)。

(由于您使用的是 MacOS,请使用

LLDB
并找到等效命令(可能尚不存在))。

如果您在打印

ERROR: AddressSanitizer: heap-use-after-free...
行后捕获系统调用,请检查其他线程,很可能其中一个线程在 ASan 运行时内试图生成错误。

使用 GDB,您可以

set schedule-locking on
并仅继续生成错误的线程(它将完成生成报告并返回错误)。我也不知道等效的 LLDB 命令。


另一种方法是简单地重试运行程序 1000 次。有时您根本不会收到任何报告,但有时您可能会收到完整的报告。

附注某些编码风格(例如 Google 的)禁止使用非平凡析构函数的全局变量,正是因为此类“退出时”错误通常很难发现和修复。

P.P.S。另一个可能的修复方法是在调用

exit
之前加入所有线程。

© www.soinside.com 2019 - 2024. All rights reserved.