总线错误"消息是什么意思,它与段错误有什么区别?
如今,总线错误在x86上很少见,并在处理器甚至无法尝试请求的内存访问时发生,通常是:
- 使用地址不满足其对齐要求的处理器指令。
当访问不属于您的进程的内存时,会发生分段错误,它们很常见,通常是由于以下原因导致的:
- 使用指向已释放对象的指针。
- 使用未初始化的虚假指针。
- 使用空指针。
- 缓冲区溢出。
PS:更准确地说,这不是操纵会导致问题的指针本身,而是访问它指向的内存(取消引用)。
段错误正在访问您不允许访问的内存。它是只读的,您没有权限,等等。
总线错误正在尝试访问可能不存在的内存。您使用了对系统无意义的地址,或者该操作使用了错误的地址。
I believe the kernel raises SIGBUS
when an application exhibits data
misalignment on the data bus. I think
that since most[?] modern compilers
for most processors pad / align the
data for the programmers, the
alignment troubles of yore (at least)
mitigated, and hence one does not see
SIGBUS too often these days (AFAIK).
从这里
mmap最小POSIX 7示例
当内核将SIGBUS发送到进程时,将发生"总线错误"。
产生它的一个最小示例,因为它忘记了ftruncate:
1 |
#include <fcntl.h> /* O_ constants */ |
运行:
1 |
gcc -std=c99 main.c -lrt |
在Ubuntu 14.04中测试。
POSIX将SIGBUS描述为:
Access to an undefined portion of a memory object.
mmap规范指出:
References within the address range starting at pa and continuing for len bytes to whole pages following the end of an object shall result in delivery of a SIGBUS signal.
shm_open表示它生成大小为0的对象:
The shared memory object has a size of zero.
因此,在*map = 0处,我们触摸分配对象的末尾。
ARMv8 aarch64中未对齐的堆栈内存访问
在以下位置提到此问题:什么是总线错误? SPARC,但在这里我将提供一个更可重现的示例。
您需要的是一个独立的aarch64程序:
1 |
.global _start |
然后,该程序在ThunderX2服务器计算机上的Ubuntu 18.04 aarch64,Linux内核4.15.0上引发SIGBUS。
不幸的是,我无法在QEMU v4.0.0用户模式下重现它,我不确定为什么。
该故障似乎是可选的,并由SCTLR_ELx.SA和SCTLR_EL1.SA0字段控制,我在这里对相关文档进行了一些总结。
当由于某种原因而无法分页代码页时,您也可以获得SIGBUS。
我在OS X上进行C编程时遇到的总线错误的一个具体示例:
如果您不记得文档strcat可以通过更改第一个参数将第二个参数附加到第一个参数(翻转参数并可以正常工作)。在Linux上,这会产生分段错误(如预期的那样),但是在OS X上,则会出现总线错误。为什么?我真的不知道
总线错误的一个经典实例是在某些架构上,例如SPARC(至少某些SPARC,也许已更改)是在您进行错误对齐的访问时。例如:
1 |
unsigned char data[6]; |
此代码段尝试将32位整数值0xdeadf00d写入(最有可能)未正确对齐的地址,并且将在这方面"挑剔"的体系结构上产生总线错误。顺便说一下,Intel x86不是这样的体系结构,它将允许访问(尽管执行速度较慢)。
当根目录为100%时,出现总线错误。
通常,这意味着未对齐的访问。
尝试访问物理上不存在的内存也会导致总线错误,但是如果您使用的处理器带有MMU和没有错误的操作系统,则不会看到此错误,因为您不会遇到任何错误。 -映射到您进程的地址空间的现有内存。
这取决于您的操作系统,CPU,编译器以及其他可能的因素。
通常,这意味着CPU总线无法完成命令或发生冲突,但这可能意味着各种情况,具体取决于运行的环境和代码。
-亚当
在Mac OS X上发生总线错误的原因是,我试图在堆栈上分配大约1Mb。这在一个线程中效果很好,但是当使用openMP时,这会导致总线错误,因为Mac OS X对于非主线程的堆栈大小非常有限。
我同意以上所有答案。这是我关于BUS错误的2美分:
程序代码中的指令不必引起BUS错误。当您运行二进制文件并且在执行过程中,二进制文件被修改(被构建覆盖或删除等)时,可能会发生这种情况。
验证是否是这种情况:
检查是否是原因的一种简单方法是启动运行相同二进制文件的实例并运行构建。构建完成并替换二进制文件后(两个实例当前都在运行),两个正在运行的实例都将崩溃并出现SIGBUS错误。
根本原因:
这是因为OS交换内存页面,在某些情况下,整个二进制文件可能位于内存中,并且当OS尝试从同一二进制文件中提取下一页时,会发生这些崩溃,但是自从上次读取二进制文件以来,二进制文件已发生更改。
我刚刚发现很难在ARMv7处理器上编写一些代码,这些代码在未优化时会给您带来分段错误,而在使用-O2进行编译时会给您带来总线错误(优化更多信息)。
我正在使用来自ubuntu x64的gcc arm gnueabihf交叉编译器。
为了补充上面的答案,当您的进程无法尝试访问特定"变量"的内存时,也会发生总线错误。
1 |
for (j = 0; i < n; j++) { |
注意第一个" for循环"中变量" i"的"无意"用法吗?这就是在这种情况下导致总线错误的原因。
导致总线错误的典型缓冲区溢出是:
1 |
{
char buf[255]; sprintf(buf,"%s:%s ", ifname, message); } |
如果双引号(")中的字符串大小大于buf大小,则会出现总线错误。
https://www.codenong.com/212466/