I wrote a function to read a string with fgets that uses realloc() to make the buffer grow when needed:
char * read_string(char * message){
printf("%s", message);
size_t buffsize = MIN_BUFFER;
char *buffer = malloc(buffsize);
if (buffer == NULL) return NULL;
char *p;
for(p = buffer ; (*p = getchar()) != '\n' && *p != EOF ; ++p)
if (p - buffer == buffsize - 1) {
buffer = realloc(buffer, buffsize *= 2) ;
if (buffer == NULL) return NULL;
}
*p = 0;
p = malloc(p - buffer + 1);
if (p == NULL) return NULL;
strcpy(p, buffer);
free(buffer);
return p;
}
I compiled the program and tried it, and it worked like expected. But when I run it with valgrind, the function returns NULL when the read string is >= MIN_BUFFER and valgrind says:
(...) ==18076== Invalid write of size 1 ==18076== at 0x8048895: read_string (programme.c:73) ==18076== by 0x804898E: main (programme.c:96) ==18076== Address 0x41fc02f is 0 bytes after a block of size 7 free'd ==18076== at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==18076== by 0x8048860: read_string (programme.c:76) (...) ==18076== Warning: silly arg (-48) to malloc() (...)
I added a printf statement between *p=0; and p=malloc... and it confirmed that the arg passed had a value of -48. I didn't know that programs don't run the same way when launched alone and with valgrind. Is there something wrong in my code or is it just a valgrind bug?
When you realloc the buffer, your pointer 'p' still points at the old buffer.
That will stomp memory, and also cause future allocations to use bogus values.