C strings, strlen and Valgrind
Asked Answered
S

2

7

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?

Scuttlebutt answered 14/7, 2010 at 12:25 Comment(0)
T
14

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.

Tupper answered 14/7, 2010 at 12:37 Comment(3)
Upgrade to last SVN version corrected the problem. Thanks to point this bug out! :)Scuttlebutt
Do you remember what versions of valgrind this applied to?Rouleau
This is again a problem with recent gcc and valgrind, and is not only limited to SSE, as you can see here: bugzilla.redhat.com/show_bug.cgi?id=678518Academia
P
4

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.

Pome answered 14/7, 2010 at 12:33 Comment(1)
No, should never be a problem with aligned SSE reads. If the first byte is readable, then the last is readable too. Aligned reads cannot span page boundaries. It's a valgrind bug - see my answer.Tupper

© 2022 - 2024 — McMap. All rights reserved.