【问题标题】:Invalid Read in ValgrindValgrind中的无效读取
【发布时间】:2013-09-17 04:10:12
【问题描述】:

我一直在 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 和我的内存调试代码中产生无效的释放。但是,它不应该发生段错误,这就是正在发生的事情。关闭系统日志后,不再出现段错误,并且 Valgrind 报告与测试代码的预期一致。我不知道为什么 syslog 会导致上述问题。

测试代码:

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)

【问题讨论】:

  • 请显示更多代码,尤其是部分 test025.c:13

标签: c valgrind


【解决方案1】:

初步尝试

你得到的读取错误意味着你分配了一些空间然后被释放,但是你的程序的某些部分设法保持一个指向内存块中间的指针,然后试图从里面读取一个字节在第 13 行用 memcpy() 阻止 main()

不太清楚的是分配内存的位置。看起来好像免费是在对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 行也不例外。有些人会因为演员表而责备你;我不属于那种思想流派。我允许你忽略它们——只要你保证用-Wmissing-prototypes -Wstrict-prototypes(和-Wall -Wextra)编译并且在运行代码之前修复报告的问题。如果你不这样做,你需要注意我(关于使用严格的编译器选项并修复编译器警告标识的问题)或它们(关于不强制转换 malloc() 的结果)。

第 12 行避免了“未使用的变量”警告;否则就是无操作。

第 13 行,memcpy(),尝试从b 开始之前的 200 个字节复制到为b 分配的空间末尾之外的 200 个字节。在这 450 个字节中,访问其中的 400 个会导致未定义的行为。如果您只是在读取内存,并且目的地 - p - 足够大,那么您就“OK”了。但是读取b 两边的字节是无效的,valgrind 抱怨是完全正确的。

第 14 行,free(),尝试释放 malloc() 未返回的指针。因此,您正在调用未定义的行为。除了灾难之外,没有任何事情可以发生。很有可能free() 本身不会失败——尽管调试malloc() 会注意到您正在从分配空间的中间释放。但是任何后续的内存分配或释放都是非常有问题的。问题是free() 会在(通常)指向的空格之前查看控制信息,而该信息将无效。

【讨论】:

  • Jonathan,m61.c 和 m61_allocation_core.c 是我的代码。我关闭了 syslog 的日志记录,现在我没有收到段错误,而且在 valgrind 调查结果中也没有调用 free 。我不知道为什么 syslog 会导致问题。再次查看我的测试代码,实际上它是被 Valgrind 捕获的(以及我的内存分配调试代码),而不是 segfault。所以现在我取出了系统日志,我粘贴了 Valgrind 的新报告。根据我的测试代码,这对我来说似乎是正确的。我只是不知道为什么syslog会导致首先报告的问题。
猜你喜欢
  • 1970-01-01
  • 2018-07-07
  • 1970-01-01
  • 2017-04-09
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多