簡體   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