From 14597475b19a63ae2fc886a7747802f6d26cfa2f Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 14 Sep 2003 21:17:54 +0000 Subject: [PATCH] Jeff Pohlmeyer did some marvelous debugging to track this one down. We MUST NOT free the existing hash entry when we try to add a new one that matches an existing entry. We now instead free the new one, and make the parent function use the old entry's struct instead. --- lib/hash.c | 21 ++++++++++----------- lib/hash.h | 2 +- lib/hostip.c | 19 +++++++++++++------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/hash.c b/lib/hash.c index 1743db3c7..89078d1f3 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -138,34 +138,33 @@ mk_hash_element(char *key, size_t key_len, const void *p) #define FETCH_LIST(x,y,z) x->table[find_slot(x, y, z)] -int -Curl_hash_add(curl_hash *h, char *key, size_t key_len, const void *p) +/* Return the data in the hash. If there already was a match in the hash, + that data is returned. */ +void * +Curl_hash_add(curl_hash *h, char *key, size_t key_len, void *p) { curl_hash_element *he; curl_llist_element *le; curl_llist *l = FETCH_LIST(h, key, key_len); - for (le = l->head; - le; - le = le->next) { + for (le = l->head; le; le = le->next) { he = (curl_hash_element *) le->ptr; if (hash_key_compare(he->key, he->key_len, key, key_len)) { - h->dtor(he->ptr); - he->ptr = (void *) p; - return 1; + h->dtor(p); /* remove the NEW entry */ + return he->ptr; /* return the EXISTING entry */ } } he = mk_hash_element(key, key_len, p); if (!he) - return 0; + return NULL; /* failure */ if (Curl_llist_insert_next(l, l->tail, he)) { ++h->size; - return 1; + return p; /* return the new entry */ } - return 0; + return NULL; /* failure */ } #if 0 diff --git a/lib/hash.h b/lib/hash.h index 03c771a47..9009df75a 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -47,7 +47,7 @@ typedef struct _curl_hash_element { int Curl_hash_init(curl_hash *, int, curl_hash_dtor); curl_hash *Curl_hash_alloc(int, curl_hash_dtor); -int Curl_hash_add(curl_hash *, char *, size_t, const void *); +void *Curl_hash_add(curl_hash *, char *, size_t, void *); int Curl_hash_delete(curl_hash *h, char *key, size_t key_len); void *Curl_hash_pick(curl_hash *, char *, size_t); void Curl_hash_apply(curl_hash *h, void *user, diff --git a/lib/hostip.c b/lib/hostip.c index c397a3c75..3f465a0d0 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -231,15 +231,22 @@ cache_resolv_response(struct SessionHandle *data, return NULL; } - dns->inuse = 0; - dns->addr = addr; + dns->inuse = 0; /* init to not used */ + dns->addr = addr; /* this is the address(es) */ - /* Store it in our dns cache */ - Curl_hash_add(data->hostcache, entry_id, entry_len+1, - (const void *) dns); + /* Store the resolved data in our DNS cache. This function may return a + pointer to an existing struct already present in the hash, and it may + return the same argument we pass in. Make no assumptions. */ + dns = Curl_hash_add(data->hostcache, entry_id, entry_len+1, (void *) dns); + if(!dns) { + /* major badness, run away! */ + Curl_freeaddrinfo(addr); + free(entry_id); + return NULL; + } time(&now); - dns->timestamp = now; + dns->timestamp = now; /* used now */ dns->inuse++; /* mark entry as in-use */