0
votes

I'm practicing C by coding functions of the string.h lib. But I'm currently stuck with a problem that I don't understand. When I execute my program, it crashes with the following message:

double free or corruption (!prev)

I tried with Valgrind but it seems that the bug does not occur with it.

This is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

char * duplicateString(const char * str) {
    size_t strLength = strlen(str);

    char * duplicatedString = malloc(strLength);
    if(duplicatedString == NULL)
        exit(EXIT_FAILURE);

    // +1 to copy '\0'
    strncpy(duplicatedString, str, strLength + 1);

    return duplicatedString;
}

void test_duplicateString()
{
  const char * src = "abc";
  char buf[1024];
  int i, j;
  char * temp = duplicateString(src);

  assert((strcmp((src),(temp)) == 0));
  assert(src != temp);
  free(temp);

  for(i = 0; i < 1024; ++i)
  {
    for(j = 0; j < i; ++j)
      buf[j] = (char) ('a' + (j % 26));
    buf[i] = '\0';

    temp = duplicateString(buf);
    assert((strcmp((buf),(temp)) == 0));
    free(temp);
  }
}

int main()
{
    test_duplicateString();
    return 0;
}

According to GDB, this error happens always at line 38 when i=136. For example why at i=136, and not before?

#0  0x00007ffff7a6a5f8 in raise () from /usr/lib/libc.so.6
No symbol table info available.
#1  0x00007ffff7a6ba7a in abort () from /usr/lib/libc.so.6
No symbol table info available.
#2  0x00007ffff7aa905a in __libc_message () from /usr/lib/libc.so.6
No symbol table info available.
#3  0x00007ffff7aae9a6 in malloc_printerr () from /usr/lib/libc.so.6
No symbol table info available.
#4  0x00007ffff7aaf18e in _int_free () from /usr/lib/libc.so.6
No symbol table info available.
#5  0x000000000040093e in test_duplicateString () at /media/sf_data/Cours/Polytech/DI3/Langage_C/DoubleFreeTest/main.c:38
        src = 0x400a10 "abc"
        buf = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef\000\344\377\367\377\177\000\000\240\345\377\377\377\177\000\000x\030\375\367\377\177\000\000\000\000\000\000\000\000\000\000\230\331\377\367\377\177\000\000`\346\377\377\377\177\000\000?M\336\367\377\177\000\000\001\000\000\000\000\000\000\000"...
        i = 136
        j = 136
        temp = 0x602010 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
        __PRETTY_FUNCTION__ = "test_duplicateString"
#6  0x0000000000400979 in main () at /media/sf_data/Cours/Polytech/DI3/Langage_C/DoubleFreeTest/main.c:44
No locals.
1
char * duplicatedString = malloc(strLength); should be char * duplicatedString = malloc(strLength+1);BLUEPIXY
malloc(strLength +1 )too honest for this site
char * duplicatedString = malloc(strLength);. Shouldn't that be malloc(strLength + 1)?kaylum
And I find it surprising that you say valgrind doesn't spot the error. It certainly does for me: ==8066== Invalid write of size 1; at 0x402D763: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so); by 0x8048745: test_duplicateString (in /tmp/a.out)kaylum
Note: Simplification strncpy(duplicatedString, str, strLength + 1); return duplicatedString; --> return memcpy(duplicatedString, str, strLength + 1);chux - Reinstate Monica

1 Answers

1
votes

To put what all of the comments said into an answer, in your function duplicateString(), you didn't allocate enough memory to fit the string and the null character.

So when you do this

strncpy(duplicatedString, str, strLength + 1);

You're copying more than the buffer can hold. The solution is obviously to increase the buffer size by 1.

char * duplicatedString = malloc(strLength + 1);