代码之家  ›  专栏  ›  技术社区  ›  raldi

什么是总线错误?

  •  229
  • raldi  · 技术社区  · 16 年前

    “总线错误”消息是什么意思?它与 segmentation fault ?

    15 回复  |  直到 3 年前
        1
  •  280
  •   Peter Mortensen code4jhon    3 年前

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

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

    访问不属于进程的内存时会出现分段错误。它们非常常见,通常是以下原因造成的:

    • 使用指向已解除分配的内容的指针。
    • 使用未初始化的伪指针。
    • 使用空指针。

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

        2
  •  94
  •   Clinton Pierce    16 年前

    segfault正在访问不允许访问的内存。它是只读的,你没有权限,等等。。。

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

        3
  •  23
  •   Ciro Santilli OurBigBook.com    5 年前

    mmap

    “总线错误”发生在内核发送 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 describes 西格布斯 作为:

    这个 mmap spec

    shm_open says that 它生成大小为0的对象:

    共享内存对象的大小为零。

    *map = 0 我们正在触摸已分配对象的末尾。

    ARMv8 aarch64中未对齐的堆栈内存访问

    What is a bus error?

    您只需要一个独立的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 server machine .

    不幸的是,我不能在QEMU v4.0.0用户模式下复制它,我不知道为什么。

    该故障似乎是可选的,由控制 SCTLR_ELx.SA SCTLR_EL1.SA0 字段,我已经总结了相关文档 a bit further here

        4
  •  11
  •   Oli    16 年前

    我相信内核会引发SIGBUS 当应用程序显示数据时 那是因为大多数现代编译器 为程序员提供的数据 减轻了,因此人们看不到 SIGBUS最近太频繁了(AFAIK)。

    Here

        5
  •  8
  •   Peter Mortensen code4jhon    3 年前

    在…上 POSIX 系统,您还可以获得 SIGBUS

        6
  •  6
  •   Aditya Vikas Devarapalli    4 年前

    我同意上面所有的答案。这是我关于总线错误的2美分:

    总线错误不必由程序代码中的指令引起。当您运行二进制文件时,在执行过程中,二进制文件会被修改(被生成或删除等覆盖),这可能会发生。

    检查这是否是原因的一种简单方法是,从构建输出目录启动两个相同二进制格式的实例,并在它们启动后运行构建。这两个正在运行的实例都会崩溃 SIGBUS 生成完成并替换二进制文件(两个实例当前正在运行的二进制文件)后不久出错。

    根本原因

    这是因为操作系统交换内存页,在某些情况下,二进制文件可能不会完全加载到内存中。当操作系统试图从同一个二进制文件中获取下一页时,会发生这些崩溃,但该二进制文件自上次读取以来已发生更改。

        7
  •  5
  •   Peter Mortensen code4jhon    3 年前

    总线错误的一个典型实例是在某些体系结构上,例如 SPARC

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

    0xdeadf00d 指向(很可能)未正确对齐的地址,并将在这方面“挑剔”的体系结构上生成总线错误。顺便说一下,英特尔x86是,

        8
  •  4
  •   Erik Vesteraas    10 年前

    我在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上,这会导致分段错误(正如预期的那样),但在OSX上,它会导致总线错误。为什么?我真的不知道。

        9
  •  3
  •   goCards    8 年前

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

        10
  •  2
  •   Mark Baker    16 年前

    尝试访问物理上不存在的内存也会导致总线错误,但如果使用的处理器带有MMU和没有bug的操作系统,则不会出现这种情况,因为不会有任何不存在的内存映射到进程的地址空间。

        11
  •  2
  •   Peter Mortensen code4jhon    3 年前

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

        12
  •  1
  •   Alleo    9 年前

    我在MacOSX上出现总线错误的原因是我试图在堆栈上分配大约1Mb。这在一个线程中运行良好,但在使用openMP时,这会导致总线错误,因为Mac OS X的性能非常有限 stack size for non-main threads .

        13
  •  1
  •   John Kearney    3 年前

    首先,SIGBUS和SIGSEGV不是一种特定类型的错误,而是一组或一系列错误。这就是为什么您通常会看到一个信号编号(si_no)和一个信号代码(si_code)。

    一般来说,我们可以这样说。

    SIGBUS是指内存映射成功,并且您遇到底层内存系统问题(内存不足、该位置无内存、对齐、smmu阻止访问等),即总线错误。。

    如果文件从系统中消失,SIGBUS也可以与mmap文件一起使用,例如,您将文件mmap到可移动介质上,然后将其拔出。

    查看平台的一个好地方是siginfo.h头,以了解信号子类型。 e、 g.对于linux,本页提供了概述。 https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/siginfo.h#L245

    /*
     * SIGSEGV si_codes
     */
    #define SEGV_MAPERR 1   /* address not mapped to object */
    #define SEGV_ACCERR 2   /* invalid permissions for mapped object */
    #define SEGV_BNDERR 3   /* failed address bound checks */
    #ifdef __ia64__
    # define __SEGV_PSTKOVF 4   /* paragraph stack overflow */
    #else
    # define SEGV_PKUERR    4   /* failed protection key checks */
    #endif
    #define SEGV_ACCADI 5   /* ADI not enabled for mapped object */
    #define SEGV_ADIDERR    6   /* Disrupting MCD error */
    #define SEGV_ADIPERR    7   /* Precise MCD exception */
    #define SEGV_MTEAERR    8   /* Asynchronous ARM MTE error */
    #define SEGV_MTESERR    9   /* Synchronous ARM MTE exception */
    #define NSIGSEGV    9
    
    /*
     * SIGBUS si_codes
     */
    #define BUS_ADRALN  1   /* invalid address alignment */
    #define BUS_ADRERR  2   /* non-existent physical address */
    #define BUS_OBJERR  3   /* object specific hardware error */
    /* hardware memory error consumed on a machine check: action required */
    #define BUS_MCEERR_AR   4
    /* hardware memory error detected in process but not consumed: action optional*/
    #define BUS_MCEERR_AO   5
    #define NSIGBUS     5
    

    最后一点需要注意的是,所有信号也可以由用户生成,例如kill。

    /*
     * si_code values
     * Digital reserves positive values for kernel-generated signals.
     */
    #define SI_USER     0       /* sent by kill, sigsend, raise */
    #define SI_KERNEL   0x80        /* sent by the kernel from somewhere */
    #define SI_QUEUE    -1      /* sent by sigqueue */
    #define SI_TIMER    -2      /* sent by timer expiration */
    #define SI_MESGQ    -3      /* sent by real time mesq state change */
    #define SI_ASYNCIO  -4      /* sent by AIO completion */
    #define SI_SIGIO    -5      /* sent by queued SIGIO */
    #define SI_TKILL    -6      /* sent by tkill system call */
    #define SI_DETHREAD -7      /* sent by execve() killing subsidiary threads */
    #define SI_ASYNCNL  -60     /* sent by glibc async name lookup completion */
    
    #define SI_FROMUSER(siptr)  ((siptr)->si_code <= 0)
    #define SI_FROMKERNEL(siptr)    ((siptr)->si_code > 0)
    
        14
  •  0
  •   Peter Mortensen code4jhon    5 年前

    我刚刚发现,在ARMv7处理器上,您可以编写一些代码,在未优化时会出现分段错误,但在使用-O2(优化更多)编译时会出现总线错误。

    我使用的是来自Ubuntu 64位的GCC ARM gnueabihf交叉编译器。

        15
  •  0
  •   deeBo    3 年前

    对我来说,我无意中触发了一个“总线错误”,因为我没有声明我的程序集正在返回到 .text

    .globl _myGlobal # Allocate a 64-bit global with the value 2
    .data
    .align 3
    _myGlobal:
    .quad 2
    .globl _main # Main function code
    _main:
    push %rbp
    

    从数据返回代码时缺少文本指令:

    _myGlobal:
    .quad 2
    .text # <- This
    .globl _main
    _main:
    

    希望这对某人有帮助

        16
  •  -1
  •   md5    12 年前

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

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

        17
  •  -1
  •   mimoralea    5 年前

    除了上面blxtd的回答之外,当您的进程 无法尝试访问特定“变量”的内存 .

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

    注意 无意的 变量“i” 第一个“for循环”?