【发布时间】:2021-09-24 13:39:40
【问题描述】:
我正在尝试诊断一个带有 Heisenbug 的程序。使用 gdb 和 Ghidra 的组合,我已经能够追踪到特定部分的崩溃。这是我的代码的要点:
FD_ZERO(&readfds);
FD_SET(sock1, &readfds);
max_fd = sock1;
if ( some_condition ) {
FD_SET(sock2, &readfds);
if ( sock2 > max_fd ) {
max_fd = sock2;
}
}
if ( select(max_fd+1, &readfds, NULL, NULL, &timer) == -1 ) {
goto error;
}
if ( FD_ISSET(sock1, &readfds) ) {
...
}
if ( FD_ISSET(sock2, &readfds) ) {
...
}
我已经能够将崩溃范围缩小到最后一个 FD_ISSET 宏的扩展。具体来说,它调用 __fdelt_chk 最终导致我的 shell 报告
*** buffer overflow detected ***: terminated
但是,如果我将代码更改为
bool using_sock2 = false;
...
if ( some_condition ) {
using_sock2 = true;
...
}
...
if ( using_sock2 && FD_ISSET(sock2, &readfds) ) {
...
}
问题消失了。
显然,我调用了某种未定义的行为。但是,我查看了手册页,没有看到任何似乎相关的警告/要求。究竟是什么导致了这次崩溃?
编辑:在 gdb 或 valgrind 下运行程序会使错误消失。我无法找到崩溃源的唯一方法是正常运行程序,然后从另一个终端附加 gdb。
【问题讨论】:
-
请提供 MRE (minimal reproducible example) 以证明不当行为。
-
另外,尝试通过 valgrind 运行您的代码。如果你对内存管理不善,它会告诉你在哪里。
-
要么 sock2 无效,要么 readfds 无效。 sock2 的检查正在关闭。或者 readfds 超出范围或(如果在堆上分配)被释放。仅用于测试 - 将 sock2 和 readfds 声明为静态,看看会发生什么。
-
啊,@moi 是对的。我设法用 strace 附加,发现
close被调用sock2,然后sock2被设置为-1。由于“由错字引起”而投票结束(足够接近)。
标签: c select undefined-behavior