From: Azat Khuzhin Date: Tue, 27 Feb 2018 18:12:14 +0000 (+0300) Subject: Fix base unlocking in event_del() if event_base_set() runned in another thread X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=08a0d366073eacf800027725891c2f668f2f0144;p=libevent Fix base unlocking in event_del() if event_base_set() runned in another thread Image next situation: T1: T2: event_del_() lock the event.ev_base.th_base_lock event_del_nolock_() event_set_base() unlock the event.ev_base.th_base_lock In this case we will unlock the wrong base after event_del_nolock_() returns, and deadlock is likely to happens, since event_base_set() do not check any mutexes (due to it is possible to do this only if event is not inserted anywhere). So event_del_() has to cache the base before removing the event, and cached base.th_base_lock after. --- diff --git a/event.c b/event.c index 17570c27..c5560707 100644 --- a/event.c +++ b/event.c @@ -2749,17 +2749,16 @@ static int event_del_(struct event *ev, int blocking) { int res; + struct event_base *base = ev->ev_base; - if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) { + if (EVUTIL_FAILURE_CHECK(!base)) { event_warnx("%s: event has no event_base set.", __func__); return -1; } - EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock); - + EVBASE_ACQUIRE_LOCK(base, th_base_lock); res = event_del_nolock_(ev, blocking); - - EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock); + EVBASE_RELEASE_LOCK(base, th_base_lock); return (res); }