trap fails to catch SIGSEGV

旧时模样 提交于 2021-01-28 12:11:01

问题


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 permissions

  • SIGBUS 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 instruction

  • SIGABRT is raised internally by glibc malloc() 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!