更新时间:2023-11-29 22:34
段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gd tr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的 gdt表,后13位保存 相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向 的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起 始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。
A segmentation fault (often shortened to segfault) is a particular error condition that can occur during the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (e.g., attempts to write to a read-only location, or to overwrite part of the operating system). Systems based on processors like the Motorola 68000 tend to refer to these events as Address or Bus errors.
On Unix-like operating systems, a process that accesses invalid memory receives the SIGSEGV signal. On Microsoft Windows, a process that accesses invalid memory receives the STATUS_ACCESS_VIOLATION exception.
另外,这里有个基本上对照的中文解释,来自库扩展阅读1;
一旦一个程序发生了越界访问,cpu就会产生相应的保护,于是segmentation fault就出现
了通过上面的解释,段错误应该就是访问了不可访问的内存,这个内存区要么是不存在的,
要么是受到系统保护的,还有可能是缺少文件或者文件损坏。
在编程中以下几类做法容易导致段错误,基本上是错误地使用指针引起的。
(1)访问系统数据区,尤其是往系统保护的内存地址写数据最常见就是给一个指针以0地址。
(2)内存越界(数组越界,变量类型不一致等): 访问到不属于你的内存区域。
下面将就以下的一个存在段错误的程序介绍几种调试方法:
出错并退出。作为一个熟练的C/C++程序员,以上代码的bug应该是很清楚的,因为它尝试操作地址为0的内存区域,而这个内存区域通常是不可访问的禁区,当然就会出错了。我们尝试编译运行它:
这种方法也是被大众所熟知并广泛采用的方法,首先我们需要一个带有调试信息的可执行程序,所以我们加上“-g -rdynamic”的参数进行编译,然后用gdb调试运行这个新编译的程序,具体步骤如下:
不用一步步调试我们就找到了出错位置d.c文件的第4行,其实就是如此的简单。
从这里我们还发现进程是由于收到了SIGSEGV信号而结束的。通过进一步的查阅文档(man 7 signal),我们知道SIGSEGV默认handler的动作是打印“段错误”的出错信息,并产生Core文件,由此我们又产生了方法二。
以 上资料摘自man page(man 5 core)。不过奇怪了,我的系统上并没有找到core文件。后来,忆起为了渐少系统上的垃圾文件的数量,禁止了core文件的生成,查看了以下果真如此,将系统的core文件的大小限制在512K大小,再试:
利用backtrace和objdump进行分析
xiaosuo@gentux test $ ./a.out
Obtained 5 stack frames.
./a.out(dump+0x19) [0x80486c2]
[0xffffe420]
./a.out(main+0x35) [0x804876f]
1,
被装载时,系统把“hello world” 连同其它的字符串和const型数据放入到内存的只读区。执行时,一个变量s被设为指向该字符串的位置,当再试图向该位置写时,就会产生段错误。
2,
因为该代码只创建了一个空指针,并没有指向一个具体空间,当赋值时,产生段错误。
3,