]> granicus.if.org Git - libevent/commitdiff
Avoid segfault on weird timeout during name lookup.
authorGreg Hazel <ghazel@gmail.com>
Mon, 30 Jul 2012 20:52:55 +0000 (16:52 -0400)
committerNick Mathewson <nickm@torproject.org>
Mon, 30 Jul 2012 21:01:52 +0000 (17:01 -0400)
If an evdns_getaddrinfo timeout happens while pending_cb is set, and
a callback is about to run, but we get a call to
evdns_getaddrinfo_gotresolve before it finishes.

Github issue #60. Thanks to Greg Hazel for patch and patience.

evdns.c

diff --git a/evdns.c b/evdns.c
index d648c936cc0a84ff342aea122d240d6cf47178e3..e9cea45b52720535633c2577fcf2453cb5784630 100644 (file)
--- a/evdns.c
+++ b/evdns.c
@@ -4214,6 +4214,8 @@ evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
 
        /* Cancel any pending requests, and note which one */
        if (data->ipv4_request.r) {
+               /* XXXX This does nothing if the request's callback is already
+                * running (pending_cb is set). */
                evdns_cancel_request(NULL, data->ipv4_request.r);
                v4_timedout = 1;
                EVDNS_LOCK(data->evdns_base);
@@ -4221,6 +4223,8 @@ evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
                EVDNS_UNLOCK(data->evdns_base);
        }
        if (data->ipv6_request.r) {
+               /* XXXX This does nothing if the request's callback is already
+                * running (pending_cb is set). */
                evdns_cancel_request(NULL, data->ipv6_request.r);
                v6_timedout = 1;
                EVDNS_LOCK(data->evdns_base);
@@ -4244,6 +4248,10 @@ evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
                data->user_cb(e, NULL, data->user_data);
        }
 
+       data->user_cb = NULL; /* prevent double-call if evdns callbacks are
+                              * in-progress. XXXX It would be better if this
+                              * weren't necessary. */
+
        if (!v4_timedout && !v6_timedout) {
                /* should be impossible? XXXX */
                free_getaddrinfo_request(data);
@@ -4314,6 +4322,13 @@ evdns_getaddrinfo_gotresolve(int result, char type, int count,
                return;
        }
 
+       if (data->user_cb == NULL) {
+               /* We already answered.  XXXX This shouldn't be needed; see
+                * comments in evdns_getaddrinfo_timeout_cb */
+               free_getaddrinfo_request(data);
+               return;
+       }
+
        if (result == DNS_ERR_NONE) {
                if (count == 0)
                        err = EVUTIL_EAI_NODATA;