“总线错误”消息是什么意思,它与段错误有何不同?

有帮助吗?

解决方案

如今,总线错误在 x86 上很少见,当您的处理器甚至无法尝试请求的内存访问时,就会发生总线错误,通常是:

  • 使用地址不满足对齐要求的处理器指令。

当访问不属于您的进程的内存时,会出现分段错误,这种情况很常见,通常是由于以下原因造成的:

  • 使用指向已释放的内容的指针。
  • 使用未初始化的虚假指针。
  • 使用空指针。
  • 缓冲区溢出。

附:更准确地说,这并不是操作指针本身会导致问题,而是访问它指向的内存(取消引用)。

其他提示

段错误正在访问您不允许访问的内存。它是只读的,你没有权限等......

总线错误正在尝试访问不可能存在的内存。您使用了对系统无意义的地址,或者该操作的错误地址类型。

  

我相信内核提出了SIGBUS   当应用程序显示数据时   数据总线上的错位。我认为   那是因为大多数[?]现代编译器   对于大多数处理器垫/对齐   程序员的数据,   以前的对齐问题(至少)   减轻了,因此人们看不到   SIGBUS这些天太常见了(AFAIK)。

发件人:此处

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 as:

  

访问内存对象的未定义部分。

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

然后该程序在Ubuntu 18.04 aarch64,Linux内核4.15.0中的 ThunderX2服务器机器。

不幸的是,我无法在QEMU v4.0.0用户模式下重现它,我不知道为什么。

故障似乎是可选的,由 SCTLR_ELx.SA SCTLR_EL1.SA0 字段控制,我总结了相关的文档在这里进一步了解

当代码页由于某种原因无法被分页时,您也可以获得SIGBUS。

某些架构错误的典型实例是某些架构,例如 SPARC (至少有一些SPARC,可能已经改变了),就是当你进行错误对齐的访问时。例如:

unsigned char data[6];
(unsigned int *) (data + 2) = 0xdeadf00d;

此代码段尝试将32位整数值 0xdeadf00d 写入(很可能)未正确对齐的地址,并将在“挑剔”的架构上生成总线错误。在这方面。顺便说一句,英特尔x86是这样的架构,它允许访问(尽管执行速度更慢)。

这取决于您的操作系统,CPU,编译器以及可能的其他因素。

一般来说,这意味着CPU总线无法完成命令或遇到冲突,但这可能意味着一系列事情,具体取决于运行的环境和代码。

- 亚当

通常表示未对齐访问。

尝试访问实际上不存在的内存也会导致总线错误,但是如果您使用的是带有MMU的处理器和没有错误的操作系统,您将看不到这一点,因为您不会将任何不存在的内存映射到进程的地址空间。

我在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上会出现总线错误。为什么?我真的不知道。

当根目录为100%时,我收到了总线错误。

我在Mac OS X上出现总线错误的原因是我试图在堆栈上分配大约1Mb。这在一个线程中运行良好,但是当使用openMP时,这会导致总线错误,因为Mac OS X非常有限非主线程的堆栈大小

要添加上面回答的blxtd,当您的进程无法尝试访问特定“变量”的内存时,也会发生总线错误。

for (j = 0; i < n; j++) {
                for (i =0; i < m; i++) {
                        a[n+1][j] += a[i][j];
                }
        }

请注意 无意 变量'i' 的使用首先'for loop'? 这就是造成总线错误的原因。

我刚刚发现,在ARMv7处理器上你可以编写一些代码,在未经优化的情况下为你提供分段错误,但在使用-O2编译时会出现总线错误(优化更多)。 我正在使用ubuntu x64的gcc arm gnueabihf交叉编译器。

我同意上面的所有答案。以下是关于BUS错误的2美分:

程序代码中的指令不需要出现BUS错误。当您运行二进制文件时会发生这种情况,并且在执行期间,二进制文件会被修改(由构建覆盖或删除等)。

验证是否属于这种情况: 检查这是否是原因的一种简单方法是启动相同二进制文件的运行实例并运行构建。在构建完成后不久,两个正在运行的实例都会因 SIGBUS 错误而崩溃并替换二进制文件(两个实例当前正在运行的那个)

潜在原因: 这是因为操作系统交换内存页面,在某些情况下,整个二进制文件可能存在于内存中,当操作系统尝试从同一个二进制文件中获取下一页时会发生这些崩溃,但二进制文件自上次读取后就已更改。 / p>

导致总线错误的典型缓冲区溢出是

{
    char buf[255];
    sprintf(buf,"%s:%s\n", ifname, message);
}

如果双引号(“&quot;”)中字符串的大小超过buf大小,则会出现总线错误。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top