关于segmentfault
时间:2010-03-17 来源:sandflee
SIGSEGV 在何时发生,即“当程序试图访问不被允许访问的内存区域
(比如,尝试写一块属于操作系统的内存),或以错误的类型访问内存区域(比如,尝试写
一块只读内存).
有一个常见的误解,linux为进程分配内存的时候,分配的不是实际的物理内存,而只是一个虚拟地址空间,但是你要一个字节的内存,os不可能傻乎乎的单独分配一个字节给你,而是有一大块内存分好了,映射到进程的地址空间,你访问的时候就通过这个地址空间访问吧。所以当你访问不属于进程地址空间的内容时会发生段错误,而不是访问没有申请的内存。
有几个有趣的例子
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 void foo () {
6 char c;
7
8 memset (&c, 0x55, 128);
9}
10
11 int main () {
12 foo();
13 }
因为stack是向下增长的,所以memset会把main的stack置成0x555555,函数返回的时候就跳到55555的地址,也就是说可以通过仔细分析stack的数据更改进程的行为,我曾经偶然打印出程序的环境变量,这东西应该不能改。
还有跳转到某个非代码区时为什么会受到sigsegv而不是sigill(非法指令)?因为x86是复杂指令级,很难找到一条无效的代码编码,往往是往某个非法地址空间操作,导致sigsegv
(比如,尝试写一块属于操作系统的内存),或以错误的类型访问内存区域(比如,尝试写
一块只读内存).
有一个常见的误解,linux为进程分配内存的时候,分配的不是实际的物理内存,而只是一个虚拟地址空间,但是你要一个字节的内存,os不可能傻乎乎的单独分配一个字节给你,而是有一大块内存分好了,映射到进程的地址空间,你访问的时候就通过这个地址空间访问吧。所以当你访问不属于进程地址空间的内容时会发生段错误,而不是访问没有申请的内存。
有几个有趣的例子
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 void foo () {
6 char c;
7
8 memset (&c, 0x55, 128);
9}
10
11 int main () {
12 foo();
13 }
因为stack是向下增长的,所以memset会把main的stack置成0x555555,函数返回的时候就跳到55555的地址,也就是说可以通过仔细分析stack的数据更改进程的行为,我曾经偶然打印出程序的环境变量,这东西应该不能改。
还有跳转到某个非代码区时为什么会受到sigsegv而不是sigill(非法指令)?因为x86是复杂指令级,很难找到一条无效的代码编码,往往是往某个非法地址空间操作,导致sigsegv
相关阅读 更多 +