From 7cf47a7740f666ae3c06361781a341a7da403041 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 21 Dec 2024 11:16:09 +0100 Subject: [PATCH] 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 --- lib/llist.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/llist.c b/lib/llist.c index 8edbab2431..a2c199bc62 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -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)