From 12199fa7a51ee93479fa0db30c2f7b9c8159bb94 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Tue, 28 Jul 2009 17:11:03 +0000 Subject: [PATCH] Fix segfault during failed allocatino of locked evdns base. 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 | 1 + evdns.c | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ccc2143..0a1a9df9 100644 --- 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 6962cc19..ffada0eb 100644 --- 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; }