开始试验。试验 1,下面代码相当于楼主第 2 个例子。
代码: 全选
#include <stdio.h>
#include <stdlib.h>
int main() {
char h = 128;
int i = 0;
for( i = 0; i < 135200; i++ ) {
fprintf( stderr, "h[%d]: %d\n", i, *( &h + i ) );
}
return 0;
}
用 gdb 运行。
代码: 全选
$ gcc -g -Wall -o test test.c
$ gdb ./test
GNU gdb (GDB) 7.4.1-debian
...# 省略。
(gdb) r
Starting program: /tmp/test
h[0]: -128
...# 省略。
h[3156]: 0
Program received signal SIGSEGV, Segmentation fault.
0x08048466 in main () at test.c:9
9 fprintf( stderr, "h[%d]: %d\n", i, *( &h + i ) );
(gdb) p &h
$1 = 0xbffff3ab "\200U\f"
(gdb) p &h + i
$2 = 0xc0000000 <Address 0xc0000000 out of bounds>
(gdb)
重复试验的结果相同,h 的地址总是 0xbffff3ab,当 i = 3157 时发生段错误。因为此时 &h + i = 0xc0000000,已经对应于操作系统的部分,所以会段错误,属于前述 1.。
不用 gdb 直接运行时,&h、发生段错误时的 i 和 &h + i 随不同试验而不同,原因我还不清楚。但估计段错误的原因也是 1.。
试验 1.1,同样是 test.c,不过把 &h + i 改成了 &h - i。
这时无段错误发生。改 stack 大小,减少到 64K。
代码: 全选
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 12050
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 12050
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
$ ulimit -c unlimited
$ ulimit -S -s 64
这时有段错误发生。
代码: 全选
h[62443]: 0
Program received signal SIGSEGV, Segmentation fault.
0x0804846a in main () at test.c:9
9 fprintf( stderr, "h[%d]: %d\n", i, *( &h - i ) );
(gdb) p &h
$1 = 0xbffff3eb "\200\354", <incomplete sequence \363>
(gdb) p &h - i
$2 = 0xbffeffff <Address 0xbffeffff out of bounds>
(gdb) p &h - i + 1
$3 = 0xbfff0000 ""
从 0xbfff0000 到 0xc0000000 恰好是 64K。按
这里,开始只给 h 分配了一个 char 的内存,当访问 h 附近的未分配内存时,内核会自动扩展 stack 而不发生段错误,当 stack 达到最大可用大小后才会生段错误。这属于前述 2. 的情况。多次重复结果相同。
不用 gdb 直接运行时,&h、发生段错误时的 i 和 &h - i 同样随不同试验而不同,原因我也不清楚。