C getline()与fgets():控制内存分配
要从文件中读取行,有C getline()与fgets():控制内存分配,c,posix,C,Posix,要从文件中读取行,有getline()和fgets()POSIX函数(忽略可怕的gets())。常识是,getline()优于fgets(),因为它根据需要分配行缓冲区 我的问题是:这不是很危险吗?如果由于意外或恶意,有人创建了一个100GB的文件,其中没有'\n'字节,那会不会使我的getline()调用分配了大量内存 我的问题是:这不是很危险吗?如果是意外或恶意的呢 意图有人创建一个100GB文件,其中没有“\n”字节–不会 这使得我的getline()调用分配了大量内存 是的,你所描述的是
getline()
和fgets()
POSIX函数(忽略可怕的gets()
)。常识是,getline()
优于fgets()
,因为它根据需要分配行缓冲区
我的问题是:这不是很危险吗?如果由于意外或恶意,有人创建了一个100GB的文件,其中没有'\n'
字节,那会不会使我的getline()
调用分配了大量内存
我的问题是:这不是很危险吗?如果是意外或恶意的呢
意图有人创建一个100GB文件,其中没有“\n”字节–不会
这使得我的getline()调用分配了大量内存
是的,你所描述的是一个似是而非的风险。但是,
- 如果程序需要一次将整行加载到内存中,那么允许
尝试这样做并不比使用getline()
fgets()编写自己的代码更危险;及
- 如果您的程序存在这样的漏洞,那么您可以通过使用
限制它可以保留的(虚拟)内存总量来降低风险。这可以用来导致它失败,而不是成功地分配足够的内存来干扰系统的其余部分setrlimit()
getline()
为您重新分配缓冲区,以稍微减轻程序中的内存管理
但事实上,这可能会导致分配大量内存。如果这是一个问题,那么您应该采取额外的步骤来使用不隐式分配内存的函数。这可能很危险,是的。不知道这在其他计算机上如何工作,但运行下面的代码会将我的计算机冻结到需要硬重置的程度:
/* 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;
}
/*危险代码*/
#包括
内部主(空)
{
文件*f;
char*s;
尺寸n=0;
f=fopen(“/dev/zero”,“r”);
getline(s&n,f);
返回0;
}
函数getline
在内部使用malloc
和realloc
并在失败时返回-1,因此结果与尝试调用malloc(10000000000)
时没有什么不同。也就是说,errno
设置为ENOMEM
,而getline
返回-1
因此,无论您是使用
getline
还是尝试使用fgets
和手动内存分配来确保读取完整的行,您都会遇到相同的问题。实际上,这取决于您希望如何处理过长的行
fgets
具有适当大小的缓冲区通常可以工作,并且您可以检测到它已“失败”-缓冲区端没有换行符。可以避免总是使用strlen()来确认缓冲区是否溢出,但这是另一个问题
也许您的策略是跳过无法处理的行,或者可能该行的其余部分只是一条您无论如何都会忽略的注释,在这种情况下,很容易将fgets
放入一个循环中,以丢弃该行的其余部分,而不会产生分配惩罚
如果您确实希望阅读整行内容,那么getline
可能是更好的策略。恶意用户将需要大量磁盘空间来导致您描述的不良行为,或者可能传递/dev/random或类似的输入文件名
同样,如果getline
无法realloc,它将以一种您可以恢复的方式失败,尽管如果您将缓冲区重新用于多行读取,您可能希望在尝试读取更多内容之前释放错误后的缓冲区,因为它仍然被分配,并且在失败之前可能已经增长到最大。一些编码准则(如MISRA C)可能会阻止您使用动态内存分配(如getline()
)。这是有原因的,例如避免内存泄漏
若您知道所有可接受行的最大大小,那个么您可以通过使用
fgets()
而不是getline()
,来避免内存分配,从而删除一个潜在的内存泄漏点。这不取决于实现吗?当然。我担心的是,我的系统可能会切换到停滞的地步。使用fgets()
这是不可能的。我想知道我是否误解了什么,或者是否知道getline()
的这种风险。内存量太大了
-100GB内存量太大了吗?是100KB吗?是1PB吗?告诉20年后的某个人。。。。有多少记忆是疯狂的,有多少不是getline()
是上世纪90年代的一个函数。它的存在是为了“让生活更轻松”,而不是“处理用户想要的所有疯狂案例”。编写具有最大限制的getline()
实现并不是那么难。@KamilCuk分别是、否和是。20年后,答案将是否定、否定和肯定。在以后的几年里,构成疯狂内存量的确切阈值肯定会增加,但潜在的问题是(存在导致内存不足或抖动的线条)将存在于任何有限内存系统上。@KamilCuk:一个包含100GB记录但没有长度前缀的文件的概念似乎有点疯狂,不管目标计算机有多少内存。除了fgets()
和手动分配您可以在进程的整个内存耗尽之前选择退出。实际上,这种行为与只调用malloc(100000000000)
非常不同,因为getline()
将首先分配一个小的大小,然后逐步重新分配到它找到新行的位置,文件或内存lim的结尾