mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-18 08:49:57 -04:00
prevent nested multicast references, reworked locking
This commit is contained in:
parent
9d7368ae2d
commit
26041a8ed8
42
buffer.c
42
buffer.c
@ -221,10 +221,11 @@ evbuffer_chain_free(struct evbuffer_chain *chain)
|
|||||||
EVBUFFER_CHAIN_EXTRA(
|
EVBUFFER_CHAIN_EXTRA(
|
||||||
struct evbuffer_multicast_parent,
|
struct evbuffer_multicast_parent,
|
||||||
chain);
|
chain);
|
||||||
|
EVUTIL_ASSERT(info->source != NULL);
|
||||||
EVUTIL_ASSERT(info->parent != NULL);
|
EVUTIL_ASSERT(info->parent != NULL);
|
||||||
EVBUFFER_LOCK(info);
|
EVBUFFER_LOCK(info->source);
|
||||||
evbuffer_chain_decref(info->parent);
|
evbuffer_chain_decref(info->parent);
|
||||||
EVBUFFER_UNLOCK(info);
|
_evbuffer_decref_and_unlock(info->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_free(chain);
|
mm_free(chain);
|
||||||
@ -325,11 +326,8 @@ static inline void
|
|||||||
evbuffer_chain_decref(struct evbuffer_chain *chain)
|
evbuffer_chain_decref(struct evbuffer_chain *chain)
|
||||||
{
|
{
|
||||||
EVUTIL_ASSERT(chain->refcnt > 0);
|
EVUTIL_ASSERT(chain->refcnt > 0);
|
||||||
if (--chain->refcnt > 0) {
|
--chain->refcnt;
|
||||||
return;
|
// chain will be freed when parent buffer is released
|
||||||
}
|
|
||||||
|
|
||||||
evbuffer_chain_free(chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct evbuffer *
|
struct evbuffer *
|
||||||
@ -837,28 +835,12 @@ APPEND_CHAIN_MULTICAST(struct evbuffer *dst, struct evbuffer *src)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
|
extra = EVBUFFER_CHAIN_EXTRA(struct evbuffer_multicast_parent, tmp);
|
||||||
if (chain->flags & EVBUFFER_MULTICAST) {
|
// reference source chain which now becomes immutable
|
||||||
// source chain is a reference itself
|
_evbuffer_incref(src);
|
||||||
struct evbuffer_multicast_parent *info =
|
extra->source = src;
|
||||||
EVBUFFER_CHAIN_EXTRA(
|
evbuffer_chain_incref(chain);
|
||||||
struct evbuffer_multicast_parent,
|
extra->parent = chain;
|
||||||
chain);
|
chain->flags |= EVBUFFER_IMMUTABLE;
|
||||||
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
|
||||||
extra->lock = info->lock;
|
|
||||||
#endif
|
|
||||||
EVBUFFER_LOCK(info);
|
|
||||||
evbuffer_chain_incref(info->parent);
|
|
||||||
EVBUFFER_UNLOCK(info);
|
|
||||||
extra->parent = info->parent;
|
|
||||||
} else {
|
|
||||||
// reference source chain which now becomes immutable
|
|
||||||
evbuffer_chain_incref(chain);
|
|
||||||
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
|
||||||
extra->lock = src->lock;
|
|
||||||
#endif
|
|
||||||
extra->parent = chain;
|
|
||||||
chain->flags |= EVBUFFER_IMMUTABLE;
|
|
||||||
}
|
|
||||||
tmp->buffer_len = chain->buffer_len;
|
tmp->buffer_len = chain->buffer_len;
|
||||||
tmp->misalign = chain->misalign;
|
tmp->misalign = chain->misalign;
|
||||||
tmp->off = chain->off;
|
tmp->off = chain->off;
|
||||||
@ -953,7 +935,7 @@ evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (; chain; chain = chain->next) {
|
for (; chain; chain = chain->next) {
|
||||||
if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE)) != 0) {
|
if ((chain->flags & (EVBUFFER_FILESEGMENT|EVBUFFER_SENDFILE|EVBUFFER_MULTICAST)) != 0) {
|
||||||
// chain type can not be referenced
|
// chain type can not be referenced
|
||||||
result = -1;
|
result = -1;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -248,9 +248,8 @@ struct evbuffer_file_segment {
|
|||||||
/** Information about the multicast parent of a chain. Lives at the
|
/** Information about the multicast parent of a chain. Lives at the
|
||||||
* end of an evbuffer_chain with the EVBUFFER_MULTICAST flag set. */
|
* end of an evbuffer_chain with the EVBUFFER_MULTICAST flag set. */
|
||||||
struct evbuffer_multicast_parent {
|
struct evbuffer_multicast_parent {
|
||||||
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
|
/** source buffer the multicast parent belongs to */
|
||||||
void *lock; /**< lock prevent concurrent access to the parent */
|
struct evbuffer *source;
|
||||||
#endif
|
|
||||||
/** multicast parent for this chain */
|
/** multicast parent for this chain */
|
||||||
struct evbuffer_chain *parent;
|
struct evbuffer_chain *parent;
|
||||||
};
|
};
|
||||||
|
@ -393,11 +393,15 @@ int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf);
|
|||||||
This is a non-destructive add. The data from one buffer is copied
|
This is a non-destructive add. The data from one buffer is copied
|
||||||
into the other buffer. However, no unnecessary memory copies occur.
|
into the other buffer. However, no unnecessary memory copies occur.
|
||||||
|
|
||||||
|
Note that buffers already containing buffer references can't be added
|
||||||
|
to other buffers.
|
||||||
|
|
||||||
@param outbuf the output buffer
|
@param outbuf the output buffer
|
||||||
@param inbuf the input buffer
|
@param inbuf the input buffer
|
||||||
@return 0 if successful, or -1 if an error occurred
|
@return 0 if successful, or -1 if an error occurred
|
||||||
*/
|
*/
|
||||||
int evbuffer_add_buffer_reference(struct evbuffer *outbuf, struct evbuffer *inbuf);
|
int evbuffer_add_buffer_reference(struct evbuffer *outbuf,
|
||||||
|
struct evbuffer *inbuf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A cleanup function for a piece of memory added to an evbuffer by
|
A cleanup function for a piece of memory added to an evbuffer by
|
||||||
|
@ -1544,7 +1544,9 @@ test_evbuffer_multicast(void *ptr)
|
|||||||
tt_assert(buf2);
|
tt_assert(buf2);
|
||||||
|
|
||||||
tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
|
tt_int_op(evbuffer_add_buffer_reference(buf2, buf1), ==, 0);
|
||||||
|
// nested references are not allowed
|
||||||
tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1);
|
tt_int_op(evbuffer_add_buffer_reference(buf2, buf2), ==, -1);
|
||||||
|
tt_int_op(evbuffer_add_buffer_reference(buf1, buf2), ==, -1);
|
||||||
|
|
||||||
// both buffers contain the same amount of data
|
// both buffers contain the same amount of data
|
||||||
tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1));
|
tt_int_op(evbuffer_get_length(buf1), ==, evbuffer_get_length(buf1));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user