C字符串,strlen和Valgrind

我试图理解为什么Valgrind正在吐痰:

==3409== Invalid read of size 8 ==3409== at 0x4EA3B92: __GI_strlen (strlen.S:31) 

每当我在动态分配的字符串上应用strlen时?

这是一个简短的测试用例:

 #include  #include  #include  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) 

避免这些警告的正确方法是什么? 他们是真正的警告吗?

这很可能与此bug报告有关:

https://bugzilla.redhat.com/show_bug.cgi?id=518247

正如Paul已经建议的那样,英特尔平台上的strlen()可选择使用SSE优化来加速strlen和朋友。 这种加速涉及分配块后面的安全读取,而旧版本的valgrind还没有理解。 所以升级你的valgrind就可以了。

我的猜测是你的strlen实现已经过优化,它一次读取8个字节,并测试64位字中任何地方的第一个零字节(可能使用MMX / SSE)。 这意味着对于12字节的字符串示例,它读取超出字符串末尾的4个字节。 关于这是否是strlen实现中的错误,这是有争议的。 我想你只需要忽略它。 或者确保您的字符串分配始终是8个字节的倍数。