zoukankan      html  css  js  c++  java
  • 总线错误与段错误

    总线错误"消息是什么意思,它与段错误有什么区别?


    如今,总线错误在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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    #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, fd0);
        /* This is what generates the SIGBUS. */
        *map 0;
    }

    运行:

    1
    2

    gcc -std=c99 main.-lrt
    ./a.out

    在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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    .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 x00
        mov x893
        svc 0

    然后,该程序在ThunderX2服务器计算机上的Ubuntu 18.04 aarch64,Linux内核4.15.0上引发SIGBUS。

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

    该故障似乎是可选的,并由SCTLR_ELx.SA和SCTLR_EL1.SA0字段控制,我在这里对相关文档进行了一些总结。


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


    我在OS X上进行C编程时遇到的总线错误的一个具体示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    #include <string.h>
    #include <stdio.h>

    int main(void)
    {
        char buffer[120];
        fgets(buffersizeof buffer, stdin);
        strcat("foo", buffer);
        return 0;
    }

    如果您不记得文档strcat可以通过更改第一个参数将第二个参数附加到第一个参数(翻转参数并可以正常工作)。在Linux上,这会产生分段错误(如预期的那样),但是在OS X上,则会出现总线错误。为什么?我真的不知道


    总线错误的一个经典实例是在某些架构上,例如SPARC(至少某些SPARC,也许已更改)是在您进行错误对齐的访问时。例如:

    1
    2

    unsigned char data[6];
    (unsigned int *(data 20xdeadf00d;

    此代码段尝试将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
    2
    3
    4
    5

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

    注意第一个" for循环"中变量" i"的"无意"用法吗?这就是在这种情况下导致总线错误的原因。


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

    1
    2
    3
    4
    5

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

    如果双引号(")中的字符串大小大于buf大小,则会出现总线错误。

    https://www.codenong.com/212466/

    ------------------越是喧嚣的世界,越需要宁静的思考------------------ 合抱之木,生于毫末;九层之台,起于垒土;千里之行,始于足下。 积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里;不积小流,无以成江海。骐骥一跃,不能十步;驽马十驾,功在不舍。锲而舍之,朽木不折;锲而不舍,金石可镂。蚓无爪牙之利,筋骨之强,上食埃土,下饮黄泉,用心一也。蟹六跪而二螯,非蛇鳝之穴无可寄托者,用心躁也。
  • 相关阅读:
    【Leetcode】反转链表 II
    将博客搬至CSDN
    UVA 11021(概率)
    zoj
    Codeforces Round #227 (Div. 2) / 387C George and Number (贪心)
    点头(1163)
    fzu-2164 Jason's problem(数论)
    nyist --ACM组队练习赛(链接)
    nyoj-括号匹配(二)15---动态规划
    动态规划
  • 原文地址:https://www.cnblogs.com/feng9exe/p/14364190.html
Copyright © 2011-2022 走看看