Fix issue #127, double free for filterevents that use BEV_OPT_CLOSE_ON_FREE

This commit is contained in:
John Ohl 2014-04-30 13:55:49 -04:00 committed by Nick Mathewson
parent 571295bdf8
commit 2c82aa0fef

View File

@ -425,26 +425,34 @@ be_filter_readcb(struct bufferevent *underlying, void *me_)
enum bufferevent_filter_result res; enum bufferevent_filter_result res;
enum bufferevent_flush_mode state; enum bufferevent_flush_mode state;
struct bufferevent *bufev = downcast(bevf); struct bufferevent *bufev = downcast(bevf);
struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
int processed_any = 0; int processed_any = 0;
bufferevent_incref_and_lock_(bufev); BEV_LOCK(bufev);
if (bevf->got_eof) // It's possible our refcount is 0 at this point if another thread free'd our filterevent
state = BEV_FINISHED; EVUTIL_ASSERT(bufev_private->refcnt >= 0);
else
state = BEV_NORMAL;
/* XXXX use return value */ // If our refcount is > 0
res = be_filter_process_input(bevf, state, &processed_any); if (bufev_private->refcnt > 0) {
(void)res;
/* XXX This should be in process_input, not here. There are if (bevf->got_eof)
* other places that can call process-input, and they should state = BEV_FINISHED;
* force readcb calls as needed. */ else
if (processed_any) state = BEV_NORMAL;
bufferevent_trigger_nolock_(bufev, EV_READ, 0);
bufferevent_decref_and_unlock_(bufev); /* XXXX use return value */
res = be_filter_process_input(bevf, state, &processed_any);
(void)res;
/* XXX This should be in process_input, not here. There are
* other places that can call process-input, and they should
* force readcb calls as needed. */
if (processed_any)
bufferevent_trigger_nolock_(bufev, EV_READ, 0);
}
BEV_UNLOCK(bufev);
} }
/* Called when the underlying socket has drained enough that we can write to /* Called when the underlying socket has drained enough that we can write to
@ -454,11 +462,20 @@ be_filter_writecb(struct bufferevent *underlying, void *me_)
{ {
struct bufferevent_filtered *bevf = me_; struct bufferevent_filtered *bevf = me_;
struct bufferevent *bev = downcast(bevf); struct bufferevent *bev = downcast(bevf);
struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
int processed_any = 0; int processed_any = 0;
bufferevent_incref_and_lock_(bev); BEV_LOCK(bev);
be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
bufferevent_decref_and_unlock_(bev); // It's possible our refcount is 0 at this point if another thread free'd our filterevent
EVUTIL_ASSERT(bufev_private->refcnt >= 0);
// If our refcount is > 0
if (bufev_private->refcnt > 0) {
be_filter_process_output(bevf, BEV_NORMAL, &processed_any);
}
BEV_UNLOCK(bev);
} }
/* Called when the underlying socket has given us an error */ /* Called when the underlying socket has given us an error */
@ -467,11 +484,21 @@ be_filter_eventcb(struct bufferevent *underlying, short what, void *me_)
{ {
struct bufferevent_filtered *bevf = me_; struct bufferevent_filtered *bevf = me_;
struct bufferevent *bev = downcast(bevf); struct bufferevent *bev = downcast(bevf);
struct bufferevent_private *bufev_private = BEV_UPCAST(bev);
bufferevent_incref_and_lock_(bev); BEV_LOCK(bev);
/* All we can really to is tell our own eventcb. */
bufferevent_run_eventcb_(bev, what, 0); // It's possible our refcount is 0 at this point if another thread free'd our filterevent
bufferevent_decref_and_unlock_(bev); EVUTIL_ASSERT(bufev_private->refcnt >= 0);
// If our refcount is > 0
if (bufev_private->refcnt > 0) {
/* All we can really to is tell our own eventcb. */
bufferevent_run_eventcb_(bev, what, 0);
}
BEV_UNLOCK(bev);
} }
static int static int