[英]No memory leak, but confusing errors from valgrind when using malloc and file pointers
这从一个已经存在的文本文件中读取,并从 infile 中创建 6 个小片段的 outfiles。 它按预期工作,但在运行 valgrind 时出现多个错误。 但是,没有 memory 泄漏:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char buffer[5];
FILE* infile = fopen("clams.txt", "r");
if (infile == NULL)
{
return 1;
}
for (int i = 0; i < 6; i++)
{
fread(buffer, sizeof(char), 5, infile);
char* filename = malloc(sizeof(char) * 4); //line 17
sprintf(filename,"%03i.txt", i);
printf("%c%c%c\n", filename[0], filename[1], filename[2]); //19
FILE* outfile = fopen(filename, "w"); //21
if (outfile == NULL)
{
return 2;
}
fwrite(buffer, sizeof(char), 5, outfile);
fclose(outfile);
free(filename);
}
fclose(infile);
}
瓦尔格林德 说:
==1042== Invalid write of size 1
==1042== at 0x4C762B4: _IO_default_xsputn (genops.c:394)
==1042== by 0x4C762B4: _IO_default_xsputn (genops.c:370)
==1042== by 0x4C5B165: __vfprintf_internal (vfprintf-internal.c:1719)
==1042== by 0x4C69278: __vsprintf_internal (iovsprintf.c:95)
==1042== by 0x4C46047: sprintf (sprintf.c:30)
==1042== by 0x401234: main (filename.c:18)
==1042== Address 0x4dd62a4 is 0 bytes after a block of size 4 alloc'd
==1042== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1042== by 0x401218: main (filename.c:17)
==1042==
==1042== Invalid write of size 1
==1042== at 0x4C6927E: __vsprintf_internal (iovsprintf.c:97)
==1042== by 0x4C46047: sprintf (sprintf.c:30)
==1042== by 0x401234: main (filename.c:18)
==1042== Address 0x4dd62a7 is 3 bytes after a block of size 4 alloc'd
==1042== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1042== by 0x401218: main (filename.c:17)
==1042==
000
==1042== Syscall param openat(filename) points to unaddressable byte(s)
==1042== at 0x4CF1EAB: open (open64.c:48)
==1042== by 0x4C74195: _IO_file_open (fileops.c:189)
==1042== by 0x4C74459: _IO_file_fopen@@GLIBC_2.2.5 (fileops.c:281)
==1042== by 0x4C66B0D: __fopen_internal (iofopen.c:75)
==1042== by 0x4C66B0D: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==1042== by 0x401275: main (filename.c:21)
==1042== Address 0x4dd62a4 is 0 bytes after a block of size 4 alloc'd
==1042== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1042== by 0x401218: main (filename.c:17)
==1042==
001
002
003
004
005
==1042==
==1042== HEAP SUMMARY:
==1042== in use at exit: 0 bytes in 0 blocks
==1042== total heap usage: 20 allocs, 20 frees, 32,000 bytes allocated
==1042==
==1042== All heap blocks were freed -- no leaks are possible
==1042==
==1042== For lists of detected and suppressed errors, rerun with: -s
==1042== ERROR SUMMARY: 30 errors from 3 contexts (suppressed: 0 from 0)
( filename.c
是我的程序的名称)
我能够消除错误的唯一方法是更改第 17 行以分配 8 个或更多字节。 介于 4 和 7 之间的任何东西都会给我带来错误。 我很困惑为什么会这样,因为每个字符串由 3 个字符组成,而\0
应该只需要 4 个字节来存储。
如果我保留malloc(4)
,我应该担心这些错误吗? 对于使用更多 memory(例如图像而不是文本)的类似程序,这些错误最终会导致崩溃或分段错误吗?
通过查看以下两行,问题就很清楚了:
char* filename = malloc(sizeof(char) * 4); // 17
sprintf(filename, "%03i.txt", i); // 18
在第 17 行,您分配了 4 个字节,这对于 3 个字符加上一个终止符 ( \0
) 的字符串来说已经足够了。 然后,在那之后,您在该字符串中写入超过 3 个字符:至少 4 个来自.txt
,然后由于%03i
更多。
相反,您应该分配更多空间。 保存文件名的字符串所需大小的保守估计是 4 ( .txt
) + 3 (因为i
可以假设值从0
到5
并填充到 3 个十进制数字) + 1 ( \0
终止符),所以一共8个字节。
这就是为什么将malloc(4)
更改为malloc(8)
不会产生错误的原因。
顺便说一句,对于这么小的缓冲区,您可以避免使用malloc
/ free
使事情复杂化,只需在堆栈上将其声明为局部变量:
char filename[8];
如果我保留
malloc(4)
,我应该担心这些错误吗?
是的,您正在写入已分配缓冲区的末尾,这是 C 中未定义的行为,这意味着您的程序很容易崩溃、段错误或做更糟糕的事情。
对于使用更多 memory(例如图像而不是文本)的类似程序,这些错误最终会导致崩溃或分段错误吗?
即使对于您刚刚提供的小程序,这些错误也可能导致崩溃,所以是的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.