精华内容
下载资源
问答
  • Linux程序调试--Bus Error

    千次阅读 2019-06-28 16:39:12
    Linux程序调试--BusError Bus Error究竟是指什么 一 Bus Error,即总线错误。 引发原因: CPU出于性能方面的考虑,要求对数据进行访问时都必须是地址对齐的。如果发现进行的不是地址对齐的访问,就会发送SIGBUS...

    Linux程序调试--Bus Error

    Bus Error究竟是指什么

    一  Bus Error,即总线错误。

       引发原因:

      CPU出于性能方面的考虑,要求对数据进行访问时都必须是地址对齐的。如果发现进行的不是地址对齐的访问,就会发送SIGBUS信号给进程,使进程产生 core dump。RISC包括SPARC(一种微处理器架构)都是这种类型的芯片。x86系列CPU都支持不对齐访问,也提供了开关禁用这个机制。x86架构不要求对齐访问的时候,必定会有性能代价。例如,对int的访问应该是4字节对齐的,即地址应该是4的倍数,对short则是2字节对齐的,地址应该是2的倍数。

       Bus Error也有可能是因为机器物理问题或者访问无效物理地址,但这种情况非常少见。

       Linux平台上执行malloc(),如果没有足够的RAM,Linux不是让malloc()失败返回,而是向当前进程分发SIGBUS信号。
              注: 对该点执怀疑态度,有机会可自行测试确认当前系统反应。

    SIGBUS与SIGSEGV信号的一般区别如下:

       1) SIGBUS(Bus error)意味着指针所对应的地址是有效地址,但总线不能正常使用该指针。通常是未对齐的数据访问所致。
        2) SIGSEGV(Segment fault)意味着指针所对应的地址是无效地址,没有物理内存对应该地址。

     

    二  例子程序:

     

    1 int main(){
      6 #if defined(__GNUC__)
      7 # if defined(__i386__)
      8    
      9     __asm__("pushf\n orl $0x40000,(%esp) \n popf");
     10 # elif defined(__x86_64__)
     11     
     12     __asm__("pushf\norl $0x40000,(%rsp)\npopf");
     13 # endif
     14 #endif
     24    short array[16];
     25
     26    int * p = (int *) &array[1];
     27    *p = 1;
     28
     29    return 1;
     30 }

     short类型大小为2个字节,其地址必是2的倍数。而对于int指针来说,能够使用以访问数据的地址应该是4的倍数,转化arrary[1]的地址为int *并访问,系统会发出SIGBUS信号,导致程序崩溃。

       wiki上的例子:

        http://en.wikipedia.org/wiki/Bus_error#Bus_error_example

    #include <stdlib.h> 
     
     int main( int argc, char ** argv) { 
     int * iptr; 
     char * cptr; 
     
     #if defined(__GNUC__) 
     # if defined(__i386__) 
     
    __asm__( "pushf/n orl $0x40000,(%esp)/n popf" ) ; 
     # elif defined(__x86_64__)  
     
    __asm__( "pushf/n orl $0x40000,(%rsp)/n popf" ) ; 
     # endif 
     #endif 
     
     
    cptr = malloc( sizeof ( int ) + 1) ; 
     
     
    iptr = ( int * ) ++ cptr; 
     
     
     * iptr = 42 ; 
     
     return 0 ; 
     } 
     
    $ gcc -ansi sigbus.c -o sigbus
    $ ./sigbus 
    Bus error
    $ gdb ./sigbus
    (gdb) r
    Program received signal SIGBUS , Bus error.
    0x080483ba in main ()
    (gdb) x/i $pc
    0x80483ba <main+54>: mov DWORD PTR [eax],0x2a
    (gdb) p/x $eax
    $1 = 0x804a009
    (gdb) p/t $eax & (sizeof(int) - 1)
    $2 = 1
     

     

    三,编译器和硬件平台相关性

     

        上述已经描述,对于x86平台,默认允许非对齐访问,只不过会有性能代价。开启检测可以使用上述代码中的宏。

     

        这段程序如果用Sun Studio编译器的话,运行就没有问题。这是因为Sun Studio默认对32位编译使用的参数是-xmemalign=8i,其中i选项设置明确指明不产生SIGBUS信号。
        不过如果编译成64位程序,Sun Studio使用的-xmemalign=8s,其中s选项设置意味对这种非对齐访问产生SIGBUS信号,则仍旧会遇到这个错误。

     

        如果坚持在SPARC上使用GCC去编译这种代码,可以如下进行:

        GCC有一个Type Attributes特性,例如在需人工对齐的变量后加上:__attribute__ ((aligned (4))); 其意义就是指定偏移量为4的倍数。比如:

     short array[10] __attribute__ ((aligned (4)));

        不过这个属性只对Linker连接器可见的变量有效,也就是说对local variable无效。而且这种特性作用粒度比较大,比如这里只对第一个元素有作用,并不为数组的每个成员设置偏移量。如果一定要针对local variable或者数组的每个成员进行偏移量设置,可以使用union类型:

     union {
    short s;
    int i;
    }
    

     

    Linux程序调试--Bus Error(2)

    我们经常会发现有两种内存转储(core   dump)
    一种是段错误(segment error)通常是在一个非法的地址上进行取值赋值操作造成。
    一种是总线错误(bus   error)通常是指针强制转换,导致CPU读取数据违反了一定的总线规则。

    下面请大家讨论一下总线错误

    有例子如下sizeof(int)==4:
    #include   <stdio.h>
    #include   <stdlib.h>
    int   main()
    {
    int   i[5];
    int   j;
    i[0]=65536+2;
    i[1]=65536*3+4;
    j=*((int   *)((char   *)i+2));      
    printf( "size   of   int   is   %d\nj=%d ",sizeof(int),j);
    return   0;
    }

    我们姑且不考字节序问题,不管j结果是几.

    在一般RISC的CPU上,一般的unix机器上都会出现bus   error。
    而在windows机器上,我用了vc的cl   borland的bcc32和gnu的gcc编译执行都没问题。

    大家有兴趣可以讨论一下

    ***********************************************************************************************

    我想,说来说去bus error都是一个“边界”问题。以下是我的看法:
    从硬件的角度来看,大家应该发现内存是一小块一小块的吧,每一块都有固定大小,现在应该都是4的整数倍,又或者说int大小的整数倍,又或者说地址线总数的整数倍。为什么要这样?硬件好处理呀。举个例子来说吧,如果int型为四字节大小,且首字节地址不受限制的话,该int就可能跨在2个内存块之间(又或者别人说的“跨在2个页内存之间”),那么硬件如何来取数据呢?熟悉硬件的人都应该知道,内存访问是用“十字交叉”来决定地址的,也就是说,每个内存块是互斥的,这时要读这个数据岂不麻烦?如果地址硬规定4的整数倍,可想而知,问题解决了,效率也高了。
    从编程的角度来说,采用的是虚内存,与页内存存在映射关系,当然会导致上述问题。

    unix出现该错误,用我的观点应该可以解释,至于楼主说的vc,如果将奇地址转化为int指针再取值的话,应该会出现问题,那为什么2倍数非4倍数取能够正确执行呢?我想,这可能和操作系统的内存映射有关,unix下可能采用的是“完全对齐”原则,而windows可能给虚内存加了一个边界,也就是说实际的虚页总比实页少至少2字节以上,目的可能是为了防止越界而导致系统崩溃(个人猜测)。

    想到结构体的sizeof问题,顺带提一下,之所以> =内部变量和的大小,是否仔细看过大小的规律?这也应该是“边界”问题,可以说是编译器为了追求数据访问速度而做的一点预处理。

    *********************************************************************************************
    一下代码
    int   main()
    {
    int   a[4]={0,0,0,0};
    int   *pi;
    pi=(int   *)(((char   *)a)+1);
    *pi=3;
    printf( "a0   is   %d\n "   "a1   is   %d\n "   "pi   is   %d\n ",a[0],a[1],*pi);
    printf( "sizeof   int   is   %d\n ",sizeof(int));
    return   0;
    }
    同样用GCC编译
    HP_UX上是出总线错误,(其他UNIX机器上也出,以前做过)
    但拿到WINDOWS   2000机器上就好使。
    a0   is   768
    a1   is   0
    pi   is   3
    sizeof   int   is   4
    现不考虑字节序问题,为什么在windows上就好使呢,难道编译出来的不是32位的程序。难道还作了什么特殊的处理。理论上已改出错才对。怪异
    **************************************************************************************************
    不知道你用的是哪种unix,我记得在Solaris是会存在类似的bus   error的。
    我在linux和sco下进行一些测试,即使你采用编译器默认的对齐方式,对于奇地址强制转化为int地址的情况,程序运行正常,在linux和sco下编译器从栈中为非对齐的结构体非配空间的方式有点小差异,如上所述的结构体,linux是从偶地址开始,sco是从奇地址开始。。。

    撇开上面这些先不谈。
    1。每个操作系统都会有自己的进程载入和调度程序,也就是说,虚内存到实内存的映射,每种os都会有自己的特点,他们可以根据自己的情况避开某些小概率事件,“边界”也应该可以称之为小概率事件,在分配空间时做点手脚,对于分配者来说应该不会困难。
    2。对齐问题,很久以前就听别人说,是为了提高访问效率,想想也是,多一种情况就不得不“if”,而且对齐也利于硬件“批量”访问数据。
    3。采用非对齐方式会降低程序的效率,有些书上可能会提到这些,建议让编译器来决定采用哪种方式,毕竟每种编译器都是根据系统而来的。
    4。在进行地址转换取值的时候,尽量用位拷贝,这样不同的os也不用当心。
    5。不管os怎样对待bus   error问题,不管编译器如何优化,硬件访问数据时的边界问题始终存在,开发可移植系统时,我认为不应该漏掉这个问题。

    你的疑问:
    1。pi-> a对于开发者来说是int,对于c编译起来说是int,对于汇编器来说是一段空间,对于硬件来说是一段空间,在目标代码一级,没什么所谓的类型。
    2。cpu访问数据是通过发指令来控制硬件访问数据的,通常是先读到cache、寄存器。形象一点的话,和十字路口的红绿灯的控制下的车流差不多。看《微机原理》或许会有所帮助。
    3。我认为,硬件在遇到边界问题时,应该会有警告,各各os处理不同罢了。
    4。Solaris的特点

    建议:暂时不用钻得太深,除非你有足够的资料。知道这个问题和大致的可能原因就差不多了,不是说不去掌握它,而是计算机这个东西内容太多,很多硬件问题采用避开而不是花很大代价去解决。等有了足够的知识积累,相信这个问题不会是什么难事。

    展开全文
  • C 总线错误 (bus error) - 段错误 (segmentation fault) 两个常见的运行时错误: bus error (core dumped) - 总线错误 (信息已转储) segmentation fault (core dumped) - 段错误 (信息已转储) 错误信息对引起这两...

    C 总线错误 (bus error) - 段错误 (segmentation fault)

    两个常见的运行时错误

    • bus error (core dumped) - 总线错误 (信息已转储)
    • segmentation fault (core dumped) - 段错误 (信息已转储)

    错误信息对引起这两种错误的源代码错误并没有作简单的解释,上面的信息并未提供如何从代码中寻找错误的线索,而且两者之间的区别也并不是十分清楚,时至今日依然如此。

    错误就是操作系统所检测到的异常,而这个异常是尽可能地以操作系统方便的原则来报告的。总线错误和段错误的准确原因在不同的操作系统版本上各不相同。这里所描述是运行于 SPARC 架构的 SunOS 出现的这两类错误以及产生错误的原因。

    当硬件告诉操作系统一个有问题的内存引用时,就会出现这两种错误。操作系统通过向出错的进程发送一个信号与之交流。信号就是一种事件通知或一个软件中断,在 UNIX 系统编程中使用很广,但在应用程序编程中几乎不使用。在缺省情况下,进程在收到总线错误段错误信号后将进行信息转储并终止。不过可以为这些信号设置一个信号处理程序 (signal handler),用于修改进程的缺省反应。

    信号是由于硬件中断而产生的。对中断的编程是非常困难的,因为它们是异步发生的 (其发生时间是不可预测的)。阅读信号的主文档和头文件 usr/include/sys/signal.h

    1. 在 PC 上捕捉信号

    信号处理函数是 ANSI C 的一部分,与 UNIX 一样,它也同样适用于 PC。例如 PC 程序员可以使用 signal() 函数来捕捉 Ctrl-Break 信号,防止用户用这种方法中断程序。

    在任何使用信号的源文件中,都必须在文件前面增加一行 #include <singal.h>

    这条信息的 core dumped 部分来源于很早的过去,那时所有的内存都是由铁氧化物圆环 (也就是 core,指磁心) 制造的。半导体成为内存的主要制造材料的时间已经超过十五年,但 core 这个词仍然被用作内存的同义词。

    core [kɔː(r)]:n. 核心,要点,果心,磁心 vt. 挖...的核
    

    2. 总线错误 (bus error)

    事实上,总线错误几乎都是由于未对齐的读或写引起的。它之所以称为总线错误,是因为出现未对齐的内存访问请求时,被堵塞的组件就是地址总线。对齐 (alignment) 的意思就是数据项只能存储在地址是数据项大小的整数倍的内存位置上。在现代的计算机架构中,尤其是 RISC 架构,都需要数据对齐,因为与任意的对齐有关的额外逻辑会使整个内存系统吏大且更慢。通过迫使每个内存访问局限在一个 Cache 行或一个单独的页面内,可以极大地简化 (并加速) 如 Cache 控制器和内存管理单元这样的硬件。

    我们表达数据项不能跨越页面或 Cache 边界规则的方法多少有些问接,因为我们用地址对齐这个术语来陈述这个问题,而不是直截了当说是禁止内存跨页访问,但它们说的是同一回事。例如,访问一个 8 字节的 double 数据时,地址只允许是 8 的整数倍。所以一个 double 数据可以存储于地址 24、8008 或 32768,但不能存储于地址 1006 (因为它无法被 8 整除)。页和 Cache 的大小是经过精心设计的,这样只要遵守对齐规则就可以保证一个原子数据项不会跨越一个页或 Cache 块的边界。

    2.1 引起总线错误的程序

    //============================================================================
    // Name        : main
    // Author      : Yongqiang Cheng
    // Version     : Version 1.0.0
    // Copyright   : Copyright (c) 2019 Yongqiang Cheng
    // Description : Hello World in C++, Ansi-style
    //============================================================================
    
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
    	union union_name
    	{
    		char a[10];
    		int i;
    	} union_object;
    
    	printf("argc = %d\n", argc);
    
    	for (int idx = 0; idx < argc; ++idx)
    	{
    		printf("argv[%d] --> %s\n", idx, argv[idx]);
    	}
    
    	printf("argv[argc] = %p\n\n", (void*)argv[argc]);
    
    	int *pt = (int *)&(union_object.a[1]);
    	int *pi = (int *)&(union_object.i);
    
    	*pt = 17;
    
    	printf("*pt = %d\n", *pt);
    	printf("pt = %p\n", pt);
    	printf("pi = %p\n", pi);
    
    	return 0;
    }
    
    argc = 1
    argv[0] --> D:\visual_studio_workspace\yongqiang\Debug\yongqiang.exe
    argv[argc] = 00000000
    
    *pt = 17
    pt = 008FFA39
    pi = 008FFA38
    请按任意键继续. . .
    

    在这里插入图片描述

    pt 中未对齐的地址会引起一个总线错误!
    在实际的运行中并没有出现错误,运行环境如下:
    在这里插入图片描述

    x86 体系结构,如果没有默认对齐的话,访问速度会降低。读一个 int 本来只读一次的,没有对齐的话要读 2 次才行,把第一次的尾巴和第二次的头拼起来。如果在代码中将对齐检查功能打开,运行后能显示 bus error

    这可能导致一个总线错误,因为数组和 int 的联合确保数组 a 是按照 int 的 4 字节对齐的,a+l 的地址肯定未按 int 对齐。我们试图往这个地址存储 4 个字节的数据,但这个访问只是按照单字节的 char 对齐,这就违反了规则。一个好的编译器发现不对齐的情况时会发出警告,但它并不能检测到所有不对齐的情况。

    编译器通过自动分配和填充数据 (在内存中) 来进行对齐。当然,在磁盘或磁带上并没有这样的对齐要求,所以程序员对它们可以很偷快地不必关心数据对齐。但是,当他们把一个 char 指针转换为 int 指针时,就会出现神秘的总线错误。几年前,当检测到一个内存奇偶检验错误时也会产生总线错误。现在,内存芯片已经非常可靠,而且很好地得到了错误检测和修正电路的保护,所以在应用程序编程这一级,奇偶检验错误几乎不再听闻。总线错误也可能由于引用一块物理上不存在的内存引起。如果不遭遇一个淘气的驱动程序,你恐怕不大可能遭遇这种不幸。

    //============================================================================
    // Name        : main
    // Author      : Yongqiang Cheng
    // Version     : Version 1.0.0
    // Copyright   : Copyright (c) 2019 Yongqiang Cheng
    // Description : Hello World in C++, Ansi-style
    //============================================================================
    
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
    #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
    
    	union
    	{
    		char a[10];
    		int i;
    	} u;
    
    	int *p = (int*) &(u.a[1]);
    	*p = 17;
    
    	return 0;
    }
    
    
    16:26:55 **** Build of configuration Debug for project yongqiang_example ****
    make all 
    Building file: ../src/yongqiang.c
    Invoking: GCC C Compiler
    gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/yongqiang.d" -MT"src/yongqiang.o" -o "src/yongqiang.o" "../src/yongqiang.c"
    Finished building: ../src/yongqiang.c
     
    Building target: yongqiang_example
    Invoking: GCC C Linker
    gcc  -o "yongqiang_example"  ./src/yongqiang.o   
    Finished building target: yongqiang_example
     
    
    16:26:56 Build Finished (took 524ms)
    
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ pwd
    /home/strong/eclipse-work/yongqiang_example/Debug
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ ll
    total 56
    drwxrwxr-x 3 strong strong  4096 Mar 30 16:26 ./
    drwxrwxr-x 5 strong strong  4096 Mar 28  2018 ../
    -rw-rw-r-- 1 strong strong  1009 Mar 30 16:26 makefile
    -rw-rw-r-- 1 strong strong   231 Mar 30 16:26 objects.mk
    -rw-rw-r-- 1 strong strong   392 Mar 30 16:26 sources.mk
    drwxrwxr-x 2 strong strong  4096 Mar 30 16:26 src/
    -rwxrwxr-x 1 strong strong 29720 Mar 30 16:26 yongqiang_example*
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ 
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ ./yongqiang_example 
    Bus error (core dumped)
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$
    

    3. 段错误 (segmentation fault)

    段错误或段违规 (segmentation violation)。在 Sun 的硬件中,段错误是由于内存管理单元 (负责支持虚拟内存的硬件) 的异常所致,而该异常则通常是由于解除引用一个未初始化或非法值的指针引起的。如果指针引用一个并不位于你的地址空间中的地址,操作系统便会对此进行干涉。

    一个小型的会引起段错误的程序如下:

    	int *pt = 0;
    	*pt = 17;
    
    //============================================================================
    // Name        : main
    // Author      : Yongqiang Cheng
    // Version     : Version 1.0.0
    // Copyright   : Copyright (c) 2019 Yongqiang Cheng
    // Description : Hello World in C++, Ansi-style
    //============================================================================
    
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
    	printf("argc = %d\n", argc);
    
    	for (int idx = 0; idx < argc; ++idx)
    	{
    		printf("argv[%d] --> %s\n", idx, argv[idx]);
    	}
    
    	printf("argv[argc] = %p\n\n", (void*)argv[argc]);
    
    	int *pt = 0;
    	*pt = 17;
    
    	printf("*pt = %d\n", *pt);
    	printf("pt = %p\n", pt);
    
    	return 0;
    }
    
    
    16:31:07 **** Build of configuration Debug for project yongqiang_example ****
    make all 
    Building file: ../src/yongqiang.c
    Invoking: GCC C Compiler
    gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/yongqiang.d" -MT"src/yongqiang.o" -o "src/yongqiang.o" "../src/yongqiang.c"
    Finished building: ../src/yongqiang.c
     
    Building target: yongqiang_example
    Invoking: GCC C Linker
    gcc  -o "yongqiang_example"  ./src/yongqiang.o   
    Finished building target: yongqiang_example
     
    
    16:31:08 Build Finished (took 571ms)
    
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ pwd
    /home/strong/eclipse-work/yongqiang_example/Debug
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ 
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ ll
    total 56
    drwxrwxr-x 3 strong strong  4096 Mar 30 16:31 ./
    drwxrwxr-x 5 strong strong  4096 Mar 28  2018 ../
    -rw-rw-r-- 1 strong strong  1009 Mar 30 16:31 makefile
    -rw-rw-r-- 1 strong strong   231 Mar 30 16:31 objects.mk
    -rw-rw-r-- 1 strong strong   392 Mar 30 16:31 sources.mk
    drwxrwxr-x 2 strong strong  4096 Mar 30 16:31 src/
    -rwxrwxr-x 1 strong strong 29680 Mar 30 16:31 yongqiang_example*
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ 
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$ ./yongqiang_example 
    argc = 1
    argv[0] --> ./yongqiang_example
    argv[argc] = (nil)
    
    Segmentation fault (core dumped)
    strong@foreverstrong:~/eclipse-work/yongqiang_example/Debug$
    

    一个微妙之处是导致指针具有非法的值通常是由于不同的编程错误所引起的。和总线错误不同,段错误更像是一个间接的症状而不是引起错误的原因。

    一个更糟糕的微妙之处是,如果未初始化的指针恰好具有未对齐的值 (对于指针所要访问的数据而言),它将会产生总线错误,而不是段错误。对于绝大多数架构的计算机而言确实如此,因为 CPU 先看到地址,然后再把它发送给 MMU。

    violation [ˌvaɪəˈleɪʃn]:n. 违反,妨碍,侵害,违背,强奸
    

    在你的代码中,对非法指针值的解除引用操作可能会像上面这样显式地出现,也可能在库函数中出现 (传递给它一个非法值)。令人不快的是,你的程序如果进行了修改 (如在调试状态下编译或增加额外的调试语句),内存的内容便很容易改变,于是这个问题被转移到别处或干脆消失。段错误是非常难于解决的,而且只有非常顽固的段错误才会一直存在。当你看到同事们神色严峻地带着逻辑分析器和示波器进入测试实验室时,便知道他们肯定遇到了真正的麻烦。

    通常导致段错误的几个直接原因:

    • 解除引用一个包含非法值的指针。
    • 解除引用一个空指针 (常常由于从系统程序中返回空指针,并未经检查就使用)。
    • 在未得到正确的权限时进行访问,例如,试图往一个只读的文本段存储值就会引起段错误。
    • 用完了堆栈或堆空间 (虚拟内存虽然巨大但绝非无限)。

    下面这个说法可能过于简单,但在绝大多数架构的绝大多数情况下,总线错误意味着 CPU 对进程引用内存的一些做法不满,而段错误则是 MMU 对进程引用内存的一些情况发出抱怨。

    以发生频率为序,最终可能导致段错误的常见编程错误是:

    1. 坏指针值错误:在指针赋值之前就用它来引用内存,或者向库函数传送一个坏指针 (不要上当!如果调试器显示系统程序中出现了段错误,并不是因为系统程序引起了段错误,问题很可能还存在于自己的代码中)。第三种可能导致坏指针的原因是对指针进行释放之后再访问它的内容。可以修改 free 语句,在指针释放之后再将它置为空值。
      free(p); p = NULL;

    这样,如果在指针释放之后继续使用该指针,至少程序能在终止之前进行信息转储。

    1. 改写 (overwrite) 错误:越过数组边界写入数据,在动态分配的内存两端之外写入数据,或改写一些堆管理数据结构 (在动态分配的内存之前的区域写入数据就很容易发生这种情况)。
      p = malloc(256); p[-1] = 0; p[256] = 0;

    2. 指针释放引起的错误:释放同一个内存块两次,或释放一块未曾使用 malloc 分配的内存,或释放仍在使用中的内存,或释放一个无效的指针。一个极为常见的与释放内存有关的错误就是在 for(p = start; p; p = p-> next) 这样的循环中迭代一个链表,并在循环体内使用 free(p) 语句。这样,在下一次循环迭代时,程序就会对己经释放的指针进行解除引用操作,从而导致不可预料的结果。

    //============================================================================
    // Name        : main
    // Author      : Yongqiang Cheng
    // Version     : Version 1.0.0
    // Copyright   : Copyright (c) 2019 Yongqiang Cheng
    // Description : Hello World in C++, Ansi-style
    //============================================================================
    
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
    	printf("argc = %d\n", argc);
    
    	for (int idx = 0; idx < argc; ++idx)
    	{
    		printf("argv[%d] --> %s\n", idx, argv[idx]);
    	}
    
    	printf("argv[argc] = %p\n\n", (void*) argv[argc]);
    
    	int *pt = NULL;
    
    	free(pt);
    
    	printf("pt = %p\n", pt);
    
    	return 0;
    }
    
    
    argc = 1
    argv[0] --> /home/strong/eclipse-work/yongqiang_example/Debug/yongqiang_example
    argv[argc] = (nil)
    
    pt = (nil)
    
    

    在遍历链表时正确释放元素的方法是使用临时变量存储下一个元素的地址。这样就可以安全地在任何时候释放当前元素,不必担心在取下一个元素的地址时还要引用它,代码如下:

    	struct node *p, *start, *tmp;
    	for (p = start; p; p = tmp)
    	{
    		tmp = p->next;
    		free(p);
    	}
    

    3.1 程序空间是否足够?

    如果你的程序所需的内存超过了操作系统所能提供给它的数量,程序就会发出一条段错误信息并终止。可以用一种简单的方法把这种段错误与其他基于 Bug 的段错误区分开来。

    要弄清程序是否用完了堆栈,可以在 dbx 命令下运行该程序:

    % dbx a.out
    (dbx) catch SIGSEGV
    
    (dbx) run
    ...
    signal SEGV (segmentation violation) in <some_routine> at 0xeff57708
    (dbx) where
    
    如果现在可以看到调用链,那说明堆栈空间还没有用完。
    但是,如果看到像下面这样的东西:
    
    fetch at 0xeffe7a60 failed -- I/O error
    (dbx)
    

    那么,堆找很可能已经用完。上面这个十六进制数就是可以提取或映射的堆栈地址。
    你也可以尝试在 C-shell 中调整堆栈段的大小限制。

    limit stacksize 10
    

    你可以在 C-shell 中调整堆栈段和数据段的最大值。进程的总地址空间仍然受交换区大小的限制,可以用 swap -s 命令查看交换区的大小。

    当程序出现坏指针值时,什么样的结果都有可能发生。一种广被接受的说法是,如果你走运,指针将指向你的地址空间之外,这样第一次使用该指针时就会使程序进行信息转储后终止。如果你不走运,指针将指向你的地址空间之内,并损坏 (改写) 所指向的内存的任何信息。这将引起隐晦的 Bug,非常难以捕捉。

    展开全文
  • Linux系统出现bus error错误

    千次阅读 2020-01-18 13:23:28
    也就是最后显示的“Bus error”,刚巧,不就之前在我这块Linux系统的ARM板子上使用benchmark测试的时候也出现了“Bus error”的错误,一时没有找到什么原因。网上对这个错误有很多的说法,其中有一个观点是:Linux...

    在使用memtester工具对DDR进行压力测试时,出现了一下的报错:

    # memtester 200M 1
    memtester version 4.3.0 (32-bit)
    Copyright (C) 2001-2012 Charles Cazabon.
    Licensed under the GNU General Public License version 2 (only).
    
    pagesize is 4096
    pagesizemask is 0xfffff000
    want 200MB (209715200 bytes)
    got  200MB (209715200 bytes), trying mlock ...locked.
    Loop 1/1:
      Stuck Address       : testing   0Bus error

    也就是最后显示的“Bus error”,刚巧,不就之前在我这块Linux系统的ARM板子上使用benchmark测试的时候也出现了“Bus error”的错误,一时没有找到什么原因。网上对这个错误有很多的说法,其中有一个观点是:Linux平台上执行malloc(),如果没有足够的RAM,Linux不是让malloc()失败返回,而是向当前进程分发SIGBUS信号。所以我怀疑是memtester申请的内存太大了(200M),所以我改为:memtester 50M 1。就能正常执行了。

    展开全文
  • bus error 错误

    千次阅读 2020-06-28 19:00:47
    今天调算法时,第一次发现一个“bus error”的错误,以前没有见过,现记录如下: ** 1. 什么情况下出现的?** 答:有个算法接口的参数为指针,该指针指向用户开辟的内存,如果用户开辟的内存为空,或空指针,就会报...

    今天调算法时,第一次发现一个“bus error”的错误,以前没有见过,现记录如下:

    ** 1. 什么情况下出现的?**
    答:有个算法接口的参数为指针,该指针指向用户开辟的内存,如果用户开辟的内存为空,或空指针,就会报bus error的错误。使用合适的内存指针即可。特别注意,调用第三方接口时,一定要确保传参正确。

    以上情况,只针对自己遇到的境况,其他情形不确定有效。总之,还是要仔细,否则会犯一些低级错误,浪费时间。

    参考:
    1. Bus error的解决方法
    展开全文
  • bus error coredump

    2021-01-08 15:47:59
    我们经常会发现有两种内存转储(core dump) 一种是段错误(segment error)通常是在一个非法...一种是总线错误(bus error)通常是指针强制转换,导致CPU读取数据违反了一定的总线规则。 今天第一次遇到 bus error ...
  • [2]+ Bus error ./AppXXX 找BUG 有点莫名其妙,自己程序没有输出任何错误,直接bus error退了。 错误输出不是自己的打印格式,以防万一还是遍历了代码和所有库文件,未找到bus error! 百度搜索Bus error 搜到...
  • 项目中有多线程的操作,一个线程运行没有问题,两个线程同时运行时,出现报错:Bus error (core dumped) 原因分析: 问题的原因: 指针的中赋值与内容拷贝的问题。 业务逻辑中有图像数据的拷贝过程,图像数据是...
  • Bus error: 10

    千次阅读 2019-02-26 11:44:49
     调试过程中,突然出现“Bus error: 10”的错误,让人措不及防,为什么会出现这种奇观的问题呢?  网上查了很多几个帖子,基本一致认为是地址对齐的问题,大意为:int型数据的起始地址必须为4的倍数,否则会引起...
  • ARM中Bus Error的测试

    2020-08-13 14:39:11
    在芯片测试的时候,我们有时候会碰到Bus Error的情况,这种情况下程序会进到bus error的中断中,中断返回的时候,再次回到原来位置,访问地址的时候再次进入中断,这样就造成程序不停进中断,导致正常测试被打断。...
  • bug:Bus error的解决方法(zz)

    万次阅读 2019-05-28 13:51:25
    Bus error的解决方法(zz) [复制链接] 0 0 liliu4239 白手起家 好友 博客 消息 论坛徽章: 0 电梯直达 1楼 [收藏(0)] [报告] 发表于 2011-12-20...
  • 解决BUS ERROR

    千次阅读 2019-10-15 14:53:43
    记录在arm 板上抛出 BUS error错误 在ubuntu上运行正常,交叉编译后放入开发板的环境下运行,出现bus error的错误。 解决:找了半天原因,是我所使用的libevent框架版本没有统一,交叉编译器使用的是2.0.1而开发板上...
  • 解决Ubuntu下的PCIE Bus Error问题

    千次阅读 2020-03-15 19:16:40
    1 环境 Windows 10 + Ubuntu 16.04 LTS 双系统安装 设备:蓝天Clevo P775TM 2 问题缘由 为了Win10+Ubuntu 16.04双系统共存的方案,去年趁SSD还是白菜价的时候入了intel 760P 256 GB专门作为Ubuntu...PCIe Bus Erro...
  • memcpy core dump bus error size:15383 make: *** [run] Bus error (core dumped) 请教关于总线错误(Bus error) 和 定位处理问多线程Mmap文件Bus Error及解决的办法 为什么程序会出现Bus Error? memcpy...
  • Bus error (core dumped)

    千次阅读 2020-06-04 16:40:36
    Bus error (core dumped) 原因待分析
  • 如题
  • 使用mmap遇到总线错误bus error

    千次阅读 2019-03-07 14:21:35
    perror("open file error"); exit(1); } write(fd,"1",1); lseek(fd,MMAP_BUFF_SIZE,SEEK_SET); pid_t pid = fork(); if(pid == -1) { perror("fork error"); close(fd); exit(1); } if(pid > 0) {/...
  • C语言中 bus error(总线错误)解释

    千次阅读 2020-01-04 18:39:58
    bus error(总线错误): 当在ubuntu系统下编译程序遇到bus error ,这意味着你程序中的整数存储在错误的边界上,这时你应该仔细检查你的数据是否越界。 segmentation violation or memory fault : 这是提示你所编写...
  • 1. 错误:ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm). 2. 原因:Pytorch的IPC会利用共享内存,所以对于当前代码运行环境的共享内存必须足够大...
  • 在应用程序中通过memeset清零时,产生Bus error. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); .... memset(*Logical,0,Size); 原因: 在部分平台上,memset不能操作device映射的space。...
  • linux mmap bus error

    2018-05-23 18:23:31
    #include "stdio.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "sys/mman.h"...//test mmap with bus error typedef stru
  • 运行后出现 Bus error (core dumped) 方法一:df -lh 查看磁盘使用情况,是否是磁盘使用满了。如果磁盘满了,删除一些相应磁盘上的文件就可以了。 测试结果:失败 方法二:python在import tensorflow时出现Bus ...
  • Bus error的调试解决方法

    万次阅读 2015-02-26 18:10:32
    可是使用ARM的gcc进行交叉编译,再送到DaVinci目标板上运行的时候,出现了Bus error。 出现的位置如下(其中Debug的内容是我在程序中添加的调试信息): root@211.69.193.189:~# arm_v5t_le-gcc -g shit.
  • 网络编程中遇到bus error错误,由该文中可以知道是地址未对齐的问题 查找原因,在发送的报文中,某个报文使用了1个字节,发生了地址未对齐。。。。 解决方法:将该报文定义为2个字节,该问题解决。 ...
  • 今天下午在运行一个executable的时候只要一执行就报错Bus error,用gdb执行的话也是报错SIGBUS,gdb报错如下图所示。 GDB执行的结果 因为是在调试appweb的时候出的问题,我一度以为appweb有什么隐藏的逻辑会导致...
  • 其实解决方法是一样的,只是加载grub的命令不一样而已错误信息如下:Jan 22 11:42:00 office-test-001 kernel: pcieport 0000:00:1d.0: AER: Corrected error received: id=00e8Jan 22 11:42:...
  • 总线错误(Bus error)

    万次阅读 2018-06-12 18:00:14
    Bus error(core dumped);. 当出现这种信息的时候,则表示在SPARC等RISC类型的CPU中发生了"违反定位访问"的情况.例如,读者可以阅读下面的程序.#include &lt;string.h&gt; #include &lt;stdio.h&...
  • ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm). 需要把dataloader里面的num_works设置成1
  • 近期,应测试需求,将批量比较老的联想台式机安装成CentOS 7系统(发现数十台电脑全这样报错)。...Feb 28 11:52:07 test148 kernel: pcieport 0000:00:1c.5: device [8086:a115] error status/mask=00001000/...
  • RuntimeError: DataLoader worker (pid XXX) is killed by signal: Bus error 两种解决方案 第一种 ,权宜之计 把 代码中的 dataloader 改掉 num-worker改低 不行就 = 1 试试 第二种,docker的问题,docker分配的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 48,783
精华内容 19,513
关键字:

buserror