-1

I have the following test.h file:

typedef struct node *Node;
struct node {
    const char *key;
    Node next;
};

typedef struct table_s *Table;
struct table_s {
    int n;
    Node *arrayOfNodes;
};

And also this test.c file:

Table new_table() {
    Table thisTable = malloc(sizeof(Table));
    thisTable->n = 2;
    thisTable->arrayOfNodes = malloc(thisTable->n*sizeof(Node));

    //this line is inserted here so I can check that calling malloc() like this actuallt work
    Node *array = malloc(thisTable->n*sizeof(Node)); 

    return thisTable;
}

int main() {

    Table myTable = new_table();

return 0;
}

The program compiles and works, but valgrind.log indicates there are errors:

==8275== Invalid write of size 8
==8275==    at 0x40056E: new_table (test.c:8)
==8275==    by 0x40043A: main (test.c:18)
==8275==  Address 0x5204048 is 0 bytes after a block of size 8 alloc'd
==8275==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8275==    by 0x40055A: new_table (test.c:6)
==8275==    by 0x40043A: main (test.c:18)

Why does the malloc() call in line 11 works fine but in line 8 causes this errors? This is making my bigger version of this program to not work with large entries (when n gets bigger).

Hevv
  • 33
  • 4
  • You will want to review: [Is it a good idea to **typedef** pointers?](http://stackoverflow.com/questions/750178/is-it-a-good-idea-to-typedef-pointers). – David C. Rankin May 13 '18 at 03:01

1 Answers1

3

"Size 8" is a clue: it's the size of a pointer on your system. What you wanted to allocate was an object, not a pointer.

sizeof(Node) is the same as sizeof(struct node *), and sizeof(Table) has a similar problem.

It would work if you had written something like this instead:

typedef struct table_s Table, *TablePtr;
...
TablePtr thisTable = malloc(sizeof(Table));

If you insist on the types as they are, you could just use the following common malloc idiom:

// General form:
//   T *p = malloc(sizeof *p);
// or:
//   T *p = malloc(N * sizeof *p);
Table this_table = malloc(sizeof *this_table);
...
this_table->arrayOfNodes = malloc(thisTable->n * sizeof *this_table->arrayOfNodes);

Why does the malloc() call in line 11 works fine but in line 8 causes this errors?

Because you allocate a Table (size=8), then attempt to access it as if it's a struct table_s (size=16). Your declaration of array is fine, but before that, you attempt to write the pointer returned by malloc to this_table->arrayOfNodes, which resides at offset 8 in the structure (i.e. offset 0 is n and offset 8 is arrayOfNodes). In short, you're attempting to write outside the allocated memory: you only allocated 8 bytes, but you're writing past the first 8 bytes of the structure.

  • Thank you very much! This solved this problem. This differences in data types are sometimes confusing. So you mean that, whenever I have this `Invalid read of size n` errors, I should actually look in the `malloc()` call before that one? – Hevv May 13 '18 at 03:54
  • Anytime you have an invalid read or invalid write, it means you're doing something with a section of memory that your program does not own. This may mean memory you freed already (dangling pointer), or it may be an out of bounds pointer. You may need to use the info provided by Valgrind and a debugger to step through your code, so you can determine exactly what caused the issue Valgrind complained about. –  May 13 '18 at 03:59