2

I'm new to C, trying to learn dynamic memory allocation for an array of char arrays, and not sure why I can't make valgrind happy with 0 errors also whilst avoiding a segfault. My example is based on this example:

How to dynamically allocate memory for char** in C

From that example, I whipped up this test code below:

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

int main (int argc, char* argv[]){
        char **myChar;

        int nEl = 5;
        int nChars = 10;

        myChar = (char**)malloc(sizeof(char*));
        for (int it = 0; it < nEl; it++) {
                myChar[it] = (char*)malloc((nChars) * sizeof(char));
        }

        //for (int it = 0; it < nEl; it++) {
        //        free(myChar[it]);
        //}
        //free(myChar);

        return 0;
}

It compiles as is, runs without problem, exits with return 0x0, but valgrind complains:

4 errors in context 1 of 1:
Invalid write of size 8
   at 0x400583: main (in /home/username/Documents/personal/tmp/cprog2/test2)
 Address 0x5204048 is 0 bytes after a block of size 8 alloc'd
   at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x40054D: main (in /home/username/Documents/personal/tmp/cprog2/test2)

ERROR SUMMARY: 4 errors from 1 contexts (suppressed: 0 from 0)

Figuring that valgrind expects the malloc'd **myChar and myChar[it] to be free(), I uncomment the commented bits, but the program segfaults and valgrind says this:

4 errors in context 1 of 2:
Invalid read of size 8
   at 0x4005EF: main (in /home/username/Documents/personal/tmp/cprog2/test2)
 Address 0x5204048 is 0 bytes after a block of size 8 alloc'd
   at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x40058D: main (in /home/username/Documents/personal/tmp/cprog2/test2)


4 errors in context 2 of 2:
Invalid write of size 8
   at 0x4005C3: main (in /home/username/Documents/personal/tmp/cprog2/test2)
 Address 0x5204048 is 0 bytes after a block of size 8 alloc'd
   at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x40058D: main (in /home/username/Documents/personal/tmp/cprog2/test2)

ERROR SUMMARY: 8 errors from 2 contexts (suppressed: 0 from 0)

Why can I not make valgrind happy and compile and run a working app?

brneuro
  • 326
  • 1
  • 5
  • 15

1 Answers1

1

You're not allocated enough memory:

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

This allocates space for a single char *, but you treat this memory as if you allocated 5 (i.e. nEl) of them.

As a result, you write past the end of allocated memory. This is what Valgrind is alerting you of when it says "Address 0x5204048 is 0 bytes after a block of size 8 alloc'd". Doing so invokes undefined behavior, which in this case manifests as a crash.

If you want space for nEl pointers, allocate that amount of space:

myChar = malloc(sizeof(char*) * nEl);

Also, don't cast the return value of malloc.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Thanks for the answer. Regarding the casting the return from malloc, I am getting error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive] if I don't cast the return. I'll have to do some more reading in the thread you linked to fully understand why that is – brneuro Feb 21 '18 at 12:43
  • @brneuro That probably means you're compiling as C++ instead of C. – dbush Feb 21 '18 at 12:46
  • ah, indeed I am as I'm working toward implementing some of this into a class. – brneuro Feb 21 '18 at 16:25