我一直在 Valgrind 中看到这些错误。我的程序也有段错误,但我试图先在 Valgrind 中解决错误。
81 char *ptr = NULL;
82 if (addition_is_safe(sz, TRAILER_SZ))
83 ptr = malloc(sz + TRAILER_SZ);
84 syslog(LOG_NOTICE, "Calling set trailer value, ptr=%p", ptr);
将其打印到日志中:
9 月 17 日 00:05:50 设备 m61[18301]:调用设置尾部值,ptr=0x96af158
瓦尔格林德:
==18069== 2 errors in context 1 of 4:
==18069== Invalid read of size 1
==18069== at 0x402BCCA: memcpy (mc_replace_strmem.c:882)
==18069== by 0x8048819: main (test025.c:13)
==18069== Address 0x4213709 is 137 bytes inside a block of size 368 free'd
==18069== at 0x4028F0F: free (vg_replace_malloc.c:446)
==18069== by 0x40AA00B: fclose@@GLIBC_2.1 (iofclose.c:88)
==18069== by 0x4136003: __vsyslog_chk (syslog.c:228)
==18069== by 0x4136446: syslog (syslog.c:119)
==18069== by 0x8049823: attempt_create_allocation (m61_allocation_core.c:84)
==18069== by 0x8048914: m61_malloc (m61.c:47)
==18069== by 0x80487B4: main (test025.c:9)
==18069==
编辑: 我运行的测试代码实际上是为了产生一个无效的自由被 Valgrind 和我的内存调试代码捕获。但是,它不应该出现段错误,而这正是正在发生的事情。关闭 syslog 后,不再有段错误,并且 Valgrind 报告符合测试代码的预期。我不知道为什么系统日志会导致上述问题。
测试代码:
1 #include "m61.h"
2 #include <stdio.h>
3 #include <assert.h>
4 #include <string.h>
7 int main() {
8 char *a = (char *) malloc(200);
9 char *b = (char *) malloc(50);
10 char *c = (char *) malloc(200);
11 char *p = (char *) malloc(3000);
12 (void) a, (void) c;
13 memcpy(p, b - 200, 450);
14 free(p + 200);
关闭 Valgrind 后的新 Valgrind 报告:
==5688== 18 errors in context 1 of 3:
==5688== Invalid read of size 4
==5688== at 0x402BD00: memcpy (mc_replace_strmem.c:882)
==5688== by 0x8048849: main (test025.c:13)
==5688== Address 0x41f92c0 is 16 bytes before a block of size 208 alloc'd
==5688== at 0x4029F6F: malloc (vg_replace_malloc.c:270)
==5688== by 0x80497AD: attempt_create_allocation (m61_allocation_core.c:77)
==5688== by 0x8048950: m61_malloc (m61.c:48)
==5688== by 0x8048804: main (test025.c:10)
最佳答案
初次尝试
你得到的读取错误意味着你分配了一些空间然后被释放,但是你的程序的某些部分设法保持一个指向内存块中间的指针,然后试图从里面读取一个字节在第 13 行的 main()
中用 memcpy()
阻止。
不太清楚的是内存的分配位置。看起来释放是在对 syslog()
的调用中完成的,这很奇怪。
您需要仔细查看 test025.c
中的代码。如果 m61.c
是您的代码,您也应该查看它(并且可能还有 m61_allocation_core.c
)。 vg_replace_malloc.c
中的代码绝对是 valgrind
代码;我不确定中间的部分。
修改后的代码——修改后的答案
您修改后的代码中的 memcpy()
显然是 100% 错误的。同样,free()
是 100% 错误的。要了解原因,您必须记住 malloc()
通常在分配的指针之前存储一些控制信息。您还需要知道,尝试 free()
不是由 malloc()
、calloc()
或 返回的指针realloc()
是一个严重的错误。
您的代码是:
7 int main() {
8 char *a = (char *) malloc(200);
9 char *b = (char *) malloc(50);
10 char *c = (char *) malloc(200);
11 char *p = (char *) malloc(3000);
12 (void) a, (void) c;
13 memcpy(p, b - 200, 450);
14 free(p + 200);
除了错误检查(或没有错误检查)之外,第 7-11 行无一异常(exception)。有些人会因为类型转换而责备你;我不属于那种思想流派。我允许你忽略它们——只要你 promise 使用 -Wmissing-prototypes -Wstrict-prototypes
(和 -Wall -Wextra
)编译并解决问题在运行代码之前报告。如果你不这样做,你需要注意我(关于使用严格的编译器选项和修复编译器警告识别的问题)或它们(关于不转换 malloc()
的结果)。
第 12 行避免了“未使用的变量”警告;否则就是空操作。
第 13 行,memcpy()
,尝试从 b
开始之前的 200 个字节复制到为 分配的空间末尾之外的 200 个字节b
。在这 450 个字节中,访问其中的 400 个会导致未定义的行为。如果您只是在读取内存,并且目的地 — p
— 足够大,那么您就“OK”了。但是读取 b
任一侧的字节是无效的,valgrind
的提示是完全正确的。
第 14 行 free()
尝试释放 malloc()
未返回的指针。因此,您正在调用未定义的行为。除了灾难,没有什么是你可以期待的。很有可能 free()
本身不会失败 — 尽管调试 malloc()
会注意到您正在释放已分配空间的中间部分。但是任何后续的内存分配或释放都是非常有问题的。问题在于 free()
会在(通常)指向的空间之前查看控制信息,而该信息将无效。
关于c - 在 Valgrind 中读取无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18841167/