Error
当硬件告诉操作系统一个有问题的内存引用时,就会出现这两种错误。操作系统通过向出错的进程发送一个信号与之交流。进程收到“bus error”或“segmentation fault”信号后将进行信息转储并终止。不过可以为这些信号设置一个信号处理程序(signal handler),用于修改进程的缺省反应。
bus error (core dumped) 总线错误
- CPU对进程引用内存的一些做法不满
- 事实上,总线错误几乎都是由于未对齐的读或写引起的。之所以称为总线错误,是因为出现未对齐的内存访问的请求时,被堵塞的组件就是地址总线。
- alignment(对齐)的意思就是:数据项只能存储在地址是数据项大小的整数倍的内存位置上。
- 通过博士每个内存访问局限在一个Cache行货一个单独的页面内,可以极大的简化(并加速)如Cache控制器和内存管理单元这样的硬件。
- 访问一个8字节的double数据时,地址只允许是8的整数倍。所以一个double数据可以存储于地址24、8008、32768,但不能存储于地址1006(因为它无法被8整除)。
- example
union{
char a[10];
int i;
}u;
int *p = (int *)&(u.a[1]);
* p = 17; /*p中未对齐的地址会引起一个总线错误!*/
- 上述总线错误,因为数组和int的联合确保数组a是按照int的4字节对齐的,所以“a+1”的地址肯定未按int对齐。然后我们试图往这个地址存储4个字节的数据,但这个访问只是按照单字节的char对齐,这就违反了规则。
- 总线错误也可能是由于引用一块物理上不存在的内存引起的。
segmentation fault(core dumped)段错误
MMU对进程引用内存的一些情况发出抱怨。
几个直接的原因:
- 解引用一个包含非法值的指针。
- 解引用一个空指针(常常由于从系统程序中返回空指针,并未经检查就使用)。
- 在未得到正确的权限时进行访问。例如,试图往一个只读的文本端存储值就会引起段错误。
- 用完了堆栈或堆空间。
以发生频率为序:
1.坏指针值错误:
1.1 在指针赋值之前就用它来引用内存
1.2 向库函数传送一个坏指针
1.3 对指针进行释放之后再访问它的内容,可以修改free语句,在指针释放后再将它置位空值。
free(p);
p = NULL;
2.改写(overwrite)错误:
2.1 越过数组边界写入数据
2.2. 在动态分配的内存两端之外写入数据,或改写一些堆管理数据结构
p=malloc(256); p[-1]=0; p [256]= 0;
3.指针释放引起的错误
3.1 释放同一个内存块2次
3.2 释放一块未曾使用malloc分配的内存
3.3 释放仍在使用中的内存
3.4 释放一个无效的指针
//如何在链表中释放元素
/*
在遍历链表时正确释放元素的方法是使用临时变量存储下一个元素的地址,这样就可以安全地在任何时候释放当前元素,不必担心在取一下一个元素的地址时还要引用它。
*/
struct node *p, *start, *tmp;
for(p =start;p; p = tmp)
{
tmp = p ->next;
free(p);
}
软件信条
程序所用的内从超过了系统能提供的数量,这在任务堆栈中也适用(某个任务在创建时定义了任务的堆栈),程序就会发出一条“段错误”信息并终止。如何区别这种错误和其他基于Bug的段错误。即弄清楚程序是否已用完了堆栈,如何查看。