Changelog
Daniel Stenberg (11 Mar 2008)
+- Dmitry Popov filed bug report #1911069
+ (http://curl.haxx.se/bug/view.cgi?id=1911069) that identified a race
+ condition in the name resolver code when the DNS cache is shared between
+ multiple easy handles, each running in simultaneous threads that could cause
+ crashes.
+
- Added a macro for curl_easy_setopt() that accepts three arguments and simply
does nothing with them, just to make sure libcurl users always use three
arguments to this function. Due to its use of ... for the third argument, it
o better MIT kerberos configure check
o curl_easy_reset() + SFTP re-used connection download crash
o SFTP non-existing file + SFTP existing file error
+ o sharing DNS cache between easy handles running in multiple threads could
+ lead to crash
This release includes the following known bugs:
Michal Marek, Dmitry Kurochkin, Niklas Angebrand, Günter Knauf, Yang Tse,
Dan Fandrich, Mike Hommey, Pooyan McSporran, Jerome Muffat-Meridol,
Kaspar Brand, Gautam Kachroo, Zmey Petroff, Georg Lippitsch, Sam Listopad,
- Anatoli Tubman, Mike Protts, Michael Calmer, Brian Ulm
+ Anatoli Tubman, Mike Protts, Michael Calmer, Brian Ulm, Dmitry Popov
Thanks! (and sorry if I forgot to mention someone)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
+/*
+ * Check if the entry should be pruned. Assumes a locked cache.
+ */
static int
remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
{
if( !hostcache_timestamp_remove(&user,dns) )
return 0;
- /* ok, we do need to clear the cache. although we need to remove just a
- single entry we clean the entire hash, as no explicit delete function
- is provided */
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
Curl_hash_clean_with_criterium(data->dns.hostcache,
(void *) &user,
hostcache_timestamp_remove);
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-
return 1;
}
size_t entry_len;
struct SessionHandle *data = conn->data;
CURLcode result;
- int rc;
+ int rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
#ifdef HAVE_SIGSETJMP
if(sigsetjmp(curl_jmpenv, 1)) {
/* this is coming from a siglongjmp() */
failf(data, "name lookup timed out");
- return CURLRESOLV_ERROR;
+ return rc;
}
}
#endif
entry_id = create_hostcache_id(hostname, port);
/* If we can't create the entry id, fail */
if(!entry_id)
- return CURLRESOLV_ERROR;
+ return rc;
entry_len = strlen(entry_id);
/* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+ /* See whether the returned entry is stale. Done before we release lock */
+ if( remove_entry_if_stale(data, dns) )
+ dns = NULL; /* the memory deallocation is being handled by the hash */
+
+ if(dns) {
+ dns->inuse++; /* we use it! */
+ rc = CURLRESOLV_RESOLVED;
+ }
+
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
/* free the allocated entry_id again */
free(entry_id);
- /* See whether the returned entry is stale. Deliberately done after the
- locked block */
- if( remove_entry_if_stale(data,dns) )
- dns = NULL; /* the memory deallocation is being handled by the hash */
-
- rc = CURLRESOLV_ERROR; /* default to failure */
-
if(!dns) {
/* The entry was not in the cache. Resolve it to IP address */
rc = CURLRESOLV_RESOLVED;
}
}
- else {
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- dns->inuse++; /* we use it! */
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
- rc = CURLRESOLV_RESOLVED;
- }
*entry = dns;