your text
我居然在大汗淋漓之后,把cs50课程的“recover”题做完了。我得到的最后一个错误是内存泄漏,虽然我修复了它,但我仍然不明白为什么会得到它。所以如果有人能向我解释一下,我会很高兴。
给我错误的那一行是下面的( BYTE 是他们建议在问题规范中创建的类型定义,我是这样创建的:typedef uint8_t BYTE;我在代码的其他地方使用它没有问题)
//Allocating space for images names
char *filename = malloc(1 *(sizeof(BYTE)));
这就是 valgrind 所说的:
==2963== Memcheck, a memory error detector
==2963== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2963== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==2963== Command: ./recover card.raw
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A17034: \_IO_default_xsputn (genops.c:394)
==2963== by 0x4A17034: \_IO_default_xsputn (genops.c:370)
==2963== by 0x4A09822: \_IO_padn (iopadn.c:64)
==2963== by 0x49FF817: pad_func (vfprintf-internal.c:196)
==2963== by 0x49FF817: \__vfprintf_internal (vfprintf-internal.c:1516)
==2963== by 0x4A0AA08: \__vsprintf_internal (iovsprintf.c:95)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A17034: \_IO_default_xsputn (genops.c:394)
==2963== by 0x4A17034: \_IO_default_xsputn (genops.c:370)
==2963== by 0x49FED28: outstring_func (vfprintf-internal.c:239)
==2963== by 0x49FED28: \__vfprintf_internal (vfprintf-internal.c:1516)
==2963== by 0x4A0AA08: \__vsprintf_internal (iovsprintf.c:95)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
==2963== Address 0x4bb5262 is 1 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A17034: \_IO_default_xsputn (genops.c:394)
==2963== by 0x4A17034: \_IO_default_xsputn (genops.c:370)
==2963== by 0x49FF049: outstring_func (vfprintf-internal.c:239)
==2963== by 0x49FF049: \__vfprintf_internal (vfprintf-internal.c:1593)
==2963== by 0x4A0AA08: \__vsprintf_internal (iovsprintf.c:95)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
=2963== Address 0x4bb5263 is 2 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A0AA0E: \__vsprintf_internal (iovsprintf.c:97)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
==2963== Address 0x4bb5267 is 6 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Syscall param openat(filename) points to unaddressable byte(s)
==2963== at 0x4A9D6EB: open (open64.c:41)
==2963== by 0x4A15135: \_IO_file_open (fileops.c:188)
==2963== by 0x4A15491: \_IO_file_fopen@@GLIBC_2.2.5 (fileops.c:280)
==2963== by 0x4A0872D: \__fopen_internal (iofopen.c:75)
==2963== by 0x4A0872D: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==2963== by 0x109316: main (recover.c:56)
==2963== Address 0x4bb5261 is 0 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963==
==2963== HEAP SUMMARY:
==2963== in use at exit: 0 bytes in 0 blocks
==2963== total heap usage: 104 allocs, 104 frees, 233,481 bytes allocated
==2963==
==2963== All heap blocks were freed -- no leaks are possible
==2963==
==2963== For lists of detected and suppressed errors, rerun with: -s
==2963== ERROR SUMMARY: 400 errors from 5 contexts (suppressed: 0 from 0)
这些是 check50 结果:
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:) recovers 000.jpg correctly
:) recovers middle images correctly
:) recovers 049.jpg correctly
:( program is free of memory errors
valgrind tests failed; see log for more information.
但是如果更改错误行:
//Allocating space for images names
char *filename = malloc(8 *(sizeof(char)));
一切正常。在这两种情况下分配的空间都是 1 个字节,并且在这两种情况下都被释放,如果我使用 typedef BYTE 为什么会出现错误?
//Allocating space for images names
char *filename = malloc(1 *(sizeof(BYTE)));
BYTE
是别名 uint8_t
,它是一个(至少)8 位无符号类型,它本身就是一个 unsigned char
的别名。这仅为 1 char
/ 字节分配内存。假设它是一个字符串,它只能容纳空字节。
//Allocating space for images names
char *filename = malloc(8 *(sizeof(char)));
两种情况分配的空间都是1个字节。
不,这里分配的空间是8个字节(sizeof (char)
根据定义为1),足以容纳000.jpg
+\0
。但是你不需要在这里malloc()
。分配的大小在编译时已知并保持不变,只需使用 array[8]
的简单 char
。
我在代码的其他地方使用它没有问题。
你很幸运。引用越界内存(包括读取和写入)是未定义的行为。
允许的未定义行为包括忽略情况 完全具有不可预知的结果,在翻译过程中表现 或程序以文件化的方式执行 环境(有或没有诊断消息的发布),以 终止翻译或执行(发出 诊断信息)。