llist: survive cleared list better

Make Curl_node_uremove() and Curl_node_take_elem() properly survive
run-time when the ->list field has been cleared previously. Like when
Curl_node_take_elem() is called twice.

We have asserts to catch those situations to make sure we avoid them if
we can, but if they still happen in a non-debug build we should make
sure the functions survive proper.

Pointed out by CodeSonar.

Closes #15791
This commit is contained in:
Daniel Stenberg 2024-12-21 11:16:09 +01:00
parent 34713ed8a5
commit 7cf47a7740
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -146,24 +146,26 @@ void *Curl_node_take_elem(struct Curl_llist_node *e)
DEBUGASSERT(list->_init == LLISTINIT);
DEBUGASSERT(list->_size);
DEBUGASSERT(e->_init == NODEINIT);
if(e == list->_head) {
list->_head = e->_next;
if(list) {
if(e == list->_head) {
list->_head = e->_next;
if(!list->_head)
list->_tail = NULL;
else
e->_next->_prev = NULL;
if(!list->_head)
list->_tail = NULL;
else
e->_next->_prev = NULL;
}
else {
if(e->_prev)
e->_prev->_next = e->_next;
if(!e->_next)
list->_tail = e->_prev;
else
e->_next->_prev = e->_prev;
}
--list->_size;
}
else {
if(e->_prev)
e->_prev->_next = e->_next;
if(!e->_next)
list->_tail = e->_prev;
else
e->_next->_prev = e->_prev;
}
ptr = e->_ptr;
e->_list = NULL;
@ -174,7 +176,6 @@ void *Curl_node_take_elem(struct Curl_llist_node *e)
e->_init = NODEREM; /* specific pattern on remove - not zero */
#endif
--list->_size;
return ptr;
}
@ -191,9 +192,11 @@ Curl_node_uremove(struct Curl_llist_node *e, void *user)
list = e->_list;
DEBUGASSERT(list);
ptr = Curl_node_take_elem(e);
if(list->_dtor)
list->_dtor(user, ptr);
if(list) {
ptr = Curl_node_take_elem(e);
if(list->_dtor)
list->_dtor(user, ptr);
}
}
void Curl_node_remove(struct Curl_llist_node *e)