Liunux 编程遇到的SIGBUS信号
来源:互联网 发布:统赢慢走丝编程软件 编辑:程序博客网 时间:2024/06/05 17:03
linux下编程我们最常遇到的一个信号应该是段错误信号SIGSEGV,一般表示你访问了一个不合法地址。但有时会遇到SIGBUS信号,这个信号在我的印象中是硬件故障的意思,平时没太关注,但最近一个进程老打印收到这个信号,想来这信号里面应该还有其他蹊跷。
什么时候会产生这个信号?
UNIX高级编程上讲:指示一个实现定义的硬件故障。当出现某种类型的内存故障时,实现常常产生此种信号。
就实际编程中,遇到这个信号往往是如下的情况:
1. 未对齐的地址访问
2. mmap时,访问映射区已经不存在的部分(如用文件长度映射了一个文件,但在引用该映射区之前,另一个进程已将该文件截断)
编程测试
未对齐的内存访问
x86默认是可以访问未对齐的地址的,所以测试需要加额外的汇编指令。
#include <stdlib.h>int main(int argc, char **argv) { int *iptr; char *cptr;#if defined(__GNUC__)# if defined(__i386__) /* Enable Alignment Checking on x86 */ __asm__("pushf\norl $0x40000,(%esp)\npopf");# elif defined(__x86_64__) /* Enable Alignment Checking on x86_64 */ __asm__("pushf\norl $0x40000,(%rsp)\npopf");# endif#endif /* malloc() always provides aligned memory */ cptr = malloc(sizeof(int) + 1); /* Increment the pointer by one, making it misaligned */ iptr = (int *) ++cptr; /* Dereference it as an int pointer, causing an unaligned access */ *iptr = 42; return 0;}
执行结果,在*iptr = 42
这行出错,收到SIGBUS信号
root@ubuntu:AC_PRODUCT_SVN5449# gcc bus_test.c -groot@ubuntu:AC_PRODUCT_SVN5449# gdb a.out GNU gdb (GDB) 7.5.91.20130417-cvs-ubuntuCopyright (C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "i686-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/work_sdc1/tenda3/AC6_ITB01/AC_PRODUCT_SVN5449/a.out...done.(gdb) rStarting program: /home/work_sdc1/tenda3/AC6_ITB01/AC_PRODUCT_SVN5449/a.out Program received signal SIGBUS, Bus error.0x0804844f in main (argc=1, argv=0xbffff5e4) at bus_test.c:2525 *iptr = 42;(gdb)
mmap时访问截短的文件
测试C程序,映射一个文件,然后在getchar处等待,这时用外部程序修改文件内容,使文件长度变短,然后这边终端输入字符唤醒程序,观察是否收到SIGBUS信号。
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <signal.h>#include <sys/mman.h>#include <unistd.h>void handle_sigbus(int sig){ printf("SIGBUS!\n"); _exit(0);}int main(){ int i; char *p, tmp; struct stat st; int fd = -1; fd = open("aaa.txt", O_RDWR); stat("aaa.txt", &st); p = (char*)mmap(NULL, st.st_size, PROT_READ|PROT_WRITE,MAP_SHARED, fd, 0); signal(SIGBUS, handle_sigbus); getchar(); for (i = 0; i < st.st_size; i++) { tmp = p[i]; printf("%x\n", tmp); } printf("ok\n");}
执行:
leon@leon-ubuntu:~$ gcc mmap_test.c leon@leon-ubuntu:~$ echo 12345 > aaa.txt leon@leon-ubuntu:~$ leon@leon-ubuntu:~$ ./a.out (再另一个终端输入执行leon@leon-ubuntu:~$ echo 1 > aaa.txt)31a0000ok
并没有收到信号(测试的系统为ubuntu 16.04),只是访问的文件内容变为了0。这里的结果比较怪异,和其他人的测试结果不符,后续还要在其他操作系统上测试。
在arm板子上(内核2.6.36.4)测试也没有问题,直接偏移越界出文件几个字节,没有报错,打印为0,偏移越界1M长度,报段错误。
思考
未对齐的内存访问和系统架构相关性很大,而作为嵌入式开发者,需要考虑代码的可移植性,这一点需要额外关注。而且感觉我们的程序中,也时而会有这样的未对齐地址访问的代码。例如在处理网络数据时:如下一段代码
#include <stdlib.h>#pragma pack(1)struct packet{ unsigned char enable; int data;};#pragma pack()int main(int argc, char **argv) {#if defined(__GNUC__)# if defined(__i386__) /* Enable Alignment Checking on x86 */ __asm__("pushf\norl $0x40000,(%esp)\npopf");# elif defined(__x86_64__) /* Enable Alignment Checking on x86_64 */ __asm__("pushf\norl $0x40000,(%rsp)\npopf");# endif#endif struct packet pkt; pkt.data = 12; return 0;}
因为是网络数据包,所以1字节对齐,在给结构体初始化赋值时因为未对齐的地址访问出现SIGBUS信号。那么要怎么弄呢,是否说在处理这种情况时都使用memcpy来赋值?
是否应该忽略SIGBUS信号?
首先需要关注,忽略掉这个信号会发生什么
#include <stdlib.h>#include <signal.h>#pragma pack(1)struct packet{ unsigned char enable; int data;};#pragma pack()void bad_sig_handle(int sig){ printf("rcv signal: %d\n", sig);}int main(int argc, char **argv) {#if defined(__GNUC__)# if defined(__i386__) /* Enable Alignment Checking on x86 */ __asm__("pushf\norl $0x40000,(%esp)\npopf");# elif defined(__x86_64__) /* Enable Alignment Checking on x86_64 */ __asm__("pushf\norl $0x40000,(%rsp)\npopf");# endif#endif struct packet pkt; signal(SIGBUS, bad_sig_handle); pkt.data = 12; printf("pkt.data = %d\n", pkt.data); return 0;}
在测试时发现无法捕捉这个信号,没有看到打印,还是收到SIGBUS报了总线错误。怪哉!
参考:
https://en.wikipedia.org/wiki/Bus_error
http://blog.csdn.net/u010944778/article/details/47375299
- Liunux 编程遇到的SIGBUS信号
- 关于Liunux编程的一些记录
- 当mmap遇到sigbus
- 共享内存的管理-注意信号SIGSEGV和SIGBUS(修改)
- 共享内存的管理-注意信号SIGSEGV和SIGBUS(修改过)
- 关于SIGBUS的总结
- 关于SIGBUS的总结
- 关于SIGBUS的总结
- mmap引发的SIGBUS
- /*注册信号处理函数*/ signal(SIGBUS,my_func);
- liunux常见的一些命令
- SIGBUS和SIGSEGV的区别
- SIGBUS和SIGSEGV的区别
- 由mmap引发的SIGBUS
- 由mmap引发的SIGBUS
- 由mmap引发的SIGBUS
- 由mmap引发的SIGBUS
- 由mmap引发的SIGBUS
- swustoj格雷码(0605)
- 西瓜书学习笔记(二)
- 2017.4.20课
- windows上安装MXNet
- TensorFlow实战13:实现策略网络(强化学习一)
- Liunux 编程遇到的SIGBUS信号
- RN-性能优化 (二)
- springmvc入门之注解方式重点解析
- 日期选择器 很多类型的
- Aspose Word模版使用总结
- RN-性能优化 (三)
- ASP连接Mysql小记
- Spring和SpringMVC父子容器关系初窥
- 小结:区间处理和统计与高级数据结构