繁体   English   中英

为什么当我溢出分配的字符数组时,我的C程序不会崩溃?

[英]How come my C program doesn't crash when I overflow an allocated array of characters?

我有一个简单的C文件I / O程序,它演示了逐行读取文本文件,并将其内容输出到控制台:

/**
* simple C program demonstrating how
* to read an entire text file
*/

#include <stdio.h>
#include <stdlib.h>

#define FILENAME "ohai.txt"

int main(void)
{
    // open a file for reading
    FILE* fp = fopen(FILENAME, "r");

    // check for successful open
    if(fp == NULL)
    {
        printf("couldn't open %s\n", FILENAME);
        return 1;
    }

    // size of each line
    char output[256];

    // read from the file
    while(fgets(output, sizeof(output), fp) != NULL)
        printf("%s", output);

    // report the error if we didn't reach the end of file
    if(!feof(fp))
    {
        printf("Couldn't read entire file\n");
        fclose(fp);
        return 1;
    }

    // close the file
    fclose(fp);
    return 0;
   }

看起来我已经为每行分配了一个空间为256个字符的数组(32位机器上的1024 字节 位)。 即使我在第一行填写的文本超过1000个字符的ohai.txt ,程序也不会出现段错误,我认为它会溢出,因为它溢出了output[]数组指定的可用空间。 。

我的假设是操作系统会为程序提供额外的内存,同时它有额外的内存可用。 这意味着只有当ohai.txt的一行文本占用的内存导致ohai.txt时,程序才会崩溃。

有更多C和内存管理经验的人是否支持或反驳我的假设,即为什么这个程序不会崩溃,即使文本文件的一行中的字符数远大于256?

你不会在这里溢出任何内容: fgets不会向sizeof(output)字符写入缓冲区,因此不会溢出任何内容(参见文档 )。

但是,如果溢出缓冲区,则会出现未定义的行为。 根据C规范,程序可能会做任何事情 :崩溃,不崩溃,无声地破坏重要数据,意外调用rm -rf /等等。因此,如果调用UB,不要指望程序崩溃。

OP的程序没有崩溃,因为没有缓冲区溢出发生。

while(fgets(output, sizeof(output), fp) != NULL)
  printf("%s", output);

fgets()很好地读取一组char到一个或255或一个\\n的计数。 然后printf("%s" ...很好地将它们打印出来。重复这一过程,直到没有更多的数据/

没有崩溃,没有溢出,没有运行,没有命中,没有错误。

fgets(output,sizeof(output),fp)读取(sizeof(输出)-1)这种情况下的字符数(否则读取直到换行符或文件末尾)

堆栈的解释以及为什么即使你实际上溢出也不会发生段错误(并且正如其他人已指出所写的代码不会)

你的堆栈指针从某个地址开始,比如说0x8000000,然后运行时调用main,它会向下移动一点(可能还有其他的东西,所以我们不知道在main的开头有多少东西在堆栈上),然后main将为所有它的局部变量移动堆栈指针。 所以在这一点上你的数组将有一个低于0x8000000超过256字节的地址,除非你在所有main的堆栈帧和任何其他C运行时东西的堆栈帧上运行,否则你不会得到段错误。

因此,为了简单起见,假设您的数组最终得到的是0x7fffd00的基地址,即低于0x8000000的768字节,这意味着至少你必须溢出那么多以获得段错误(好吧,你可能会遇到段错误)主要返回或当你调用feof时,因为你用随机字符填充你的堆栈框架,但是我们正在讨论fgets()中的段错误,但即使那些可写的东西被映射到堆栈上方的页面也是如此(不太可能是大多数操作系统)避免这样做,这样如果你溢出得足够远,你会得到一个段错误)

如果堆栈以另一种方式运行(即:向上增长),则必须运行整个最大大小的堆栈,在用户空间中通常非常大(Linux上的默认值为32位x86是2MB)但我很漂亮确保x86堆栈向下增长,这样你的情况就不太可能了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM