为什么下面的代码在运行时没有崩溃?
而且大小完全取决于机器/平台/编译器!!。我甚至可以在一台64位的机器上给200个。如何在操作系统中检测到主函数中的分段错误?

int main(int argc, char* argv[])
{
    int arr[3];
    arr[4] = 99;
}

这个缓冲空间是从哪里来的?这是分配给进程的堆栈吗?

最佳答案

我以前为了教育目的写的东西…
考虑以下C程序:

int q[200];

main(void) {
    int i;
    for(i=0;i<2000;i++) {
        q[i]=i;
    }
}

编译并执行后,将生成一个核心转储:
$ gcc -ggdb3 segfault.c
$ ulimit -c unlimited
$ ./a.out
Segmentation fault (core dumped)

现在使用gdb执行尸检后分析:
$ gdb -q ./a.out core
Program terminated with signal 11, Segmentation fault.
[New process 7221]
#0  0x080483b4 in main () at s.c:8
8       q[i]=i;
(gdb) p i
$1 = 1008
(gdb)

嗯,当一个程序在分配的200个项目之外写时,它没有segfault,而是在i=1008时崩溃,为什么?
输入页面。
在UNIX/Linux上,可以通过多种方式确定页面大小,一种方式是使用系统函数sysconf(),如下所示:
#include <stdio.h>
#include <unistd.h> // sysconf(3)

int main(void) {
    printf("The page size for this system is %ld bytes.\n",
            sysconf(_SC_PAGESIZE));

    return 0;
}

它给出了输出:
此系统的页面大小为4096字节。
或者可以使用命令行实用程序getconf,如下所示:
$ getconf PAGESIZE
4096

死后
结果表明,segfult不是发生在i=200处,而是发生在i=1008处,让我们找出原因。启动GDB进行尸检分析:
$gdb -q ./a.out core

Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
[New process 4605]
#0  0x080483b4 in main () at seg.c:6
6           q[i]=i;
(gdb) p i
$1 = 1008
(gdb) p &q
$2 = (int (*)[200]) 0x804a040
(gdb) p &q[199]
$3 = (int *) 0x804a35c

q结束于地址0x804a35c,或者更确切地说,q[199]的最后一个字节在该位置。页面大小如我们之前看到的4096字节,机器的32位字大小使虚拟地址分解为20位页码和12位偏移量。
q[]以虚拟页码结尾:
0x804A=32842
抵消:
0x35C=860
所以仍然有:
4096-864=3232
在分配了q[]的内存页上剩余的字节数。空间可以容纳:
3232/4=808
整数,代码将其视为在位置200到1008处包含q元素。
我们都知道,这些元素不存在,编译器没有抱怨,HW也没有,因为我们对那个页面有写权限。只有当i=1008时,q[]引用了另一个页面上我们没有写权限的地址,虚拟内存hw才检测到这一点并触发segfault。
整数存储在4个字节中,这意味着此页包含808(3236/4)个附加的伪元素,这意味着在不触发SEG故障的情况下,从q[200]、q[201]一直到元素199+808=1007(q[1007])访问这些元素仍然是完全合法的。访问q[1008]时,您将进入一个权限不同的新页面。

关于c - 当我写完数组末尾时,为什么程序不会崩溃?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6452959/

10-13 08:39