I'm experimenting with linked lists and tried to create a generic doubly linked list which allocates memory only once for each node. It means that the memory for the node and the element the node contains is allocated within same malloc
invocation.
The list itself is a structure which contains size of a unit (initialized with sizeof(struct which_is_an_element)
:
struct doubly_linked_list
{
struct dll_node *head, *tail;
size_t elem_size;
};
The node:
struct dll_node
{
struct dll_node *next, *prev;
void *elem;
};
Now, when I try to insert element and initialize it:
static struct dll_node * new_node(
struct doubly_linked_list *l,
void *elem)
{
struct dll_node *n = malloc (
sizeof(struct dll_node) + l->elem_size);
// This line throws valgrind error
memcpy(n + sizeof(struct dll_node), elem, l->elem_size);
n->prev = n->next = NULL;
n->elem = n + sizeof(struct dll_node);
return n;
}
I get a valgrind error:
Invalid write of size 8
at 0x4C3217B: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1022) by 0x400705: new_node (doubly_linked_list.c:20)
by 0x400768: dl_list_insert_at_tail (doubly_linked_list.c:30)
by 0x40093F: main (main.c:24)
Address 0x5204280 is 480 bytes inside an unallocated block of size 4,194,112 in arena "client"
memcpy
write inside unallocated block as the size of the allocated memory is equal to sizeof(struct which_is_an_element) + sizeof(dll_node)
?sizeof(struct dll_node)
because of the type of the pointer called n
inside new_node
function which points to the data?Does really
memcpy
write inside unallocated block as the size of the allocated memory is equal tosizeof(struct which_is_an_element) + sizeof(dll_node)
?
Yes.
Doing memcpy(n + sizeof(struct dll_node), ...
points sizeof(struct dll_node) * sizeof *n
(equal to sizeof(struct dll_node) * sizeof(struct dll_node)
) bytes beyond where n
points to.
You probably want to just "seek" sizeof(struct dll_node)
bytes.
Do to so change your code to be:
memcpy((char*)n + sizeof(struct dll_node), ...
or, as n
is a pointer to struct dll_node
, just do
memcpy(n + 1, ...
to get beyond a struct dll_node
.