1

此示例可以编译并按预期工作。

1 #include  <stdlib.h>
2 #include  <stdio.h>
3 #include  <string.h>
4
5 char * getstr() {
6     return strdup("Hello");
7 }
8
9 void *memcpy2(void *dest, const void *src, size_t len)
10 {
11     char * d = dest;
12     const char * s = src;
13
14     for (size_t i = 0; i < len; i++) {
15         d[i] = s[i];
16     }
17     return dest;
18 }
19
20 int main()
21 {
22     char buf[256];
23     char *str = getstr();
24
25     memset(buf, 0, 256);
26     memcpy2(buf, str, 255);
27
28     printf("%s\n", buf);
29
30     free(str);
31     return 0;
32 }

我重新实现了 memcpy 以完全控制测试,使其独立于底层 libc。如您所见,valgrind 抱怨以下警告:

$ valgrind ./a.out 
==9479== Memcheck, a memory error detector
==9479== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==9479== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==9479== Command: ./a.out
==9479== 
==9479== Invalid read of size 1
==9479==    at 0x4006B6: memcpy2 (k.c:15)
==9479==    by 0x400731: main (k.c:26)
==9479==  Address 0x5203046 is 0 bytes after a block of size 6 alloc'd
==9479==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9479==    by 0x4EC48D9: strdup (strdup.c:42)
==9479==    by 0x400673: getstr (k.c:6)
==9479==    by 0x4006F3: main (k.c:23)
==9479== 
Hello
==9479== 
==9479== HEAP SUMMARY:
==9479==     in use at exit: 0 bytes in 0 blocks
==9479==   total heap usage: 2 allocs, 2 frees, 1,030 bytes allocated
==9479== 
==9479== All heap blocks were freed -- no leaks are possible
==9479== 
==9479== For counts of detected and suppressed errors, rerun with: -v

我不明白为什么会出现这个“invalid read of size 1”消息。这对我来说完全没有意义。你们中的一些人能解释一下这段代码有什么问题吗?先感谢您!

4

2 回答 2

3
[...]
for (size_t i = 0; i < len; i++) {
    d[i] = s[i];
}
[...]

这里len是 255,但指向的字符串s长度小于 255,所以你要离开数组了。你也许可以使用'\0'放置的strdup()来避免这个错误。

于 2017-06-15T07:48:27.617 回答
2

在变量中指向一个长度为六个字节main的内存区域(字符串是字符串中的五个字符加上终止符,会分配字节)。越界会导致未定义的行为str"Hello"strdupstrlen("Hello") + 1

因为你想从这个六字节区域中读取255个字节,所以你会越界。

于 2017-06-15T07:48:51.913 回答