Home > Software engineering >  Invalid write,read when allocating memory in c
Invalid write,read when allocating memory in c

Time:08-08

I have this function split_text that takes in a char array text and attempts to split it into sub-arrays using the token as the split value, res is an array of pointers to each of the sub-strings

int split_text(char * text, char * token, char ** res)
{
    int x =0;
    char * tmp = strtok(text , token);
    while (tmp != NULL)
    {
        res[x] = malloc(1024);
        strcpy(res[x], tmp);
        x  ;
        *res = realloc(*res, sizeof(char*)*(x 1));
        tmp = strtok(NULL , token);
    }
    return x;
}

int main()
{
    char text[] = "Hello world this is elliot";

    char ** ptr = (char**)malloc(sizeof(char*));

    int x = split_text(text, " ", ptr);

    
    for (int i =0; i< x; i  )
        printf("%s\n", ptr[i]);
    
    return 0;
}

when compiling this code it works fine as in it displays the sub-strings each on a new line but when ran with valgrind, I get many Invalid write of size 8 and Invalid read of size 8

Here is the full valgrind output

==74210== Memcheck, a memory error detector
==74210== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==74210== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==74210== Command: ./a.out
==74210== 
==74210== Invalid write of size 8
==74210==    at 0x1091D0: split_text (split.c:23)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== Invalid read of size 8
==74210==    at 0x1091E7: split_text (split.c:24)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
Hello
==74210== Invalid read of size 8
==74210==    at 0x1092D3: main (split.c:42)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
world
this
is
elliot
==74210== 
==74210== HEAP SUMMARY:
==74210==     in use at exit: 4,152 bytes in 6 blocks
==74210==   total heap usage: 12 allocs, 6 frees, 6,312 bytes allocated
==74210== 
==74210== LEAK SUMMARY:
==74210==    definitely lost: 4,104 bytes in 5 blocks
==74210==    indirectly lost: 48 bytes in 1 blocks
==74210==      possibly lost: 0 bytes in 0 blocks
==74210==    still reachable: 0 bytes in 0 blocks
==74210==         suppressed: 0 bytes in 0 blocks
==74210== Rerun with --leak-check=full to see details of leaked memory
==74210== 
==74210== ERROR SUMMARY: 12 errors from 3 contexts (suppressed: 0 from 0)
==74210== 
==74210== 4 errors in context 1 of 3:
==74210== Invalid read of size 8
==74210==    at 0x1092D3: main (split.c:42)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== 
==74210== 4 errors in context 2 of 3:
==74210== Invalid read of size 8
==74210==    at 0x1091E7: split_text (split.c:24)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== 
==74210== 4 errors in context 3 of 3:
==74210== Invalid write of size 8
==74210==    at 0x1091D0: split_text (split.c:23)
==74210==    by 0x1092B2: main (split.c:38)
==74210==  Address 0x4a3f048 is 0 bytes after a block of size 8 alloc'd
==74210==    at 0x483F7B5: malloc (vg_replace_malloc.c:381)
==74210==    by 0x109294: main (split.c:36)
==74210== 
==74210== ERROR SUMMARY: 12 errors from 3 contexts (suppressed: 0 from 0)

I know that it is reading and writing from invalid memory places but it still outputs the split-ed text as sub-strings

Why do I get these errors and how do I fix them?

CodePudding user response:

At least this statement

*res = realloc(*res, sizeof(char*)*(x 1))

that is equivalent to

res[0] = realloc(res[0], sizeof(char*)*(x 1))

does not make a sense.

It always reallocates the first element of the array of pointers pointed to by the pointer res.

As a result the array pointed to by the pointer res has only one element allocated in main.

So this call strcpy

strcpy(res[x], tmp);

invokes undefined behavior at least when x is not equal to 0.

Pay attention to that if you want to change the pointer ptr declared in main within the function split_text then you need to pass it to the function by reference. That is the third parameter of the function should be declared like

int split_text(char * text, char * token, char *** res);

As for the function definition then you need to allocate memory for a pointer for each new element and also to allocate a character array pointed to by the pointer where a substring will be copied.

  • Related