简体   繁体   English

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

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

I have a simple C file I/O program which demonstrates reading a text file, line-by-line, an outputting its contents to the console: 我有一个简单的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;
   }

It looks like I've allocated an array with space for 256 characters per line (1024 bytes bits on a 32-bit machine). 看起来我已经为每行分配了一个空间为256个字符的数组(32位机器上的1024 字节 位)。 Even when I fill ohai.txt with more than 1000 characters of text on the first line, the program doesn't segfault, which I assumed it would, since it overflowed the allocated amount of space available to it designated by the output[] array. 即使我在第一行填写的文本超过1000个字符的ohai.txt ,程序也不会出现段错误,我认为它会溢出,因为它溢出了output[]数组指定的可用空间。 。

My hypothesis is that the operating system will give extra memory to the program while it has extra memory available to give. 我的假设是操作系统会为程序提供额外的内存,同时它有额外的内存可用。 This would mean the program would only crash when the memory consumed by a line of text in ohai.txt resulted in a stackoverflow. 这意味着只有当ohai.txt的一行文本占用的内存导致ohai.txt时,程序才会崩溃。

Could someone with more experience with C and memory management support or refute my hypothesis as to why this program doesn't crash, even when the amount of characters in one line of a text file is much larger than 256? 有更多C和内存管理经验的人是否支持或反驳我的假设,即为什么这个程序不会崩溃,即使文本文件的一行中的字符数远大于256?

You're not overflowing anything here: fgets won't write more than sizeof(output) characters to the buffer, and therefore will not overflow anything (see the documentation ). 你不会在这里溢出任何内容: fgets不会向sizeof(output)字符写入缓冲区,因此不会溢出任何内容(参见文档 )。

However, if you do overflow a buffer, you get undefined behaviour. 但是,如果溢出缓冲区,则会出现未定义的行为。 According to the C spec, the program may do anything : crash, not crash, silently destroy important data, accidentally call rm -rf / , etc. So, don't expect a program to crash if you invoke UB. 根据C规范,程序可能会做任何事情 :崩溃,不崩溃,无声地破坏重要数据,意外调用rm -rf /等等。因此,如果调用UB,不要指望程序崩溃。

OP's program did not crash because no buffer overflow occurred. OP的程序没有崩溃,因为没有缓冲区溢出发生。

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

The fgets() nicely read a group of char up to a count or 255 or a \\n . fgets()很好地读取一组char到一个或255或一个\\n的计数。 Then printf("%s" ... nicely printed them out. This repeated until no more data/ 然后printf("%s" ...很好地将它们打印出来。重复这一过程,直到没有更多的数据/

No crash, no overflow, no runs, no hits , no errors. 没有崩溃,没有溢出,没有运行,没有命中,没有错误。

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

Explanation of stacks and why this might not segfault even if you actually did overflow (and as others have pointed out the code as written will not) 堆栈的解释以及为什么即使你实际上溢出也不会发生段错误(并且正如其他人已指出所写的代码不会)

Your stack pointer starts at some address say 0x8000000 then the runtime calls main and it'll move down a bit (there may be other stuff up there so we don't know how much stuff is on the stack at the start of main), then main will move the stack pointer some more for all it's local variables. 你的堆栈指针从某个地址开始,比如说0x8000000,然后运行时调用main,它会向下移动一点(可能还有其他的东西,所以我们不知道在main的开头有多少东西在堆栈上),然后main将为所有它的局部变量移动堆栈指针。 So at this point your array will have an address that is more than 256 bytes below 0x8000000 and you won't get a segfault unless you run all the way over all of main's stack frame and the stack frames of whatever other C runtime stuff called main. 所以在这一点上你的数组将有一个低于0x8000000超过256字节的地址,除非你在所有main的堆栈帧和任何其他C运行时东西的堆栈帧上运行,否则你不会得到段错误。

So for the sake of simplicity assume your array ends up with it's base address at 0x7fffd00 that's 768 bytes below 0x8000000 meaning at a minimum you'd have to overflow by that much to get a segfault, (well you'd probably get a segfault when main returns or when you call feof, because you filled your stack frame with random characters, but we're talking about segfaults inside fgets()) but even that's not gaurenteed if something writable is mapped to the page above your stack (unlikely most OSs avoid doing that so you'll get a segfault if you overflow far enough) 因此,为了简单起见,假设您的数组最终得到的是0x7fffd00的基地址,即低于0x8000000的768字节,这意味着至少你必须溢出那么多以获得段错误(好吧,你可能会遇到段错误)主要返回或当你调用feof时,因为你用随机字符填充你的堆栈框架,但是我们正在讨论fgets()中的段错误,但即使那些可写的东西被映射到堆栈上方的页面也是如此(不太可能是大多数操作系统)避免这样做,这样如果你溢出得足够远,你会得到一个段错误)

If the stack runs the other way (ie: growing upward) you'd have to run over the entirety of the maximum size stack, which in userspace is usually quite large (Default on Linux for 32bit x86 is 2MB) but I'm pretty sure x86 stacks grow downward so that's not likely for your case. 如果堆栈以另一种方式运行(即:向上增长),则必须运行整个最大大小的堆栈,在用户空间中通常非常大(Linux上的默认值为32位x86是2MB)但我很漂亮确保x86堆栈向下增长,这样你的情况就不太可能了。

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

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