mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-11 13:24:43 -04:00
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:
parent
a6adeca72c
commit
a773df54ce
@ -217,6 +217,8 @@ void _bufferevent_incref_and_lock(struct bufferevent *bufev);
|
|||||||
/** Internal: Drop the reference count on bufev, freeing as necessary, and
|
/** Internal: Drop the reference count on bufev, freeing as necessary, and
|
||||||
* unlocking it otherwise. */
|
* unlocking it otherwise. */
|
||||||
void _bufferevent_decref_and_unlock(struct bufferevent *bufev);
|
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
|
/** Internal: If callbacks are deferred and we have a read callback, schedule
|
||||||
* a readcb. Otherwise just run the readcb. */
|
* a readcb. Otherwise just run the readcb. */
|
||||||
|
@ -512,12 +512,15 @@ _bufferevent_decref_and_unlock(struct bufferevent *bufev)
|
|||||||
{
|
{
|
||||||
struct bufferevent_private *bufev_private =
|
struct bufferevent_private *bufev_private =
|
||||||
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
|
EVUTIL_UPCAST(bufev, struct bufferevent_private, bev);
|
||||||
|
struct bufferevent *underlying;
|
||||||
|
|
||||||
if (--bufev_private->refcnt) {
|
if (--bufev_private->refcnt) {
|
||||||
BEV_UNLOCK(bufev);
|
BEV_UNLOCK(bufev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
underlying = bufferevent_get_underlying(bufev);
|
||||||
|
|
||||||
/* Clean up the shared info */
|
/* Clean up the shared info */
|
||||||
if (bufev->be_ops->destruct)
|
if (bufev->be_ops->destruct)
|
||||||
bufev->be_ops->destruct(bufev);
|
bufev->be_ops->destruct(bufev);
|
||||||
@ -536,6 +539,15 @@ _bufferevent_decref_and_unlock(struct bufferevent *bufev)
|
|||||||
|
|
||||||
/* Free the actual allocated memory. */
|
/* Free the actual allocated memory. */
|
||||||
mm_free(bufev - bufev->be_ops->mem_offset);
|
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
|
void
|
||||||
|
@ -200,6 +200,7 @@ bufferevent_filter_new(struct bufferevent *underlying,
|
|||||||
bufferevent_filtered_outbuf_cb, bufev_f);
|
bufferevent_filtered_outbuf_cb, bufev_f);
|
||||||
|
|
||||||
_bufferevent_init_generic_timeout_cbs(downcast(bufev_f));
|
_bufferevent_init_generic_timeout_cbs(downcast(bufev_f));
|
||||||
|
bufferevent_incref(underlying);
|
||||||
|
|
||||||
return downcast(bufev_f);
|
return downcast(bufev_f);
|
||||||
}
|
}
|
||||||
|
@ -1101,8 +1101,10 @@ bufferevent_openssl_new_impl(struct event_base *base,
|
|||||||
if (options & BEV_OPT_THREADSAFE)
|
if (options & BEV_OPT_THREADSAFE)
|
||||||
bufferevent_enable_locking(&bev_ssl->bev.bev, NULL);
|
bufferevent_enable_locking(&bev_ssl->bev.bev, NULL);
|
||||||
|
|
||||||
if (underlying)
|
if (underlying) {
|
||||||
_bufferevent_init_generic_timeout_cbs(&bev_ssl->bev.bev);
|
_bufferevent_init_generic_timeout_cbs(&bev_ssl->bev.bev);
|
||||||
|
bufferevent_incref(underlying);
|
||||||
|
}
|
||||||
|
|
||||||
bev_ssl->state = state;
|
bev_ssl->state = state;
|
||||||
bev_ssl->last_write = -1;
|
bev_ssl->last_write = -1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user