From: Nick Mathewson Date: Wed, 7 Nov 2007 05:02:21 +0000 (+0000) Subject: r16497@catbus: nickm | 2007-11-07 00:01:02 -0500 X-Git-Tag: release-2.0.1-alpha~525 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=206d43363817c4dc77976f85a9df04a411c7913c;p=libevent r16497@catbus: nickm | 2007-11-07 00:01:02 -0500 Resolve issue 1826588: make event_base_free() succeed even if there are pending non-INTERNAL events still in the base. This can leak memory and fds if used injudiciously, but at least it no longer crashes. svn:r490 --- diff --git a/ChangeLog b/ChangeLog index a78429ed..f772e6e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -40,4 +40,4 @@ Changes in current version: o Remove support for the rtsig method: it hasn't compiled for a while, and nobody seems to miss it very much. Let us know if there's a good reason to put it back in. o Rename the "class" field in evdns_server_request to dns_question_class, so that it won't break compilation under C++. Use a macro so that old code won't break. Mark the macro as deprecated. o Fix DNS unit tests so that having a DNS server with broken IPv6 support is no longer cause for aborting the unit tests. - + o Make event_base_free() succeed even if there are pending non-internal events on a base. This may still leak memory and fds, but at least it no longer crashes. diff --git a/event.c b/event.c index 391d317f..fb94691b 100644 --- a/event.c +++ b/event.c @@ -199,17 +199,32 @@ event_init(void) void event_base_free(struct event_base *base) { - int i; + int i, n_deleted=0; + struct event *ev; if (base == NULL && current_base) base = current_base; - if (base == current_base) + if (base == current_base) current_base = NULL; /* XXX(niels) - check for internal events first */ assert(base); + /* Delete all non-internal events. */ + for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) { + struct event *next = TAILQ_NEXT(ev, ev_next); + if (!(ev->ev_flags & EVLIST_INTERNAL)) { + event_del(ev); + ++n_deleted; + } + ev = next; + } + if (n_deleted) + event_debug(("%s: %d events were still set in base", + __func__, n_deleted)); + if (base->evsel->dealloc != NULL) base->evsel->dealloc(base, base->evbase); + for (i=0; i < base->nactivequeues; ++i) assert(TAILQ_EMPTY(base->activequeues[i])); assert(min_heap_empty(&base->timeheap)); diff --git a/test/regress.c b/test/regress.c index 24ced27a..e098f61c 100644 --- a/test/regress.c +++ b/test/regress.c @@ -557,6 +557,22 @@ test_signal_switchbase(void) } #endif +void +test_free_active_base(void) +{ + struct event_base *base1; + struct event ev1; + setup_test("Free active base: "); + base1 = event_init(); + event_set(&ev1, pair[1], EV_READ, simple_read_cb, &ev1); + event_base_set(base1, &ev1); + event_add(&ev1, NULL); + /* event_del(&ev1); */ + event_base_free(base1); + test_ok = 1; + cleanup_test(); +} + void test_loopexit(void) { @@ -1063,6 +1079,8 @@ main (int argc, char **argv) test_bufferevent(); + test_free_active_base(); + http_suite(); rpc_suite();