c语言运行时出现segment fault的原因

segment fault段错误是在编程报错中经常出现的,特别是在c语言编程中,尤其常见,其原因本质上上是访问了非法(不属于这个程序)的内存地址空间,具体来说有以下几种情况:

  1. 局部变量定义中,使用了过大的局部变量,大于了系统给之的栈(stack)的大小,因此报错。比如以下代码在linux环境下,就可能出现段错误报错:
void foo(){
	float vars[10000][10000];
}

代码很简单,就是在栈上划出了一个很大的连续内存空间,翻译成汇编如:

mov $100000016, %rsp
# 还有多出的16个字节是上下文切换需要的内存,frame pointer %rbp, return address等,
# 同时如果用gcc等编译的,还要考虑其内存对齐的要求,即是其是16字节的倍数。

这个栈大小可能超出了系统给定每个程序的栈的大小,可以通过shell命令ulimit -s进行查看系统给定的栈大小,比如笔者的就是:

user@ubuntu: ulimit -s 
8192

注意这里都是以1024字节(1KB)为单位的,因此默认的就是8MB的栈大小,如果你的程序需要更大的栈空间,那么可以通过

ulimit -s 1000000

类似这样的命令去重定义最大的栈大小。

  1. stack overflow栈溢出
    C语言是没有对数组的边界检测的,这样在实际应用中常常会导致越界的问题,我们知道,程序的栈如下图所示:

在这里插入图片描述

考察以下代码:

void foo(){
	int vars[100];
	vars[100] = 0;
	vars[101] = 0;
	vars[102] = 0;
	vars[103] = 0;
}

当然,我们知道,我们对该数组vars只能检索到vars[99],因为其索引范围是[0,99],但是这种超出了理论上的索引边界(越界)的“低级错误”确是在实际代码中经常出现的bug的根源之一。从上图的程序栈我们可以看出,如果栈中的变量边界溢出,那么可能会对一些上下文信息,比如return address进行期望之外的修改,导致难以预料的错误(比如无法返回到调用函数,或者返回到不该返回的地址,这里容易被黑客进行栈溢出攻击),因此操作系统一般会检测这种段错误,同时报错segment fault

发布了127 篇原创文章 · 获赞 219 · 访问量 30万+

猜你喜欢

转载自blog.csdn.net/LoseInVain/article/details/104127334