blt*_*txd 232
现在,在x86上很少出现总线错误,并且当您的处理器甚至无法尝试请求的内存访问时发生错误,通常是:
访问不属于您的进程的内存时会发生分段错误,它们非常常见,通常是以下结果:
PS:更确切地说,这不是操纵会导致问题的指针本身,而是访问它指向的内存(解除引用).
Oli*_*Oli 11
我相信当应用程序在数据总线上出现数据错位时,内核会引发SIGBUS.我认为,由于大多数处理器的大多数[?]现代编译器为程序员填充/对齐数据,因此过去(至少)减少了对齐问题,因此现在人们看不到SIGBUS(AFAIK).
来自:这里
Cir*_*四事件 10
mmap
最小的POSIX 7示例
内核发送SIGBUS
到进程时发生"总线错误" .
产生它的最小例子因为ftruncate
被遗忘了:
#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */
int main() {
int fd;
int *map;
int size = sizeof(int);
char *name = "/a";
shm_unlink(name);
fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
/* THIS is the cause of the problem. */
/*ftruncate(fd, size);*/
map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
/* This is what generates the SIGBUS. */
*map = 0;
}
Run Code Online (Sandbox Code Playgroud)
运行:
gcc -std=c99 main.c -lrt
./a.out
Run Code Online (Sandbox Code Playgroud)
在Ubuntu 14.04中测试过.
POSIX 描述 SIGBUS
为:
访问内存对象的未定义部分.
该MMAP规范说:
从pa开始并且在对象结束之后继续len字节到整个页面的地址范围内的引用将导致SIGBUS信号的传递.
并shm_open
说它生成大小为0的对象:
共享内存对象的大小为零.
所以*map = 0
我们正在触及分配对象的末尾.
总线错误的一个典型实例是在某些体系结构上,例如SPARC(至少有一些 SPARC,也许这已被更改),即当您进行未对齐的访问时。例如:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
Run Code Online (Sandbox Code Playgroud)
此代码段尝试将 32 位整数值写入0xdeadf00d
(很可能)未正确对齐的地址,并且会在这方面“挑剔”的架构上生成总线错误。顺便说一下,Intel x86 并不是这样的架构。它将允许访问(尽管执行速度更慢)。
我刚刚在 OS X 上编程 C 时遇到的总线错误的具体示例:
#include <string.h>
#include <stdio.h>
int main(void)
{
char buffer[120];
fgets(buffer, sizeof buffer, stdin);
strcat("foo", buffer);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您不记得文档strcat
通过更改第一个参数将第二个参数附加到第一个参数(翻转参数,它可以正常工作)。在 Linux 上,这会产生分段错误(如预期),但在 OS X 上,会产生总线错误。为什么?我真的不知道。
我同意上面的所有答案。这是我关于 BUS 错误的 2 美分:
程序代码中的指令不一定会导致 BUS 错误。当您运行二进制文件并且在执行期间,二进制文件被修改(被构建覆盖或删除等)时,可能会发生这种情况。
验证是否是这种情况
检查这是否是原因的一种简单方法是通过从构建输出目录启动相同二进制文件的几个实例,并在它们启动后运行构建。SIGBUS
在构建完成并替换二进制文件(两个实例当前正在运行的那个)后不久,两个正在运行的实例都会因错误而崩溃。
根本原因
这是因为操作系统会交换内存页面,并且在某些情况下,二进制文件可能不会完全加载到内存中。当操作系统尝试从同一个二进制文件中获取下一页时,就会发生这些崩溃,但该二进制文件自上次读取以来已发生更改。