]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
llist: survive cleared list better
authorDaniel Stenberg <daniel@haxx.se>
Sat, 21 Dec 2024 10:16:09 +0000 (11:16 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 21 Dec 2024 13:18:22 +0000 (14:18 +0100)
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

index 8edbab243143d70ef6a7c565a7d2c6d4cea656b0..a2c199bc626bb7b2483687923c049756e32733d5 100644 (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;
-  }
-  else {
-    if(e->_prev)
-      e->_prev->_next = e->_next;
+      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;
+      if(!e->_next)
+        list->_tail = e->_prev;
+      else
+        e->_next->_prev = e->_prev;
+    }
+    --list->_size;
   }
-
   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)