Valgrind 错误和每个元素一个分配的通用列表

Valgrind error and generic list with one allocation per element

我正在试验链表并尝试创建一个通用双向链表,它只为每个节点分配一次内存。这意味着节点的内存和节点包含的元素是在同一个 malloc 调用中分配的。 列表本身是一个包含单位大小的结构(初始化为 sizeof(struct which_is_an_element):

struct doubly_linked_list
{
    struct dll_node *head, *tail;
    size_t elem_size;
};

节点:

struct dll_node
{
    struct dll_node *next, *prev;
    void *elem;
};

现在,当我尝试插入元素并对其进行初始化时:

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;
}

我收到一个 valgrind 错误:

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"

  1. 真的 memcpy 在未分配块内写入,因为已分配内存的大小等于 sizeof(struct which_is_an_element) + sizeof(dll_node) 吗?
  2. 这些问题是由 valgrind 认为分配的内存大小 = sizeof(struct dll_node) 引起的,因为 new_node 函数中指向数据的指针类型称为 n 吗?
  3. 这个方法好吗?我可以为每个元素分配一次内存还是应该为节点和元素分别分配内存?
  4. 如果这种方法很好,那么我怎样才能摆脱这个 valgrind 错误?

Does really memcpy write inside unallocated block as the size of the allocated memory is equal to sizeof(struct which_is_an_element) + sizeof(dll_node)?

是的。

memcpy(n + sizeof(struct dll_node), ... 指向 sizeof(struct dll_node) * sizeof *n(等于 sizeof(struct dll_node) * sizeof(struct dll_node))字节超出 n 指向的位置。

您可能只想 "seek" sizeof(struct dll_node) 字节。

这样做,将您的代码更改为:

memcpy((char*)n + sizeof(struct dll_node), ...

或者,作为 n 指向 struct dll_node 的指针,只需要

memcpy(n + 1, ...

超越 struct dll_node