Fix a segfault when freeing SSL bufferevents in an unusual order

Have container bufferevents hold a reference to their underlying bufferevents.

(Commit message and minor revisions by nickm.)
This commit is contained in:
Joachim Bauch 2009-12-18 16:24:41 -05:00 committed by Nick Mathewson
parent a6adeca72c
commit a773df54ce
4 changed files with 18 additions and 1 deletions

View File

@ -217,6 +217,8 @@ void _bufferevent_incref_and_lock(struct bufferevent *bufev);
/** Internal: Drop the reference count on bufev, freeing as necessary, and
* unlocking it otherwise. */
void _bufferevent_decref_and_unlock(struct bufferevent *bufev);
/** Sometimes it is more clear to say "decref" than "free" */
#define bufferevent_decref(b) bufferevent_free(b)
/** Internal: If callbacks are deferred and we have a read callback, schedule
* a readcb. Otherwise just run the readcb. */

View File

@ -512,12 +512,15 @@ _bufferevent_decref_and_unlock(struct bufferevent *bufev)
{
struct bufferevent_private *bufev_private =
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
struct bufferevent *underlying;
if (--bufev_private->refcnt) {
BEV_UNLOCK(bufev);
return;
}
underlying = bufferevent_get_underlying(bufev);
/* Clean up the shared info */
if (bufev->be_ops->destruct)
bufev->be_ops->destruct(bufev);
@ -536,6 +539,15 @@ _bufferevent_decref_and_unlock(struct bufferevent *bufev)
/* Free the actual allocated memory. */
mm_free(bufev - bufev->be_ops->mem_offset);
/* release the reference to underlying now that we no longer need
* the reference to it. This is mainly in case our lock is shared
* with underlying.
* XXX Should we/can we just refcount evbuffer/bufferevent locks?
* It would probably save us some headaches.
*/
if (underlying)
bufferevent_decref(underlying);
}
void

View File

@ -200,6 +200,7 @@ bufferevent_filter_new(struct bufferevent *underlying,
bufferevent_filtered_outbuf_cb, bufev_f);
_bufferevent_init_generic_timeout_cbs(downcast(bufev_f));
bufferevent_incref(underlying);
return downcast(bufev_f);
}

View File

@ -1101,8 +1101,10 @@ bufferevent_openssl_new_impl(struct event_base *base,
if (options & BEV_OPT_THREADSAFE)
bufferevent_enable_locking(&bev_ssl->bev.bev, NULL);
if (underlying)
if (underlying) {
_bufferevent_init_generic_timeout_cbs(&bev_ssl->bev.bev);
bufferevent_incref(underlying);
}
bev_ssl->state = state;
bev_ssl->last_write = -1;