C 字符串、strlen 和 Valgrind
我试图理解为什么 Valgrind 会吐出:
==3409== Invalid read of size 8
==3409== at 0x4EA3B92: __GI_strlen (strlen.S:31)
每当我在动态分配的字符串上应用 strlen 时?
这是一个简短的测试用例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *hello = "Hello World";
char *hello2;
/* Step 1 */
printf("Step 1\n");
printf("strlen : %lu\n",(unsigned long)strlen(hello));
/* Step 2 */
hello2 = calloc(12,sizeof(char));
hello2[0] = 'H';
hello2[1] = 'e';
hello2[2] = 'l';
hello2[3] = 'l';
hello2[4] = 'o';
hello2[5] = ' ';
hello2[6] = 'W';
hello2[7] = 'o';
hello2[8] = 'r';
hello2[9] = 'l';
hello2[10] = 'd';
hello2[11] = 0;
printf("Step 2\n");
printf("strlen : %lu\n",(unsigned long)strlen(hello2));
free(hello2);
return 0;
}
这是 Valgrind 的结果输出:
lenain@perseus:~/work/leaf$ valgrind ./leaf
==3409== Memcheck, a memory error detector
==3409== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3409== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==3409== Command: ./leaf
==3409==
Step 1
strlen : 11
Step 2
==3409== Invalid read of size 8
==3409== at 0x4EA3B92: __GI_strlen (strlen.S:31)
==3409== by 0x40098A: main (in /home/lenain/work/leaf/leaf)
==3409== Address 0x5189048 is 8 bytes inside a block of size 12 alloc'd
==3409== at 0x4C234CB: calloc (vg_replace_malloc.c:418)
==3409== by 0x4008F0: main (in /home/lenain/work/leaf/leaf)
==3409==
strlen : 11
==3409==
==3409== HEAP SUMMARY:
==3409== in use at exit: 0 bytes in 0 blocks
==3409== total heap usage: 1 allocs, 1 frees, 12 bytes allocated
==3409==
==3409== All heap blocks were freed -- no leaks are possible
==3409==
==3409== For counts of detected and suppressed errors, rerun with: -v
==3409== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
避免这些警告的正确方法是什么?它们是真正的警告吗?
I'm trying to understand why Valgrind is spitting out :
==3409== Invalid read of size 8
==3409== at 0x4EA3B92: __GI_strlen (strlen.S:31)
whenever I'm applying strlen on a dynamically allocated string?
Here is a short testcase :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *hello = "Hello World";
char *hello2;
/* Step 1 */
printf("Step 1\n");
printf("strlen : %lu\n",(unsigned long)strlen(hello));
/* Step 2 */
hello2 = calloc(12,sizeof(char));
hello2[0] = 'H';
hello2[1] = 'e';
hello2[2] = 'l';
hello2[3] = 'l';
hello2[4] = 'o';
hello2[5] = ' ';
hello2[6] = 'W';
hello2[7] = 'o';
hello2[8] = 'r';
hello2[9] = 'l';
hello2[10] = 'd';
hello2[11] = 0;
printf("Step 2\n");
printf("strlen : %lu\n",(unsigned long)strlen(hello2));
free(hello2);
return 0;
}
And here is the result output from Valgrind :
lenain@perseus:~/work/leaf$ valgrind ./leaf
==3409== Memcheck, a memory error detector
==3409== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3409== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==3409== Command: ./leaf
==3409==
Step 1
strlen : 11
Step 2
==3409== Invalid read of size 8
==3409== at 0x4EA3B92: __GI_strlen (strlen.S:31)
==3409== by 0x40098A: main (in /home/lenain/work/leaf/leaf)
==3409== Address 0x5189048 is 8 bytes inside a block of size 12 alloc'd
==3409== at 0x4C234CB: calloc (vg_replace_malloc.c:418)
==3409== by 0x4008F0: main (in /home/lenain/work/leaf/leaf)
==3409==
strlen : 11
==3409==
==3409== HEAP SUMMARY:
==3409== in use at exit: 0 bytes in 0 blocks
==3409== total heap usage: 1 allocs, 1 frees, 12 bytes allocated
==3409==
==3409== All heap blocks were freed -- no leaks are possible
==3409==
==3409== For counts of detected and suppressed errors, rerun with: -v
==3409== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
What is the correct way to avoid these warnings? Are they real warnings?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这很可能与此错误报告有关:
https://bugzilla.redhat.com/show_bug。 cgi?id=518247
正如 Paul 已经建议的那样,intel 平台上的 strlen() 可以选择使用 SSE 优化来加速 strlen 和其他函数。这种加速涉及分配块后面的安全读取,这是旧版本的 valgrind 尚不理解的。所以升级你的 valgrind 就可以了。
This is most likely related to this bugreport:
https://bugzilla.redhat.com/show_bug.cgi?id=518247
As Paul already suggested, strlen() on intel platforms optionally uses SSE optimization to speed up strlen and friends. This speed up involve safe reads behind the allocated blocks, something older versions of valgrind did not understand yet. So upgrade your valgrind and you will be OK.
我的猜测是,您的 strlen 实现已经过优化,可以一次读取 8 个字节,并测试 64 位字中任意位置的第一个零字节(可能使用 MMX/SSE)。这意味着对于 12 字节字符串示例,它会读取超出字符串末尾的 4 个字节。关于这是否是 strlen 实现中的错误是有争议的。我想你只能忽略它。或者确保您的字符串分配始终是 8 字节的倍数。
My guess is that your strlen implementation has been optimised such that it reads 8 bytes at a time and tests for the first zero byte anywhere in the 64 bit word (probably using MMX/SSE). This means that for your 12 byte string example it's reading 4 bytes beyond the end of the string. It's arguable as to whether this is a bug in the strlen implementation or not. I think you'll just have to ignore it. Or make sure your string allocations are always multiples of 8 bytes.