这是我的代码:我正在尝试获取结构的信息并深入复制信息。但是,valgrind
表示“无效阅读”。我知道那是我读过发布的内存。我不知道为什么;是否有人能够为我解决这个问题?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct student
{
int id;
char *name;
int age;
};
void get_info(struct student *dest, struct student *src)
{
memcpy(dest,src,sizeof(struct student));
dest->name = strdup(src->name);
}
int main()
{
struct student foo;
foo.id = 1001;
foo.name = strdup("kevin");
foo.age = 18;
struct student bar;
get_info(&bar, &foo);
puts(bar.name);
free(foo.name);
free(bar.name);
return 0;
}
valgrind --tool=memcheck --leak-check=full ./test
==2130== Memcheck, a memory error detector
==2130== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2130== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==2130== Command: ./test
==2130==
==2130== Invalid read of size 4
==2130== at 0x40B083B: ??? (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x40B04A4: strdup (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x80484B1: get_info (test.c:15)
==2130== by 0x80484F8: main (test.c:26)
==2130== Address 0x419902c is 4 bytes inside a block of size 6 alloc'd
==2130== at 0x4026775: malloc (vg_replace_malloc.c:291)
==2130== by 0x40B04AF: strdup (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x80484D8: main (test.c:22)
==2130==
==2130== Invalid read of size 4
==2130== at 0x40B083B: ??? (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x409ACE4: puts (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x8048504: main (test.c:28)
==2130== Address 0x4199064 is 4 bytes inside a block of size 6 alloc'd
==2130== at 0x4026775: malloc (vg_replace_malloc.c:291)
==2130== by 0x40B04AF: strdup (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x80484B1: get_info (test.c:15)
==2130== by 0x80484F8: main (test.c:26)
==2130==
kevin
==2130==
==2130== HEAP SUMMARY:
==2130== in use at exit: 0 bytes in 0 blocks
==2130== total heap usage: 2 allocs, 2 frees, 12 bytes allocated
==2130==
==2130== All heap blocks were freed -- no leaks are possible
==2130==
==2130== For counts of detected and suppressed errors, rerun with: -v
==2130== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 11 from 6)
答案 0 :(得分:6)
我认为这实际上是valgrind
的错误报告,你应该压制它。它最终是您系统上C库中的一个错误。
投诉是从strdup()
调用的代码在4个字节的偏移处读取4个字节到由malloc()
分配的6个字节的块中。鉴于"kevin"
占用了6个字节,我相信memcpy()
已使用strdup()
变体,并且已经捕获到通过数据一次读取4个字节的行为。虽然它实际上可能是安全的,但从技术上讲,valgrind
抱怨是正确的。但是,您无法做任何事情 - 您的代码是无辜的,系统库是有罪的。这就是抑制的东西!
+---+---+---+---+---+---+...+...+
| k | e | v | i | n | \0| ? | ? |
+---+---+---+---+---+---+...+...+
快速复制使用的事实是malloc()
'd数据是4字节(更可能是8字节)对齐的。它在一次操作中复制4个字节'k','e','v'和'i';然后它复制字符串的另外两个字节('n','\ 0')加上在第二个操作中技术上不属于分配空间的两个字节。在32位系统上,最小实际分配大概是8个字节;它在64位计算机上往往是16字节。这意味着额外的两个字节是为内存分配保留的空间的一部分,但是valgrind
报告代码在分配的空间之外复制是正确的。
答案 1 :(得分:1)
这看起来像strdup()
和puts()
中的优化,他们一次读取四个字节的块而不是一个字节的输入,但是他们小心不要写超越结束。只要四个字节的地址对齐,这是安全的:正确对齐的读取永远不会触发硬件异常,并且由于这两个函数不会写超出字符串的末尾,因此它们的操作是安全的,即使从语言的角度来看它是非法的。并且您可以确定这四个字节的地址将被正确对齐,因为它是一个优化,未对齐的读取会使代码爬行。
Valgrind检查语言级别的正确性,而不是物理级别,因此检查错误报告。所以我同意Jonathan Leffler你应该压制这个“错误”,看看评论,似乎是由更新版本的valgrind自动完成的。