分段故障本身就悬而未决
Segmentation fault itself is hanging
我今天的服务器出现了一些问题,现在我已经将其归结为无法摆脱出现segfault的进程。
在进程出现seg故障后,进程只是保持挂起状态,而不是被终止。
应该的测试会导致错误Segmentation fault (core dumped)
。
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *buf;
buf = malloc(1<<31);
fgets(buf, 1024, stdin);
printf("%sn", buf);
return 1;
}
使用gcc segfault.c -o segfault && chmod +x segfault
编译和设置权限。
在有问题的服务器上运行此操作(并按enter键1次)会导致它挂起。我还在另一台具有相同内核版本(以及大多数相同包)的服务器上运行了这个程序,它出现了seg错误,然后退出。
以下是在两台服务器上运行strace ./segfault
之后的最后几行。
错误的服务器
"n", 1024) = 1
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} ---
# It hangs here....
工作服务器
"n", 1024) = 1
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
root@server { ~ }# echo $?
139
当进程挂起时(在出现分段故障之后),它就是这样的。
无法^c它
root@server { ~ }# ./segfault
^C^C^C
从ps aux进入
root 22944 0.0 0.0 69700 444 pts/18 S+ 15:39 0:00 ./segfault
cat/proc/22944/stack
[<ffffffff81223ca8>] do_coredump+0x978/0xb10
[<ffffffff810850c7>] get_signal_to_deliver+0x1c7/0x6d0
[<ffffffff81013407>] do_signal+0x57/0x6c0
[<ffffffff81013ad9>] do_notify_resume+0x69/0xb0
[<ffffffff8160bbfc>] retint_signal+0x48/0x8c
[<ffffffffffffffff>] 0xffffffffffffffff
另一件有趣的事情是,我无法将strace
附加到挂起的segfault进程。这样做实际上会让它被杀死。
root@server { ~ }# strace -p 1234
Process 1234 attached
+++ killed by SIGSEGV (core dumped) +++
ulimit -c 0
是sat,ulimit -c
、ulimit -H -c
和ulimit -S -c
都显示值0
- 内核版本:
3.10.0-229.14.1.el7.x86_64
- Distro版本:
Red Hat Enterprise Linux Server release 7.1 (Maipo)
- 在vmware中运行
服务器在其他所有方面都正常工作。
更新关闭abrt(systemctl stop abrtd.service
)解决了堆芯转储后进程已挂起的问题,并创建了新的堆芯转储进程。再次启动abrt并没有使问题再次出现。
更新2016-01-26我们遇到了一个看起来相似但不完全相同的问题。用于测试的初始代码:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char *buf;
buf = malloc(1<<31);
fgets(buf, 1024, stdin);
printf("%sn", buf);
return 1;
}
正在上吊。cat /proc/<pid>/maps
的输出为
00400000-00401000 r-xp 00000000 fd:00 13143328 /root/segfault
00600000-00601000 r--p 00000000 fd:00 13143328 /root/segfault
00601000-00602000 rw-p 00001000 fd:00 13143328 /root/segfault
7f6c08000000-7f6c08021000 rw-p 00000000 00:00 0
7f6c08021000-7f6c0c000000 ---p 00000000 00:00 0
7f6c0fd5b000-7f6c0ff11000 r-xp 00000000 fd:00 14284 /usr/lib64/libc-2.17.so
7f6c0ff11000-7f6c10111000 ---p 001b6000 fd:00 14284 /usr/lib64/libc-2.17.so
7f6c10111000-7f6c10115000 r--p 001b6000 fd:00 14284 /usr/lib64/libc-2.17.so
7f6c10115000-7f6c10117000 rw-p 001ba000 fd:00 14284 /usr/lib64/libc-2.17.so
7f6c10117000-7f6c1011c000 rw-p 00000000 00:00 0
7f6c1011c000-7f6c1013d000 r-xp 00000000 fd:00 14274 /usr/lib64/ld-2.17.so
7f6c10330000-7f6c10333000 rw-p 00000000 00:00 0
7f6c1033b000-7f6c1033d000 rw-p 00000000 00:00 0
7f6c1033d000-7f6c1033e000 r--p 00021000 fd:00 14274 /usr/lib64/ld-2.17.so
7f6c1033e000-7f6c1033f000 rw-p 00022000 fd:00 14274 /usr/lib64/ld-2.17.so
7f6c1033f000-7f6c10340000 rw-p 00000000 00:00 0
7ffc13b5b000-7ffc13b7c000 rw-p 00000000 00:00 0 [stack]
7ffc13bad000-7ffc13baf000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
然而,触发segfault的较小c代码(int main(void){*(volatile char*)0=0;}
)确实导致了segfault,并且没有挂起。。。
警告-此答案包含基于手头不完整信息的许多假设。希望它仍然有用!
为什么segfault似乎挂起了
如堆栈跟踪所示,内核正忙于创建崩溃进程的核心转储。
但为什么要花这么长时间?一种可能的解释是,您用于创建segfault的方法导致进程具有巨大的虚拟地址空间。
如M.M.的评论中所指出的,表达式1<lt;31是C标准未定义的,所以很难说传递给malloc的实际值是多少,但根据随后的行为,我假设它是一个很大的数字。
请注意,malloc要想成功,您的系统中实际上没有必要有这么多RAM——内核会扩展进程的虚拟大小,但只有当您的程序真正访问这个RAM时,才会分配实际的RAM。
我相信对malloc的调用成功了,或者至少返回了,因为您在按enter键后声明它是segfault,所以在调用fgets之后也是如此。
在任何情况下,segfault都会导致内核执行内核转储。如果进程的虚拟大小很大,则可能需要很长时间,特别是如果内核决定转储所有页面,即使是进程从未接触过的页面。我不确定它是否会这样做,但如果真的这样做了,如果系统中没有足够的RAM,它将不得不开始在内存中交换页面,以便将它们转储到核心转储。这将产生高IO负载,这可能导致进程看起来没有响应(并且整个系统性能将降低)。
您可以通过查找abrtd转储目录(可能是/var/tmp/abrt
,或检查/etc/abrt/abrt.conf
)来验证其中的一些内容,在该目录中可以找到已创建的核心转储(或部分核心转储)。
如果你能够再现行为,那么你可以检查:
/proc/[pid]/maps
查看进程的地址空间映射,看看它是否真的很大- 使用类似vmstat的工具来查看系统是否正在交换、正在进行的I/O量以及经历了多少IO等待状态
- 如果您运行了
sar
,那么即使在重新启动abrtd之前,您也可以看到类似的信息
为什么要创建一个核心转储,尽管ulimit-c是0
根据这个错误报告,无论ulimit设置如何,abrtd都会触发核心转储的收集。
为什么当arbtd再次启动时,这种情况没有再次发生
对此有几种可能的解释。首先,这将取决于系统中可用RAM的数量。如果有足够的空闲RAM并且系统没有被强制交换,那么大型进程的单核转储可能不会花那么长时间,也不会被认为是挂起的。
如果在你最初的实验中,你有几个过程处于这种状态,那么症状会比只让一个过程行为不端的情况严重得多。
另一种可能性是abrtd的配置已经更改,但服务尚未重新加载,因此当您重新启动它时,它开始使用新的配置,可能会改变它的行为。
也有可能是百胜更新更新了abrtd,但没有重新启动它,所以当您重新启动它时,新版本正在运行。
- 分段故障(堆芯转储)矢量
- C++中的动态铸造故障
- 数组的指针从不分段故障
- vscode g++链路故障:体系结构x86_64的未定义符号
- 访问被拒绝后,c++中的故障保护代码
- Windows 10-使用gtkmm-3.0库和g++[包括再现]的分段故障
- 调试 CUDA MMU 故障
- Geeksforgeeks C 程序故障排除:IEE 754 表示法为十进制
- Arch Linux.AUR 包 mysql 不能用 makepkg 构建.错误:构建 () 中出现故障
- 正在处理故障(堆芯转储)
- 在 Boost::fiber 中引发的BOOST_ASSERT故障 Visual Studio "Debug" 构建
- 如何进行故障排除:未定义对"非虚拟 thunk to ..."的引用
- C++函数过载会导致 SEG 故障
- 分段故障 运行C++代码时出现 SIGSEGV
- 当新的故障时,是否有必要留出一些紧急内存?
- Python & C-C++ 扩展模块案例段故障
- 带升压的 SEG 故障::make_shared / 特征3 内存.h.
- 在 c++ 中,发生故障后是否需要 stream.clear()?
- 分段故障背包问题
- 分段故障本身就悬而未决