问题
I'm using this script to test trap:
#!/bin/bash
trap "echo segfault!" SIGSEGV
g++ forever.cpp
./a.out
And forever.cpp
just runs a recursive function:
void forever(){
forever();
}
int main(){
forever();
}
However it gives Segmentation fault: 11
instead of printing segfault
. I'm not sure why.
回答1:
The trap
statement traps signals received by bash
, not its children. The child receives the segfault and will be exiting with an appropriate exit code. You should therefore check the exit code from the child process. As you can see from here, the exit code is 128+signal number. SEGV
is 11 (see man signal
), so you will get an exit code of 139. So simply test $?
against 139, and you have done.
回答2:
The bash trap will catch a segfault in bash itself, not in a process spawned from bash.
In this case you are spawning a process, and that process gets a segfault. You would need to install a signal handler in the C-program forever.cpp to catch that.
回答3:
What you want is to trap when bash catches the SIGCHLD from the process it forked- you can use trap <expression> CHLD
for this
trap 'if [[ $? -eq 139 ]]; then echo "SIGSEGV IN CHILD PROCESS, EXITING"; exit 139; fi' CHLD
Or, if you want a general purpose trap handler, you could do something like:
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
Just keep in mind that process_returned
will fire every time a process you invoke returns- the first logic in the handler function (if you use a function) should probably be [[ $? -eq 0 ]] && return
The reason you may want to use a function is because if you're interested in SIGSEGV
, you're probably also interested in SIGBUS
, SIGILL
and SIGABRT
as these can all occur as a result of memory corruption in a process
SIGSEGV
is caused specifically by either an attempt to access and unmapped virtual memory address in a process or by an attempt to execute on a memory page that is mapped but without executable permissionsSIGBUS
tends to occur either as a result of hardware faults or in the case of some RISC architecture CPUs, as a result of an unaligned read or write. This happens on, for example, SPARC, PA-RISC, MIPS and I'm sure one or two others- though not ARM, x86 or x86_64- at least not with any of the standard store/load instructions. It's possible there are alignment requirements with some of the extensions on modern x86 / x86_64 chips.SIGILL
is raised when the CPU can't decode the instruction at the currently executing address. The most common cause for this is the program counter got corrupted while it was saved on the stack and returned to some address within a multi-byte CPU instructionSIGABRT
is raised internally by glibcmalloc()
when it detects inconsistencies in heap metadata due to heap corruption. Of all of these,SIGABRT
is the one that you can't always assume has anything to do with memory corruption or a fault related to memory, so you may not want to catch that one
来源:https://stackoverflow.com/questions/26485793/trap-fails-to-catch-sigsegv