即使在释放 C 语言中的 malloc 空间后,Valgrind 也能检测到可访问的块(cs50 问题集 4 恢复)

Valgrind detects reachable blocks even after freeing malloc space in C (cs50 Problem Set 4 Recover)

提问人:Savvidaios 提问时间:9/21/2023 更新时间:9/21/2023 访问量:39

问:

我已经完成了 cs50 的问题集 4 称为 recover。您将在下面看到我已将 malloc 用于名为 sfile 的 char*。在文件的末尾,我记得释放分配的空间(又名 sfile)并关闭我打开的 2 个文档。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage: ./recover IMAGE\n");
        return 1;
    }
    printf("%s", argv[1]);

    FILE *file = fopen(argv[1], "r");

    if (file == NULL)
    {
        printf(" can't be opened for reading\n");
        return 2;
    }

    unsigned char arr[512];

    int s = 0;

    FILE *output_file = NULL;

    char *sfile = malloc(sizeof(char) * 8);

    while (fread(arr, sizeof(char), 512, file) != 0)
    {

        if (arr[0] == 0xff && arr[1] == 0xd8 && arr[2] == 0xff && (arr[3] & 0xf0) == 0xe0)
        {
            sprintf(sfile, "%03i.jpg", s);

            output_file = fopen(sfile, "w");

            s++;
        }

        if (output_file != NULL)
        {
            fwrite(arr, sizeof(char), 512, output_file);
        }

    }

    free(sfile);

    fclose(output_file);
    fclose(file);


    return 0;
}

但是,当运行 check50 时,这是一个检查您是否完成了练习的所有要点的工具,我只收到一条红色消息,表明 valgrind 检测到内存错误。所以我的下一步是运行:

$ valgrind ./recover card.raw

这是返回的内容:

==53590== HEAP SUMMARY:
==53590==     in use at exit: 23,128 bytes in 49 blocks
==53590==   total heap usage: 1,091 allocs, 1,042 frees, 240,880 bytes allocated
==53590== 
==53590== 23,128 bytes in 49 blocks are still reachable in loss record 1 of 1
==53590==    at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==53590==    by 0x4A076CD: __fopen_internal (iofopen.c:65)
==53590==    by 0x4A076CD: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==53590==    by 0x109304: main (recover.c:37)
==53590== 
==53590== LEAK SUMMARY:
==53590==    definitely lost: 0 bytes in 0 blocks
==53590==    indirectly lost: 0 bytes in 0 blocks
==53590==      possibly lost: 0 bytes in 0 blocks
==53590==    still reachable: 23,128 bytes in 49 blocks
==53590==         suppressed: 0 bytes in 0 blocks
==53590== 
==53590== For lists of detected and suppressed errors, rerun with: -s
==53590== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

该程序运行良好,这是剩下的唯一问题。

我看过 cs50 恢复门槛,但没有 valgrind 错误,但我无法真正理解它,因为他的代码在我眼中是意大利面条代码(没有冒犯!!

我还是 C 的新手,拥有 Python 编程背景使我很难理解与内存有关的任何事情,因为 python 更直接。

任何帮助都不胜感激:)

C 存储器 Malloc Valgrind CS50

评论

0赞 Some programmer dude 9/21/2023
OT:有没有理由而不是平淡无奇?char *sfile = malloc(sizeof(char) * 8);char sfile[8];
1赞 Fe2O3 9/21/2023
...或者 使用 GB 内存,为什么要缩减(并且当源文件中有 > 个 999 个目标时,可能会溢出?char sfile[ 128 ];
1赞 Fe2O3 9/21/2023
如果上次成功读取没有获得完整的 512 字节,会发生什么情况?
1赞 Some programmer dude 9/21/2023
@Savvidaios 关于数组大小,没有必要便宜。最好注意安全,并为未来的问题做好准备。如果输入文件大小不是 的倍数,则最后一个字节将丢失,您将不会读取它们,也不会将它们写入输出。时刻做好准备。CS50 在这方面有点糟糕,因为它以一种太好的方式呈现事物,你需要了解现实生活中的事情通常并不那么好。512
1赞 Savvidaios 9/21/2023
@Fe2O3 当然,我愿意听经验,这就是我想知道为什么使用 128 字节的原因。这是我第一次使用 sprintf,我不知道 %03d 指定了最小值,也不知道 128 就足够了。正如我上面所说,记忆的思想对我来说是一个全新的学习领域。非常感谢您的解释!!

答:

3赞 Some programmer dude 9/21/2023 #1

问题是

output_file = fopen(sfile, "w");

将发生多次。但你只关闭一次。output_file

您需要添加检查以查看是否不是,然后先关闭文件,然后再再次打开它。output_fileNULL


主要提示是泄漏发生在 .这在 Valgrind 输出中很容易看到。fopen

评论

0赞 Savvidaios 9/21/2023
你是完全正确的!我把它改成了: if (output_file == NULL) { output_file = fopen(sfile, “w”); } else { fclose(output_file); output_file = fopen(sfile, “w”); } 而且效果很好!非常感谢!!
0赞 Fe2O3 9/21/2023
@Savvidaios 建议你熟悉一下......可惜该功能需要打开文件...如果它像...freopen()realloc()malloc()
1赞 Savvidaios 9/21/2023
@Fe2O3我会检查一下。谢谢!!