c - 条件跳转或移动取决于使用 fread() 后未初始化的值
问题描述
出于某种原因,这个超级简单的代码给了我一个 valgrind 错误。代码摘录:
char* readFile(char* filename){
FILE * f = fopen (filename, "rb");
if (f){
printf("sucessfully opened file\n");
fseek (f, 0, SEEK_END);
int length = ftell (f);
fseek (f, 0, SEEK_SET);
char* buffer = malloc (length*2); <- line 109
if (buffer){
printf("in here");
fread (buffer, 1, length, f);
}
fclose (f);
buffer[length+1]='\0';
printf("buffer: %s",buffer); <- line 116
瓦尔格林:
==102== Memcheck, a memory error detector
==102== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==102== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==102== Command: ./run
==102==
==102== error calling PR_SET_PTRACER, vgdb might block
inputting file:
sucessfully opened file
==102== Conditional jump or move depends on uninitialised value(s)
==102== at 0x483EF58: strlen (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==102== by 0x48CEE94: __vfprintf_internal (vfprintf-internal.c:1688)
==102== by 0x48B7EBE: printf (printf.c:33)
==102== by 0x40172C: readFile (functions.c:116)
==102== by 0x403108: main (functions.c:649)
==102== Uninitialised value was created by a heap allocation
==102== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==102== by 0x4016BB: readFile (functions.c:109)
==102== by 0x403108: main (functions.c:649)
==102==
我的一个较大程序的一部分是这个函数,它读取文件并将其内容存储在缓冲区中。这是程序做的第一件事,所以我在其他地方遇到的错误不应该真正影响这里的行为。帮助将不胜感激。
解决方案
你有一个错误的错误。您将length
字节读入元素buffer[0]...buffer[length-1]
(从零开始的数组,请记住),因此终止的空字符应该进入buffer[length]
. 但是你把它放进去buffer[length+1]
,所以printf
第 116 行试图打印buffer[length]
从未被覆盖的垃圾字符。
另一个问题是fread
可能会失败,或者读取的字节数少于length
字节。如果发生这种情况,剩余的字节buffer
不会被覆盖,然后printf
将尝试打印未初始化的数据。您需要检查 的返回值fread
以查看成功读取了多少字节,如果小于 则做出相应的响应length
。
最后,如果malloc
应该失败,它将设置buffer
为 NULL。然后buffer[length+1] = '\0'
将取消引用与 null 相关的指针,从而导致未定义的行为。您需要更改逻辑以正确处理malloc
返回 NULL,并且buffer
在这种情况下不取消引用或打印。
推荐阅读
- python-3.x - 从嵌套字典的子集字典创建字典
- ios - 在 UICollectionView 中动态插入 Item
- amazon-web-services - CDK 将 API Gateway 堆栈拆分为 2 个小堆栈
- regex - 在 ibm watson 中实体的电子邮件识别模式中,术语 {2, } 在这里表示什么?
- assembly - 为什么在执行 pushl 指令时 rA:rB 是 2:8 而不是 2:f?
- git - 如何计算在 git 中更改一行的提交数?
- vb.net - 在多个控件内的禁用按钮上显示工具提示
- assembly - 需要一个很好的汇编语言代码解释(8086 微处理器)
- c++ - 生成 constexpr 字符串表,不能产生常量表达式
- r - 如何并行化crossprod以计算共现矩阵?