段错误以及调试方法
---恢复内容开始---
常见内存错误
(1)内存分配(malloc, new)未成功,却使用了它。
解决方法:在使用内存之前检查指针是否为NULL
(2)内存分配成功,但是没有初始化。在定义数组时养成赋0值的习惯。
(3)内存分配成功,也初始化了,操作越过了内存的边界。
(4)忘记释放内存,造成内存泄漏
(5)释放了内存后继续使用,有三种情况:
- 程序中的对象调用过于复杂,比如:
int *a = new int[10]; int *b = a; delete b;//已经将a所指向的内存释放 delete a;//又释放一遍,会出现错误
- 函数return一个局部变量指针,函数结束申请的栈中的资源就会被回收
- 使用free和delete释放内存后,没有将指针设置为NULL,导致产生野指针
段错误:
简而言之,产生段错误就是访问了错误的内存段,一般是由于没有权限,或者根本就不存在对应的物理地址,尤其常见的是访问0地址。
一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存控件,通常这个值由gdr来保存的,它是一个48为的寄存器,其中的32位用来保存由它指向的gdt表;后13位用来保存相应于gdt的下标;最后3位包括了程序是否在内存中,以及程序的在CPU中的运行级别。指向的gdt是一个以64位单位的表,在这张表中保存着程序运行的代码段、数据段的起始地址,以及与此相应的段限和页面交换还有程序运行级别,还有内存粒度等的信息。一旦这个程序发生了越界访问,CPU就会产生相应的异常保护,于是segment fault就出现了。
方法一:利用gdb逐步查找段错误
方法二:分析core文件
本人使用的RedHat 5的系统,禁止了core文件的生成。
使用ulimit -c查看一个系统core的大小限制
ulimit -c unlimited无限制
gcc -g test.c -o test
./test
出现段错误会显示 (段错误(core dump))
gdb test core
方法三:利用backtrace和objdump进行分析
1 #include <stdio.h> 2 #include <execinfo.h> 3 #include <stdlib.h> 4 #include <signal.h> 5 6 void dummy_function(void) 7 { 8 unsigned char * ptr = 0x00; 9 *ptr = 0x00; 10 } 11 12 void dump(int signo)//利用backstrace来打印信息 13 { 14 void *array[10]; 15 size_t size; 16 char **strings; 17 size_t i; 18 size = backtrace(array, 10); 19 strings = backtrace_symbols(array, size); 20 printf("Obtained %zd stack frames.\n", size); 21 22 for (i = 0; i < size; i++) 23 { 24 printf("%s\n", strings[i]); 25 } 26 27 free(strings); 28 exit(0); 29 } 30 31 32 int main() 33 { 34 signal(SIGSEGV, &dump); 35 dummy_function(); 36 37 return 0; 38 }
再结合objdump -d a.out反汇编,找出出错地址在哪个函数中(实在是看不懂,但是了解一下吧)