About Segmentation Fault in Linux ( SIGSEGV )

http://download.csdn.net/detail/doublewei1/4140866

刚拜读了一篇《Segmentation fault in linux.pdf》,下面是自己总结的一些内容

segmentation fault引发内核产生SIGSEGV信号;SIGSEGV是在访问内存时发生的错误,当用户态程序访问不允许访问内存,或者以错误的方式访问允许访问的内存时产生SIGSEGV。
     下面来说下常见的几种引发SIGSEGV的情况:
1. 错误的访问类型引发SIGSEGV
1 #include <stdio.h>
2 #include <stdlib.h>
3 int main() {
4     char * s = "hello world";
5     s [ 1 ] = 'H';
6
* 上面的函数引发SIGSEGV是因为“hello world”作为一个常量字符串,在编译链接后会放在ELF可执行目标文件的.rodata(存储只读数据,比如printf语句中的格式和开关语句的跳转表)部分,由于这片内存区域是只读的,这就引起可SIGSEGV.
2.访问了不属于进程地址空间的内存
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main() {
5     int * p = ( int *) 0xC0000fff;
6     *p = 10;
7 }
*    众所周知,linux地址空间顶部的四分之一是预留给内核的。即0xffffffff到0xc0000000是用户代码不可见的存储器,上述程序访问的0xc0000fff刚好访问的是这片地址空间。
3.访问了不存在的内存
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main () {
5     int * a = NULL;
6     * a = 1;
7 }
*   这个很显然呐....
4.栈溢出了,有可能引发SIGSEGV(栈溢出是缓存区溢出的一种)
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int * foo() {
05     int a = 10;
06
07     return & a;
08 }
09
10 int main() {
11     int * b;
12
13     b = foo();
14     printf ( "%d \n " , *b);
15 }
*     如上程序编译时会报:“warning: function returns address of local variable”,这是编译器在提醒你,该程序由栈溢出的危险。按照常理,&a在foo运行结束后应该被是释放,再以*b访问,相对于当前的程序是发生了栈溢出,但是该沉序实际运行正常,这是因为linux中典型的页的大小为4K,当栈溢的幅度小于页的大小时,不会产生SIGSEGV.
01 #include <stdio.h>
02 #include <stdlib.h>
03
04
05 char * foo() {
06      char buf [ 8192 ];
07
08      memset ( buf , 0x55 , sizeof( buf));
09      return buf;
10 }
11
12 int main() {
13      char * c;
14
15      c = foo();
16      printf ( "%#x \n " , c [ 5000 ]);
17 }
*    虽然上面程序的栈溢已经超出了 4K 大小,可运行仍然正常。这是因为 C 教程中提到的“栈自动释放”实际上是改变栈指针,而其指向的内存,并不是在函数返回时就被回收了。在我们的例子中,所访问的栈溢处内存仍然存在。无效的栈内存(即栈指针范围外未被回收的栈内存)是由操作系统在需要时回收的,这是无法预测的,也就无法预测何时访问非法的栈内容会引发 SIGSEGV。
*    再看下面的程序,它访问一个未分配的栈内存:
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 int main() {
05     char * c;
06
07     c = ( char *) & c 8192 * 2;
08     * c = 'a';
09     printf ( "%c \n " , * c);
10 }
*    该函数的栈溢为16K,但是我们依旧没有看到SIGSEGIV,这是因为在内核的page fault处理函数规定,栈溢小于64k左右都是没有问题的,栈会自动扩展。
5.关于堆
01 #include <stdio.h>
02 #include <stdlib.h>
03
04 #define K 1024
05 int main () {
06     char * c;
07     int i = 0;
08
09     c = malloc ( 1);
10     while ( 1) {
11        c += i * K;
12        * c = 'a';
13        printf ( "overflow %dK \n " , i);
14        i ++;
15     }
16 }
*    如上函数,对应malloc的大小不同,SIGSEGV推迟溢出的大小也不同。
*    再看一个:
01 #include <stdio.h>
02 #include <stdlib.h>
03 #define K 1024
04 int main () {
05     int * a;
06
07     a = malloc ( sizeof( int));
08     * a = 100;
09     printf ( "%d \n " , * a);
10     free ( a);
11     printf ( "%d \n " , * a);
12 }
*   上面的程序不一定会出现SIGSEGV,至于这其中的原委,看了栈溢出的话大家应该已经明白了吧:free后的内存空间不会立即归还给操作系统。
6.函数跳转到非法的地址上执行。
*   这个跟上次的那个缓存区溢出实验中
Featherain的做法 差不多,就是通过某种手段把函数的返回地址给改了...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值