繁体   English   中英

没有 memory 泄漏,但使用 malloc 和文件指针时来自 valgrind 的错误令人困惑

[英]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可以假设值从05并填充到 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM