]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
hash: lazy-alloc the table in Curl_hash_add() 8132/head
authorDaniel Stenberg <daniel@haxx.se>
Fri, 10 Dec 2021 11:54:17 +0000 (12:54 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 10 Dec 2021 22:16:43 +0000 (23:16 +0100)
This makes Curl_hash_init() infallible which saves error paths.

Closes #8132

lib/conncache.c
lib/hash.c
lib/hash.h
lib/hostip.c
lib/hostip.h
lib/multi.c
lib/share.c
tests/unit/unit1305.c
tests/unit/unit1602.c
tests/unit/unit1603.c

index f5ba8ff70a82a1f5028ecb32eede2c0c5b542122..fec1937f0bb497235d4542c95023cf27fd407120 100644 (file)
@@ -113,21 +113,16 @@ static void free_bundle_hash_entry(void *freethis)
 
 int Curl_conncache_init(struct conncache *connc, int size)
 {
-  int rc;
-
   /* allocate a new easy handle to use when closing cached connections */
   connc->closure_handle = curl_easy_init();
   if(!connc->closure_handle)
     return 1; /* bad */
 
-  rc = Curl_hash_init(&connc->hash, size, Curl_hash_str,
-                      Curl_str_key_compare, free_bundle_hash_entry);
-  if(rc)
-    Curl_close(&connc->closure_handle);
-  else
-    connc->closure_handle->state.conn_cache = connc;
+  Curl_hash_init(&connc->hash, size, Curl_hash_str,
+                 Curl_str_key_compare, free_bundle_hash_entry);
+  connc->closure_handle->state.conn_cache = connc;
 
-  return rc;
+  return 0; /* good */
 }
 
 void Curl_conncache_destroy(struct conncache *connc)
index f04c462840d15792a67a97324e46f8de659dc3e8..8848906947ba111ae46125e9f6fa5346618e8ae2 100644 (file)
@@ -53,32 +53,25 @@ hash_element_dtor(void *user, void *element)
  * @unittest: 1602
  * @unittest: 1603
  */
-int
+void
 Curl_hash_init(struct Curl_hash *h,
                int slots,
                hash_function hfunc,
                comp_function comparator,
                Curl_hash_dtor dtor)
 {
-  if(!slots || !hfunc || !comparator ||!dtor) {
-    return 1; /* failure */
-  }
+  DEBUGASSERT(h);
+  DEBUGASSERT(slots);
+  DEBUGASSERT(hfunc);
+  DEBUGASSERT(comparator);
+  DEBUGASSERT(dtor);
 
+  h->table = NULL;
   h->hash_func = hfunc;
   h->comp_func = comparator;
   h->dtor = dtor;
   h->size = 0;
   h->slots = slots;
-
-  h->table = malloc(slots * sizeof(struct Curl_llist));
-  if(h->table) {
-    int i;
-    for(i = 0; i < slots; ++i)
-      Curl_llist_init(&h->table[i], (Curl_llist_dtor) hash_element_dtor);
-    return 0; /* fine */
-  }
-  h->slots = 0;
-  return 1; /* failure */
 }
 
 static struct Curl_hash_element *
@@ -98,8 +91,9 @@ mk_hash_element(const void *key, size_t key_len, const void *p)
 
 #define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
 
-/* Insert the data in the hash. If there already was a match in the hash,
- * that data is replaced.
+/* Insert the data in the hash. If there already was a match in the hash, that
+ * data is replaced. This function also "lazily" allocates the table if
+ * needed, as it isn't done in the _init function (anymore).
  *
  * @unittest: 1305
  * @unittest: 1602
@@ -111,7 +105,18 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
   struct Curl_hash_element  *he;
   struct Curl_llist_element *le;
   struct Curl_llist *l;
+
+  DEBUGASSERT(h);
   DEBUGASSERT(h->slots);
+  if(!h->table) {
+    int i;
+    h->table = malloc(h->slots * sizeof(struct Curl_llist));
+    if(!h->table)
+      return NULL; /* OOM */
+    for(i = 0; i < h->slots; ++i)
+      Curl_llist_init(&h->table[i], hash_element_dtor);
+  }
+
   l = FETCH_LIST(h, key, key_len);
 
   for(le = l->head; le; le = le->next) {
@@ -142,15 +147,19 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
 {
   struct Curl_llist_element *le;
   struct Curl_llist *l;
+
+  DEBUGASSERT(h);
   DEBUGASSERT(h->slots);
-  l = FETCH_LIST(h, key, key_len);
+  if(h->table) {
+    l = FETCH_LIST(h, key, key_len);
 
-  for(le = l->head; le; le = le->next) {
-    struct Curl_hash_element *he = le->ptr;
-    if(h->comp_func(he->key, he->key_len, key, key_len)) {
-      Curl_llist_remove(l, le, (void *) h);
-      --h->size;
-      return 0;
+    for(le = l->head; le; le = le->next) {
+      struct Curl_hash_element *he = le->ptr;
+      if(h->comp_func(he->key, he->key_len, key, key_len)) {
+        Curl_llist_remove(l, le, (void *) h);
+        --h->size;
+        return 0;
+      }
     }
   }
   return 1;
@@ -166,7 +175,8 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
   struct Curl_llist_element *le;
   struct Curl_llist *l;
 
-  if(h) {
+  DEBUGASSERT(h);
+  if(h->table) {
     DEBUGASSERT(h->slots);
     l = FETCH_LIST(h, key, key_len);
     for(le = l->head; le; le = le->next) {
@@ -209,13 +219,13 @@ Curl_hash_apply(Curl_hash *h, void *user,
 void
 Curl_hash_destroy(struct Curl_hash *h)
 {
-  int i;
-
-  for(i = 0; i < h->slots; ++i) {
-    Curl_llist_destroy(&h->table[i], (void *) h);
+  if(h->table) {
+    int i;
+    for(i = 0; i < h->slots; ++i) {
+      Curl_llist_destroy(&h->table[i], (void *) h);
+    }
+    Curl_safefree(h->table);
   }
-
-  Curl_safefree(h->table);
   h->size = 0;
   h->slots = 0;
 }
@@ -240,7 +250,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
   struct Curl_llist *list;
   int i;
 
-  if(!h)
+  if(!h || !h->table)
     return;
 
   for(i = 0; i < h->slots; ++i) {
@@ -295,6 +305,9 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
 {
   struct Curl_hash *h = iter->hash;
 
+  if(!h->table)
+    return NULL; /* empty hash, nothing to return */
+
   /* Get the next element in the current list, if any */
   if(iter->current_element)
     iter->current_element = iter->current_element->next;
index b7f828e0716d0d1145707ca57b28d79ff9ccf56c..e166916a90b77080156c6d56540ea5d481caffbf 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -69,11 +69,11 @@ struct Curl_hash_iterator {
   struct Curl_llist_element *current_element;
 };
 
-int Curl_hash_init(struct Curl_hash *h,
-                   int slots,
-                   hash_function hfunc,
-                   comp_function comparator,
-                   Curl_hash_dtor dtor);
+void Curl_hash_init(struct Curl_hash *h,
+                    int slots,
+                    hash_function hfunc,
+                    comp_function comparator,
+                    Curl_hash_dtor dtor);
 
 void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
 int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
index c33c9af9d0df7415c493c04733aa8fc05ce559c7..5d942dca00293736e463dca74494121d4ba3b891 100644 (file)
@@ -977,12 +977,12 @@ static void freednsentry(void *freethis)
 }
 
 /*
- * Curl_mk_dnscache() inits a new DNS cache and returns success/failure.
+ * Curl_init_dnscache() inits a new DNS cache.
  */
-int Curl_mk_dnscache(struct Curl_hash *hash)
+void Curl_init_dnscache(struct Curl_hash *hash)
 {
-  return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
-                        freednsentry);
+  Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
+                 freednsentry);
 }
 
 /*
index 67a688aebdc0193fad03de337288ce74da8fa5b8..1db5981842f14a611316666c68379cd06b0306d2 100644 (file)
@@ -129,8 +129,8 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
 void Curl_resolv_unlock(struct Curl_easy *data,
                         struct Curl_dns_entry *dns);
 
-/* init a new dns cache and return success */
-int Curl_mk_dnscache(struct Curl_hash *hash);
+/* init a new dns cache */
+void Curl_init_dnscache(struct Curl_hash *hash);
 
 /* prune old entries from the DNS cache */
 void Curl_hostcache_prune(struct Curl_easy *data);
index 2bda972236130c264ffaa3ec6f8713c56619a28a..f8dcc63b471f7a8071265f5be114f7ee77b9ff75 100644 (file)
@@ -281,11 +281,8 @@ static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
   if(!check)
     return NULL; /* major failure */
 
-  if(Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash,
-                    trhash_compare, trhash_dtor)) {
-    free(check);
-    return NULL;
-  }
+  Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare,
+                 trhash_dtor);
 
   /* make/add new hash entry */
   if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
@@ -352,10 +349,10 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
  * per call."
  *
  */
-static int sh_init(struct Curl_hash *hash, int hashsize)
+static void sh_init(struct Curl_hash *hash, int hashsize)
 {
-  return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
-                        sh_freeentry);
+  Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
+                 sh_freeentry);
 }
 
 /*
@@ -382,11 +379,9 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
 
   multi->magic = CURL_MULTI_HANDLE;
 
-  if(Curl_mk_dnscache(&multi->hostcache))
-    goto error;
+  Curl_init_dnscache(&multi->hostcache);
 
-  if(sh_init(&multi->sockhash, hashsize))
-    goto error;
+  sh_init(&multi->sockhash, hashsize);
 
   if(Curl_conncache_init(&multi->conn_cache, chashsize))
     goto error;
index 9c43c8f70534887236d85f20daa470913f7c9a1c..403563fdd6e6291d464349648296e14f22e119d8 100644 (file)
@@ -39,11 +39,7 @@ curl_share_init(void)
   if(share) {
     share->magic = CURL_GOOD_SHARE;
     share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
-
-    if(Curl_mk_dnscache(&share->hostcache)) {
-      free(share);
-      return NULL;
-    }
+    Curl_init_dnscache(&share->hostcache);
   }
 
   return share;
index b0e8eda5e31bcd22e96387cf1df273d95650545c..8e551c79074dfca001984c995e9a7a2aa8611c4a 100644 (file)
@@ -46,19 +46,13 @@ static struct Curl_dns_entry *data_node;
 
 static CURLcode unit_setup(void)
 {
-  int rc;
   data = curl_easy_init();
   if(!data) {
     curl_global_cleanup();
     return CURLE_OUT_OF_MEMORY;
   }
 
-  rc = Curl_mk_dnscache(&hp);
-  if(rc) {
-    curl_easy_cleanup(data);
-    curl_global_cleanup();
-    return CURLE_OUT_OF_MEMORY;
-  }
+  Curl_init_dnscache(&hp);
   return CURLE_OK;
 }
 
index ee6acacc547c0ab695b1af501e927da83b167ab1..bb6e504c4ed1669aacfce1b0647880b5c5ddd88b 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -38,8 +38,9 @@ static void mydtor(void *p)
 
 static CURLcode unit_setup(void)
 {
-  return Curl_hash_init(&hash_static, 7, Curl_hash_str,
-                        Curl_str_key_compare, mydtor);
+  Curl_hash_init(&hash_static, 7, Curl_hash_str,
+                 Curl_str_key_compare, mydtor);
+  return CURLE_OK;
 }
 
 static void unit_stop(void)
index f9170ef995456f7696c897e926acedb87bc3a235..86641d61f567f4819472c8e0af497e348f4bfd4e 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -39,8 +39,9 @@ static void mydtor(void *p)
 
 static CURLcode unit_setup(void)
 {
-  return Curl_hash_init(&hash_static, slots, Curl_hash_str,
-                        Curl_str_key_compare, mydtor);
+  Curl_hash_init(&hash_static, slots, Curl_hash_str,
+                 Curl_str_key_compare, mydtor);
+  return CURLE_OK;
 }
 
 static void unit_stop(void)