]> granicus.if.org Git - libevent/commitdiff
Fix segfault during failed allocatino of locked evdns base.
authorNick Mathewson <nickm@torproject.org>
Tue, 28 Jul 2009 17:11:03 +0000 (17:11 +0000)
committerNick Mathewson <nickm@torproject.org>
Tue, 28 Jul 2009 17:11:03 +0000 (17:11 +0000)
We need to comb the rest of the code to make sure that we don't blindly wrap
functions in LOCK(x), UNLOCK(x) when those functions might contain a FREE(x)
in the middle.

Rocco Carbone found and reported this bug.

svn:r1384

ChangeLog
evdns.c

index 1ccc2143fd7267912b3b11faac9228476e8fa2d0..0a1a9df93375078cc11b5bab93d6c5a13613f4db 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 Changes in 2.0.3-alpha:
  o Add a new code to support SSL/TLS on bufferevents, using the OpenSSL library (where available).
  o Fix a bug where we didn't allocate enough memory in event_get_supported_methods().
+ o Avoid segfault during failed allocation of locked evdns_base. (Found by Rocco Carbone.)
 
 Changes in 2.0.2-alpha:
  o Add a new flag to bufferevents to make all callbacks automatically deferred.
diff --git a/evdns.c b/evdns.c
index 6962cc19dbed794e465018ba34b881f076d7d19c..ffada0eba78dee75ebbcc2c4731c183746543d6c 100644 (file)
--- a/evdns.c
+++ b/evdns.c
@@ -386,6 +386,7 @@ static void server_port_ready_callback(evutil_socket_t fd, short events, void *a
 static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
 static int evdns_base_set_option_impl(struct evdns_base *base,
     const char *option, const char *val, int flags);
+static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
 
 static int strtoint(const char *const str);
 
@@ -3608,8 +3609,8 @@ evdns_base_new(struct event_base *event_base, int initialize_nameservers)
                r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
 #endif
                if (r == -1) {
-                       evdns_base_free(base, 0);
-                       base = NULL;
+                       evdns_base_free_and_unlock(base, 0);
+                       return NULL;
                }
        }
        EVDNS_UNLOCK(base);
@@ -3648,16 +3649,16 @@ evdns_err_to_string(int err)
     }
 }
 
-void
-evdns_base_free(struct evdns_base *base, int fail_requests)
+static void
+evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
 {
        struct nameserver *server, *server_next;
        struct search_domain *dom, *dom_next;
        int i;
 
-       /* TODO(nickm) we might need to refcount here. */
+       /* Requires that we hold the lock. */
 
-       EVDNS_LOCK(base);
+       /* TODO(nickm) we might need to refcount here. */
 
        for (i = 0; i < base->n_req_heads; ++i) {
                while (base->req_heads[i]) {
@@ -3701,12 +3702,20 @@ evdns_base_free(struct evdns_base *base, int fail_requests)
        mm_free(base);
 }
 
+void
+evdns_base_free(struct evdns_base *base, int fail_requests)
+{
+       EVDNS_LOCK(base);
+       evdns_base_free_and_unlock(base, fail_requests);
+}
+
 void
 evdns_shutdown(int fail_requests)
 {
        if (current_base) {
-               evdns_base_free(current_base, fail_requests);
+               struct evdns_base *b = current_base;
                current_base = NULL;
+               evdns_base_free(b, fail_requests);
        }
        evdns_log_fn = NULL;
 }