我在一些代码上遇到了一个非常奇怪的问题。我正在尝试调试我在linux集群上编译的C++/Fortran代码。当我运行它时,屏幕上没有任何输出,代码崩溃。我可以用top看到我的应用程序启动并分配内存,直到它耗尽(128GB(并被内核OOM杀死。我尝试使用调试器,并在main上设置了一个断点,但仍然得到了相同的行为。因此,我假设错误发生在进入main之前,所以我假设它与静态/全局数据初始化或类初始化有关。我已经尝试了几个编译器优化选项,在使用-O0时取得了一些成功,但对于任何其他的优化级别,它们都会崩溃。具有不同优化选项的不同行为向我表明,代码中也存在问题,例如未定义的行为,但我也不知道如何处理。
我知道这个问题不是一个理想的问题,我没有一个最低限度的工作例子。尽管代码在公共存储库中可用,但编译起来很困难,并且您需要不公开的输入文件来运行它。
到目前为止,我已经做到了这一点。我不知道如何处理这个bug,所以任何想法或建议都非常受欢迎,我会尽力回答任何问题。
谢谢!
第一步是用strace
验证它不是晚期execve
故障。这种故障表现为execve
之后的立即信号,而在execve
之后没有针对相同进程的任何系统调用。
发生这种情况是因为execve
不是原子:如果它已经开始用新的进程映像替换当前进程映像,但之后失败,它不会返回错误(因为它可以返回的原始进程映像已经不见了(,而是用信号终止进程。信号随内核版本而变化(如果我没记错的话,可以是SIGKILL
或SIGSEGV
(。如果发生这种情况,就意味着你的程序可能有一些非常大的全局变量。它们应该作为带有readelf -lW
的大LOAD
段和带有readelf -SW
的大数据段可见。
如果不是后期execve
失败,希望程序初始化运行的时间足够长,以便您可以在调试器和^C
下运行它,或者将其发送到SIGINT
,并以这种方式进行回溯,以查看它在做什么。如果这不起作用,您可以在__libc_start_main
上设置一个断点,并逐步通过它,直到它通过init
函数指针调用主程序ELF构造函数。对于共享对象中的ELF构造函数,您需要在_dl_init
上设置断点(对于未来的glibc版本,可能从glibc 2.33或2.34开始;它们将不再从__libc_start_main
运行主程序ELF构造函数(。