簡體   English   中英

getline()與fgets():控制內存分配

[英]getline() vs. fgets(): Control memory allocation

要從文件中讀取行,可以使用getline()fgets() POSIX函數(忽略可怕的gets() )。 常識是getline()fgets()fgets()因為它根據需要分配行緩沖區。

我的問題是:這不危險嗎? 如果出於偶然或惡意的意圖,有人創建了一個沒有'\\n'字節的100GB文件,那會不會讓我的getline()調用分配一個瘋狂的內存量?

我的問題是:這不危險嗎? 如果出於偶然或惡意的意圖,有人創建了一個沒有'\\ n'字節的100GB文件,那會不會讓我的getline()調用分配一個瘋狂的內存量?

是的,你所描述的是一種看似合理的風險。 然而,

  • 如果程序需要一次將整行加載到內存中,那么允許getline()嘗試這樣做本身並不比使用fgets()編寫自己的代碼更危險;
  • 如果您的程序存在此類漏洞,則可以通過使用setrlimit()限制其可以保留的(虛擬)內存總量來降低風險。 這可以用於使其失敗,而不是成功分配足夠的內存來干擾系統的其余部分。

我認為,最好的整體是編寫不需要以實線為單位輸入的代碼(一次全部),但這種方法有其自身的復雜性。

這可能很危險,是的。 不知道這在其他計算機上是如何工作的,但運行下面的代碼會凍結我的計算機到需要硬重置的程度:

/* DANGEROUS CODE */

#include <stdio.h>

int main(void)
{
    FILE *f;
    char *s;
    size_t n = 0;

    f = fopen("/dev/zero", "r");
    getline(&s, &n, f);

    return 0;
}

getline函數在內部使用mallocrealloc ,如果失敗則返回-1,因此結果與嘗試調用malloc(100000000000)沒有區別。 即, errno設置為ENOMEMgetline返回-1。

因此,無論您是使用getline還是嘗試使用fgets和手動內存分配執行相同的操作,您都會遇到同樣的問題,以確保您閱讀完整行。

某些編碼指南(如MISRA C)可能會阻止您使用動態內存分配(如getline() )。 這是有原因的,例如避免內存泄漏。

如果您知道所有可接受行的最大大小,那么可以使用fgets()而不是getline()來避免內存分配,從而刪除一個潛在的內存泄漏點。

getline()為您重新分配緩沖區,以減輕程序中的內存管理。

但實際上,這可能導致分配大量內存。 如果這是一個問題,那么您應該采取額外的步驟來使用不隱式分配內存的函數。

真的,這取決於你想要處理太長的行。

具有合適大小的緩沖區的fgets通常會工作,並且您可以檢測到它已“失敗” - 緩沖區末端沒有換行符。 可以避免總是使用strlen()來確認緩沖區是否溢出,但這是一個不同的問題。

也許你的策略是簡單地跳過無法處理的行,或者行的其余部分只是你無論如何都會忽略的注釋,在這種情況下,很容易將fgets放入循環中以丟棄其余的這條線沒有分配罰金。

如果您確實想要讀取整行,那么getline對您來說可能是更好的策略。 惡意用戶需要大量磁盤空間才能導致您描述的不良行為,或者可能傳遞/ dev / random或類似輸入文件名。

同樣,如果getline無法重新分配,它將以您可以恢復的方式失敗,但是如果您正在重復使用緩沖區進行多行讀取,則可能需要在嘗試讀取之前釋放它在錯誤之后具有的緩沖區更多,因為它仍然被分配,並且可能在失敗之前增長到盡可能大。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM