17

我正在努力解决总线错误。

一种方法是未对齐的访问,我已经尝试了此处此处给出的示例,但对我来说没有错误 - 程序执行得很好。

是否有某些情况肯定会产生总线错误?

4

12 回答 12

20

这应该可靠地导致一个SIGBUS符合 POSIX 的系统。

#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
int main() {
    FILE *f = tmpfile();
    int *m = mmap(0, 4, PROT_WRITE, MAP_PRIVATE, fileno(f), 0);
    *m = 0;
    return 0;
}

从单一 Unix 规范,mmap

地址范围内的引用从pa开始并持续len字节到对象结束后的整个页面,将导致 SIGBUS 信号的传递。

于 2010-01-15T06:10:23.130 回答
11

总线错误只能在以下硬件平台上调用:

  1. 需要一致的访问权限,并且
  2. 不要通过执行两个对齐的访问并组合结果来补偿未对齐的访问。

您可能无法访问这样的系统。

于 2010-01-15T04:09:34.010 回答
7

尝试以下方式:

#include <signal.h>
int main(void)
{
    raise(SIGBUS);
    return 0;
}

(我知道,可能不是你想要的答案,但它几乎肯定会给你一个“总线错误”!)

于 2010-01-15T06:44:27.103 回答
3

正如其他人所提到的,这是非常特定于平台的。在我正在使用的 ARM 系统(没有虚拟内存)上,有很大一部分地址空间没有分配内存或外围设备。如果我读取或写入其中一个地址,则会出现总线错误。

如果总线上确实存在硬件问题,您也可能会收到总线错误。

如果您在具有虚拟内存的平台上运行,您可能无法故意在程序中生成总线错误,除非它是设备驱动程序或其他内核模式软件。无效的内存访问可能会被内存管理器捕获为访问冲突或类似情况(它甚至没有机会撞上总线)。

于 2010-01-15T06:20:47.893 回答
3

在带有 Intel CPU 的 linux 上试试这个:

int main(int argc, char **argv)
{
# if defined i386
    /* enable alignment check (AC) */
    asm("pushf; "
    "orl $(1<<18), (%esp); "
    "popf;");
# endif

    char d[] = "12345678";  /* yep! - causes SIGBUS even on Linux-i386 */
    return 0;
}

这里的技巧是在 CPU 的一个“特殊”寄存器中设置“对齐检查”位。

另见:这里

于 2010-02-17T15:29:48.957 回答
3

我确信您必须使用 x86 机器。除非设置了 EFALAGS 寄存器中的 AC 标志,否则 X86 cpu 不会产生总线错误。

试试这个代码:

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

int main(void)
{
    char *p;

    __asm__("pushf\n"
            "orl $0x40000, (%rsp)\n"
            "popf");

    /* 
     * malloc() always provides aligned memory.
     * Do not use stack variable like a[9], depending on the compiler you use,
     * a may not be aligned properly.
     */
    p = malloc(sizeof(int) + 1);
    memset(p, 0, sizeof(int) + 1);

    /* making p unaligned */
    p++;

    printf("%d\n", *(int *)p);

    return 0;
}

更多相关信息,请访问http://orchistro.tistory.com/206

于 2011-12-07T09:10:07.500 回答
1

还要记住,某些操作系统会报告“总线错误”,而不是未对齐的访问。你没有在你的问题中提到你真正想要实现的是什么。也许尝试这样:

int *x = 0;
*x=1;

您链接到的维基百科页面提到访问不存在的内存也可能导致总线错误。将已知无效地址加载到指针中并取消引用它可能会更好。

于 2010-01-15T05:53:52.337 回答
1

这个怎么样?未经测试。

  #include<stdio.h>

    typedef struct
    {
    int a;
    int b;
    } busErr;

    int main()
    {
    busErr err;
    char * cPtr;
    int *iPtr;
    cPtr = (char *)&err;
    cPtr++;
    iPtr = (int *)cPtr;
    *iPtr = 10;
    } 
于 2010-01-15T07:24:23.607 回答
1
int main(int argc, char **argv)
{
    char *bus_error = new char[1];
    for (int i=0; i<1000000000;i++) {
        bus_error += 0xFFFFFFFFFFFFFFF;
    *(bus_error + 0xFFFFFFFFFFFFFF) = 'X';
    }
}

总线错误:10(核心转储)

于 2013-03-22T14:39:51.377 回答
0

很简单,写入不属于你的内存:

int main()
{
    char *bus_error = 0;

    *bus_error = 'X';
}

我的 PowerPC Mac [OS X 10.4,双 1ghz PPC7455] 上的即时总线错误,不一定在您的硬件和/或操作系统上。

甚至还有一篇关于总线错误的维基百科文章,包括一个制作程序。

于 2010-01-15T04:21:48.397 回答
0

对于 0x86 拱门:

#include <stdio.h>

int main()
{
#if defined(__GNUC__)
# if defined(__i386__)
    /* Enable Alignment Checking on x86 */
    __asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
    /* Enable Alignment Checking on x86_64 */
    __asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif

    int b = 0;
    int a = 0xffffff;
    char *c = (char*)&a;
    c++;
    int *p = (int*)c;
    *p = 10;  //Bus error as memory accessed by p is not 4 or 8 byte aligned
    printf ("%d\n", sizeof(a));
    printf ("%x\n", *p);
    printf ("%x\n", p);
    printf ("%x\n", &a);
}

注意:如果删除 asm 指令,代码将不会像其他人建议的那样生成 SIGBUS 错误。SIGBUS 也可能由于其他原因而发生。

于 2018-04-18T14:04:41.043 回答
-1

如果您尝试访问计算机无法寻址的内存,则会发生总线错误。例如,您的计算机内存的地址范围为 0x00 到 0xFF,但您尝试访问位于 0x0100 或更大的内存元素。

实际上,您的计算机将具有比 0x00 到 0xFF 更大的范围。

要回答您的原始帖子:

告诉我一些肯定会产生总线错误的情况。

在您的代码中,索引到最大内存限制范围之外的内存方式。我不知道...使用某种巨大的十六进制值 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 索引到 char* ...

于 2010-01-15T06:01:51.730 回答