关闭

段错误(Segment Fault!)莫名的问题 by fish

656人阅读 评论(0) 收藏 举报
 

段错误或段违规(segmentation violation)应该已经很清楚,之前有过一篇文章介绍过“段模型”。

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

int *p = 0;
*p = 17;     //引起一个段错误

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

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


 

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

(1)解除引用一个包含非法值的指针;

(2)解除引用一个空指针(常常由于从系统程序中返回空指针,并未经检查就使用)。

(3)在未得到正确的权限时进行访问。例如,试图往一个只写的文本段存储值就会引起段错误。

(4)用完了堆栈或堆空间(虚拟内存虽然巨大但绝非无限)。

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

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

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

free(p);  p = NULL;

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

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

p = malloc(256);  p[-1] = 0;  p[256] = 0;

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

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7712次
    • 积分:162
    • 等级:
    • 排名:千里之外
    • 原创:10篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章存档
    最新评论