我正在使用此脚本来测试陷阱:
#!/bin/bash
trap "echo segfault!" SIGSEGV
g++ forever.cpp
./a.out
forever.cpp
只运行一个递归函数:
void forever(){
forever();
}
int main(){
forever();
}
然而,它会提供Segmentation fault: 11
而不是打印segfault
。我不确定为什么。
答案 0 :(得分:4)
bash陷阱将在bash中捕获段错误,而不是在bash中生成的进程中。
在这种情况下,您将生成一个进程,该进程会出现段错误。您需要在C程序forever.cpp中安装一个信号处理程序来捕获它。
答案 1 :(得分:3)
trap
语句捕获bash
收到的信号,而不是其子信息。孩子收到段错误,并将以适当的退出代码退出。因此,您应该检查子进程的退出代码。从here可以看出,退出代码是128 +信号编号。 SEGV
为11(请参阅man signal
),因此您将获得退出代码139.因此,只需针对139测试$?
即可。
答案 2 :(得分:0)
您想要的是当 bash 从它分叉的进程中捕获 SIGCHLD 时进行捕获 - 您可以为此使用 trap <expression> CHLD
trap 'if [[ $? -eq 139 ]]; then echo "SIGSEGV IN CHILD PROCESS, EXITING"; exit 139; fi' CHLD
或者,如果您想要一个通用的陷阱处理程序,您可以执行以下操作:
process_returned() {
local exit_code=$? # Save the exit code for the rest of the function
[[ $exit_code -eq 0 ]] && return
if [[ $? -eq 139 ]]; then
echo "SIGSEGV IN CHILD PROCESS, EXITING";
exit 139
fi
echo "Something other than SIGSEGV was returned ($exit_code)";
... trap handling logic ...
}
trap process_returned CHLD
请记住,process_returned
将在每次您调用的进程返回时触发 - 处理程序函数中的第一个逻辑(如果您使用函数)可能应该是 {{1 }}
您可能想要使用函数的原因是,如果您对 [[ $? -eq 0 ]] && return
感兴趣,那么您可能也对 SIGSEGV
、{{1} } 和 SIGBUS
因为这些都可能由于进程中的内存损坏而发生
SIGILL
是由尝试访问和未映射的进程中的虚拟内存地址或引起的,原因是尝试执行已映射但没有可执行权限的内存页
SIGABRT
往往由于硬件故障或某些 RISC 架构 CPU 的未对齐读取或写入而发生。例如,这种情况发生在 SPARC、PA-RISC、MIPS 和我确定其他一两个上——尽管不是 ARM、x86 或 x86_64——至少在任何标准存储/加载指令中都没有。现代 x86 / x86_64 芯片上的某些扩展可能存在对齐要求。
SIGSEGV
当 CPU 无法解码当前执行地址处的指令时引发。最常见的原因是程序计数器在保存在堆栈中并返回到多字节 CPU 指令中的某个地址时损坏了
SIGBUS
在 glibc SIGILL
检测到时在内部引发
由于堆损坏导致堆元数据不一致。所有的
这些,SIGABRT
是你不能总是假设有任何东西的那个
与内存损坏或与内存相关的故障有关,因此您可能
不想抓住那个