全部博文(44)
分类:
2010-03-08 13:55:38
经常看到有帖子把两者混淆,而这两者的关系也确实微妙。在此,我们把指针运算(加减)引起的越界、野指针、空指针都归为指针越界。SIGSEGV在很多时候是由于指针越界引起的,但并不是所有的指针越界都会引发SIGSEGV。一个越界的指针,如果不解引用它,是不会引起SIGSEGV的。而即使解引用了一个越界的指针,也不一定会引起SIGSEGV。这听上去让人发疯,而实际情况确实如此。SIGSEGV涉及到操作系统、C库、编译器、链接器各方面的内容,我们以一些具体的例子来说明。
1 #include
2 #include
3
4 int main() {
5 char* s = "hello world";
6
7 s[1] = 'H';
8 }
这是最常见的一个例子。想当年俺对C语言懵懂的时候,也在校内的BBS上发帖问过,当时还以为这是指针和数组的区别。此例中,”hello world”作为一个常量字符串,在编译后会被放在.rodata节(GCC),最后链接生成目标程序时.rodata节会被合并到text segment与代码段放在一起,故其所处内存区域是只读的。这就是错误的访问类型引起的SIGSEGV。
其在图2中的顺序为:
1 -à 3 -à 4 -à 6 -à 8 -à 11 -à10
1 #include
2 #include
3
4 int main() {
5 int* p = (int*)0xC0000fff;
6
7 *p = 10;
8 }
在这个例子中,我们访问了一个属于内核的地址(IA32,32bit)。当然,很少会有人这样写程序,但你的程序可能在不经意的情况下做出这样的行为(这个不经意的行为在后面讨论)。此例在图2的流程:
1 -à 2 -à 11 -à 10
最常见的情况不外乎解引用空指针了,如:
1 #include
2 #include
3
4 int main () {
5 int *a = NULL;
6
7 *a = 1;
8 }
在实际情况中,此例中的空指针可能指向用户态地址空间,但其所指向的页面实际不存在。其产生SIGSEGV在图2中的流程为:
1 à 3 -à 4 -à 5 -à 11 -à10