aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2003-09-14 21:17:54 +0000
committerDaniel Stenberg <daniel@haxx.se>2003-09-14 21:17:54 +0000
commit14597475b19a63ae2fc886a7747802f6d26cfa2f (patch)
tree378975f14d1566c84ee4e41479f7f222d666b19a
parentde3281a3a84e653f901f3955454c6c1249061591 (diff)
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.
-rw-r--r--lib/hash.c21
-rw-r--r--lib/hash.h2
-rw-r--r--lib/hostip.c21
3 files changed, 25 insertions, 19 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;
-
- /* Store it in our dns cache */
- Curl_hash_add(data->hostcache, entry_id, entry_len+1,
- (const void *) dns);
+ dns->inuse = 0; /* init to not used */
+ dns->addr = addr; /* this is the address(es) */
+
+ /* 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 */