From: Nick Mathewson Date: Tue, 28 Jul 2009 17:11:03 +0000 (+0000) Subject: Fix segfault during failed allocatino of locked evdns base. X-Git-Tag: release-2.0.3-alpha~154 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=12199fa7a51ee93479fa0db30c2f7b9c8159bb94;p=libevent 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 --- 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; }