从文件读取时如何停止堆栈缓冲区溢出?

理查德

我正在读取.txt文件,将其保存到char与文件本身大小相同数组中。这足以阻止不受控制的堆栈缓冲区溢出的发生吗?

我已经尝试过使用固定大小的缓冲区,但是现在我知道这就是发生溢出的原因。

FILE *inputFP = NULL;

inputFP = fopen(input_file, "r");
if (inputFP == NULL)
    return 1;
fseek(inputFP, 0, SEEK_END);
long fileSize = ftell(inputFP);
fseek(inputFP, 0, SEEK_SET);
char buffer[fileSize+20];

while ((ch = fgetc(inputFP)) != EOF) 
{
     buffer[i] = ch;
     i++;
}

fprintf(outputFP, buffer, "%s");

一切正常,但是我担心输入文件太大,以至于发生不好的情况。

史蒂夫·萨米特(Steve Summit)

限制缓冲区溢出的方法是仔细控制写入任何缓冲区的内存量。

如果您说(用伪代码):

filesize = compute_file_size(filename);
buffer = malloc(filesize);
read_entire_file_into(buffer, filename);

那么您就会遇到一个巨大的,巨大的,潜在的缓冲区溢出问题。根本的问题不是您分配的缓冲区恰好与文件的大小完全匹配(尽管这可能是一个问题)。问题不在于您事先计算了文件的大小(尽管这可能是一个问题)。不,根本的问题是在假设的调用中

read_entire_file_into(buffer, filename);

您没有告诉read_entire_file_into函数缓冲区有多大这可能是read_entire_file_into函数的问题,而不是您的问题,但最重要的是,将任意数量的数据写入固定大小的缓冲区而不允许指定该缓冲区的大小的函数正在等待灾难的发生。这就是为什么臭名昭著的gets()功能已从C标准中删除的原因这就是为什么不建议使用该strcpy功能,并且只能在经过仔细控制的情况下使用(如果有的话)的原因。这就是不建议使用%s%[...]格式说明符scanf的原因。

另一方面,如果您的代码看起来像这样:

filesize = compute_file_size(filename);
buffer = malloc(some_random_number);
read_entire_file_into_with_limit(buffer, some_random_number, filename);

-关键是要再次read_entire_file_into_with_limit告知(假设的)函数缓冲区的大小-在这种情况下,即使compute_file_size函数得到了错误的答案,即使您使用完全不同的大小buffer,您也可以ve确保不会溢出缓冲区。

从假设的伪代码转变为真实的实际代码:您没有显示代码中实际从文件中读取内容的部分。如果您正在调用freadfgets读取文件,并且正确地将fileSize变量作为大小传递给这些函数buffer,那么您已充分保护自己免受缓冲区溢出的侵害。但是,另一方面,如果您正在调用gets,或getc循环调用并向其中写入字符,buffer直到到达为止EOF(但不检查反对的字符数fileSize),那么您确实有很大的潜在缓冲区溢出问题,并且您需要重新考虑策略并重新编写代码。


您的代码存在第二个问题,即您将缓冲区作为可变长度数组(VLA)分配到堆栈上(可以这么说)。但是真正的大型堆栈分配数组将失败-不是因为缓冲区溢出,而是因为它们实际上太大了。因此,如果您实际上想将整个文件读入内存,则肯定要使用malloc,而不是VLA。(而且,如果您不介意依赖于操作系统的解决方案,则可能需要研究内存映射文件技术,例如mmap调用。)


您已更新代码,因此现在我可以更新此答案。您发布的文件读取循环很危险-实际上,这正是我写这篇文章时所想到的

调用getc循环并将字符写入缓冲区,直到到达为止EOF(但不检查根据读取的字符数fileSize

您应该用以下任一代码替换该代码

while ((ch = getc(inputFP)) != EOF) 
{
     if(i >= fileSize) {
         fprintf(stderr, "buffer overflow!\n");
         break;
     }

     buffer[i] = ch;
     i++;
}

要么

while ((ch = getc(inputFP)) != EOF && i < fileSize) 
{
     buffer[i] = ch;
     i++;
}

或者,您可以采用完全不同的方法。大多数时候,不需要一次将整个文件读入内存。在大多数情况下,一次读取一行,一次读取一个块,甚至一次读取一个字符,处理并写出每个片段然后再进行下一个片段就足够了。这样,您可以处理任何大小的文件,而无需事先弄清楚文件的大小,也不需要分配大的缓冲区,也不需要担心溢出该缓冲区。

我今天没有时间向您展示如何执行此操作,但是在其他一些答案中也有提示和建议。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

尝试缓冲区溢出

来自分类Dev

GCC如何检测堆栈缓冲区溢出

来自分类Dev

防止缓冲区溢出

来自分类Dev

发生缓冲区溢出

来自分类Dev

当缓冲区未满时,为什么字节缓冲区会给出缓冲区溢出异常

来自分类Dev

堆栈上的缓冲区溢出

来自分类Dev

堆栈地址不对应(试图了解缓冲区溢出)

来自分类Dev

利用缓冲区溢出读取操作

来自分类Dev

缓冲区溢出实现

来自分类Dev

查找堆栈缓冲区溢出

来自分类Dev

读取pandas中的csv文件时出错[CParserError:标记数据时出错。C错误:捕获到缓冲区溢出-可能是格式错误的输入文件。

来自分类Dev

读取文件缓冲区通过

来自分类Dev

缓冲区溢出漏洞

来自分类Dev

试验缓冲区溢出

来自分类Dev

应该如何读取堆缓冲区溢出错误消息?

来自分类Dev

执行不在堆栈上的shellcode(缓冲区溢出)

来自分类Dev

利用堆栈缓冲区溢出

来自分类Dev

利用堆栈缓冲区溢出

来自分类Dev

当缓冲区未满时,为什么字节缓冲区会给出缓冲区溢出异常

来自分类Dev

关于堆栈缓冲区溢出漏洞

来自分类Dev

如何在到达缓冲区而不是缓冲区已满时读取缓冲区中的数据?

来自分类Dev

如何使Emacs在启动时从stdin读取缓冲区?

来自分类Dev

如何实现缓冲区溢出

来自分类Dev

基于堆栈的缓冲区溢出

来自分类Dev

缓冲区溢出漏洞

来自分类Dev

此代码如何使缓冲区溢出

来自分类Dev

堆栈缓冲区溢出检测机制?

来自分类Dev

C 堆栈缓冲区溢出

来自分类Dev

C中的堆栈粉碎/缓冲区溢出