“总线错误”消息是什么意思,它与段错误有什么区别?
“总线错误”消息是什么意思,它与段错误有什么区别?
Answers:
如今,总线错误在x86上很少见,并在处理器甚至无法尝试请求的内存访问时发生,通常是:
当访问不属于您的进程的内存时,会发生分段错误,它们很常见,通常是由于以下原因导致的:
PS:更准确地说,这不是操纵会导致问题的指针本身,而是访问它指向的内存(取消引用)。
/var/cache
只是完整的askubuntu.com/a/915520/493379
static_cast
了一个void *
参数(一个属性指向该对象,另一个属性指向该方法)。然后调用该回调。但是,传递的内容void *
完全不同,因此方法调用导致总线错误。
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;
}
运行:
gcc -std=c99 main.c -lrt
./a.out
在Ubuntu 14.04中测试。
POSIX 描述 SIGBUS
为:
访问内存对象的未定义部分。
该MMAP规范说:
在地址范围内从pa开始并在整个对象的末尾连续len个字节到整个页面的引用,将导致SIGBUS信号的传递。
并shm_open
说它生成大小为0的对象:
共享内存对象的大小为零。
因此,*map = 0
我们正在触及分配对象的末尾。
ARMv8 aarch64中未对齐的堆栈内存访问
在以下位置提到此问题:什么是总线错误?SPARC,但在这里我将提供一个更可重现的示例。
您需要的是一个独立的aarch64程序:
.global _start
_start:
asm_main_after_prologue:
/* misalign the stack out of 16-bit boundary */
add sp, sp, #-4
/* access the stack */
ldr w0, [sp]
/* exit syscall in case SIGBUS does not happen */
mov x0, 0
mov x8, 93
svc 0
然后,该程序在ThunderX2服务器计算机上的Ubuntu 18.04 aarch64,Linux内核4.15.0上引发SIGBUS 。
不幸的是,我无法在QEMU v4.0.0用户模式下重现它,我不确定为什么。
故障似乎是可选的,由SCTLR_ELx.SA
和SCTLR_EL1.SA0
字段控制,我在这里对相关文档进行了进一步的总结。
我相信,当应用程序在数据总线上显示数据未对齐时,内核会提高SIGBUS。我认为,由于大多数处理器的大多数现代编译器都会为程序员填充/对齐数据,因此(至少)减轻了以往的对齐麻烦,因此,最近几天人们很少看到SIGBUS(AFAIK)。
来自:这里
当由于某种原因而无法分页代码页时,您也可以获得SIGBUS。
mmap
的文件大小大于/dev/shm
我在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;
}
以防万一您不记得文档strcat
通过更改第一个参数将第二个参数附加到第一个参数(翻转参数并可以正常工作)。在Linux上,这会产生分段错误(如预期的那样),但在OS X上,则会出现总线错误。为什么?我真的不知道
"foo"
存储在内存的只读段中,因此无法对其进行写入。它不会是堆栈溢出保护,而不会是内存写保护(如果程序可以自行重写,这是一个安全漏洞)。
总线错误的一个经典实例是在某些架构上,例如SPARC(至少某些SPARC,也许已更改)是在您进行错误对齐的访问时。例如:
unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;
此代码段尝试将32位整数值写入0xdeadf00d
(最有可能)未正确对齐的地址,并且会在这方面“挑剔”的体系结构上产生总线错误。顺便说一下,Intel x86 不是这样的体系结构,它将允许访问(尽管执行速度较慢)。
这取决于您的操作系统,CPU,编译器以及其他可能的因素。
通常,这意味着CPU总线无法完成命令或发生冲突,但这可能意味着各种情况,具体取决于运行的环境和代码。
-亚当
通常,这意味着未对齐的访问。
尝试访问物理上不存在的内存也会导致总线错误,但是如果您使用的处理器带有MMU和没有错误的操作系统,则不会看到此错误,因为您不会遇到任何错误。 -已存在的内存映射到您进程的地址空间。
scanf
),我仍然遇到此错误。这是否意味着OS X Mavericks有故障?在非越野车操作系统上的行为将是什么?
在Mac OS X上出现总线错误的原因是,我试图在堆栈上分配大约1Mb。这在一个线程中效果很好,但是当使用openMP时,这会导致总线错误,因为Mac OS X 对于非主线程的堆栈大小非常有限。
我同意以上所有答案。这是我关于BUS错误的2美分:
程序代码中的指令不必引起BUS错误。当您运行二进制文件并且在执行过程中,二进制文件被修改(被构建覆盖或删除等)时,可能会发生这种情况。
验证是否存在这种情况:
检查是否是这种原因的一种简单方法是启动运行相同二进制文件的实例并运行构建。SIGBUS
构建完成并替换二进制文件(两个实例当前正在运行的二进制文件)后不久,两个正在运行的实例都会因错误而崩溃。
根本原因: 这是因为OS交换内存页面,在某些情况下,二进制文件可能未完全加载到内存中,并且当OS尝试从同一二进制文件中获取下一页时,会发生这些崩溃,但是二进制文件自上次使用以来已发生更改阅读。
为了补充上面的答案,当您的进程无法尝试访问特定“变量”的内存时,也会发生总线错误。
for (j = 0; i < n; j++) {
for (i =0; i < m; i++) {
a[n+1][j] += a[i][j];
}
}
注意“ 无意的”使用变量“I”在第一个“for循环”?这就是在这种情况下导致总线错误的原因。
我刚刚发现很难在ARMv7处理器上编写一些代码,这些代码在未优化时会给您带来分段错误,但在使用-O2进行编译时会给您带来总线错误(优化更多信息)。
我正在使用来自Ubuntu 64位的GCC ARM gnueabihf交叉编译器。
导致总线错误的典型缓冲区溢出是:
{
char buf[255];
sprintf(buf,"%s:%s\n", ifname, message);
}
如果双引号(“”)中字符串的大小大于buf大小,则会出现总线错误。