SIGBUS和SIGSEGV

一、导致SIGSEGV 
    1.试图对只读映射区域进行写操作 。

    2.访问的内存已经被释放,也就是已经不存在或者越界。

3.官方说法是:
SIGSEGV --- Segment Fault. The possible cases of your encountering this error are: 

(1)buffer overflow --- usually caused by a pointer reference out of range.
(2)stack overflow --- please keep in mind that the default stack size is 8192K.
(3)illegal file access --- file operations are forbidden on our judge system.

 

二、导致SIGBUS信号: 
    1.硬件故障,不用说,程序员最常碰上的肯定不是这种情形。 

    2.Linux平台上执行malloc(),如果没有足够的RAM,Linux不是让malloc()失败返回, 而是向当前进程分发SIGBUS信号。 

       注: 对该点执怀疑态度,有机会可自行测试确认当前系统反应。 

    3.某些架构上访问数据时有对齐的要求,比如只能从4字节边界上读取一个4字节的 数据类型。IA-32架构没有硬性要求对齐,尽管未对齐的访问降低执行效率。另外一些架构,比如SPARC、m68k,要求对齐访问,否则向当前进程分发SIGBUS信号。 

    4.试图访问一块无文件内容对应的内存区域,比如超过文件尾的内存区域,或者以前有文件内容对应,现在为另一进程截断过的内存区域。


三、SIGBUS与SIGSEGV信号一样,可以正常捕获。SIGBUS的缺省行为是终止当前进程并产生core dump。 


四、SIGBUS与SIGSEGV信号的一般区别如下: 

    1.SIGBUS(Bus error)意味着指针所对应的地址是有效地址,但总线不能正常使用该指针。通常是未对齐的数据访问所致。 

    2.SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。 


五、弄清楚错误以后,就要查找产生错误的根源,一般我用以下两种方法: 1.gcc -g 编译       ulimit -c 20000       之后运行程序,等core dump       最后gdb -c core <exec file>  来查调用栈 2.使用strace execfile,运行程序,出错时会显示那个系统调用错


### Linux 中 SIGSEGV 信号的含义及处理 #### SIGSEGV 的定义与触发原因 SIGSEGV 是 Linux 系统中的一个信号,表示发生了段错误(Segmentation Fault),通常由于程序尝试访问未分配给它的内存区域而引发。这种错误可能由多种情况引起,包括但不限于以下几种: - 访问空指针 `nullptr` 或者未初始化的指针[^1]。 - 越界访问数组或其他数据结构[^2]。 - 尝试修改只读内存区域的内容,例如字符串常量或代码段[^3]。 当这些操作被执行时,操作系统检测到非法内存访问并发送 SIGSEGV 信号通知应用程序存在潜在问题。 #### 处理 SIGSEGV 方法概述 为了应对 SIGSEGV 错误,默认情况下该信号会导致程序终止运行,并生成 core dump 文件用于调试分析。然而,在某些特殊场景下可以自定义其行为通过设置信号处理器来改变这一过程。下面详细介绍两种常见方式——利用标准库函数 `signal()` 更灵活强大的 POSIX 接口 `sigaction()` 来注册信号处理器。 ##### 使用 signal 函数捕获 SIGSEGV 最简单的办法就是采用 C 标准库里的 `signal()` 函数指定当接收到特定类型的信号时应该调用哪个回调函数作为响应措施。如下所示的例子展示了如何创建一个基本的信号处理器以拦截 SIGSEGV 并打印消息然后退出应用: ```c #include <signal.h> #include <stdio.h> #include <stdlib.h> static void signal_handler(int sig) { printf("Caught a segmentation fault (SIGSEGV)\n"); exit(EXIT_FAILURE); } int main() { if (signal(SIGSEGV, signal_handler) == SIG_ERR){ fprintf(stderr,"Error setting signal handler\n"); return EXIT_FAILURE; } int* p = NULL; // Deliberate null pointer dereference. *p = 1; return EXIT_SUCCESS; } ``` 尽管这种方法易于理解实施,但它有一些局限性不确定性因素需要注意,比如不能保证每次都能成功安装新的信号处理器实例等问题。 ##### 利用 sigaction 设置复杂信号动作 对于更加精细控制的需求来说,则推荐使用功能更为全面丰富的 `sigaction()` API 替代原始版本。它可以提供额外选项参数允许开发者进一步定制化自己的解决方案策略。例如可以通过标志位组合形式启用自动重置机制或者防止递归进入同一个信号上下文中等情况的发生。 这里给出一段示范代码片段说明怎样运用此技术构建健壮可靠的异常恢复框架: ```c #define _GNU_SOURCE #include <execinfo.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <ucontext.h> void segfault_sigaction(int signal, siginfo_t *si, void *arg) { void *trace[16]; char **messages = (char **)NULL; int i, trace_size = 0; printf("Signal %d (%s), address is %p from %p\n", si->si_signo, strsignal(si->si_signo), si->si_addr, __builtin_return_address(0)); trace_size = backtrace(trace, 16); messages = backtrace_symbols(trace, trace_size); for(i=0;i<trace_size;++i) printf("%s\n", messages[i]); free(messages); abort(); } struct sigaction sa; sa.sa_flags = SA_SIGINFO|SA_ONSTACK; sa.sa_sigaction = segfault_sigaction; if(sigemptyset(&sa.sa_mask)==-1 || sigaddset(&sa.sa_mask,SIGBUS)==-1 || sigaction(SIGSEGV,&sa,NULL)!=0 ){ perror("Failed to set up SIGSEGV handler."); exit(EXIT_FAILURE); } // Continue normal execution... ``` 上述示例不仅记录了堆栈跟踪信息以便后续排查定位具体位置外还启用了备用栈支持以防万一主线程栈空间耗尽造成二次崩溃风险。 #### 注意事项 虽然理论上能够捕捉住大部分常规情形下的分页违例事件但是实际开发过程中仍需谨慎对待以下几个方面: - 如果在信号处理器内部再次触碰同样的条件则可能导致无限循环直至资源耗竭最终还是失败告终; - 不同平台架构之间可能存在细微差异影响兼容性表现; ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值