mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Merge branch 'evbuffer-fixes-806-v2'
* evbuffer-fixes-806-v2: evbuffer: fix last_with_datap after prepend with empty chain test: regression for evbuffer_expand_fast_() with invalid last_with_datap test: cover adjusting of last_with_datap in evbuffer_prepend() Fixes: #806
This commit is contained in:
commit
3b1864b625
2
buffer.c
2
buffer.c
@ -1905,7 +1905,7 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
|
||||
if ((tmp = evbuffer_chain_new(datlen)) == NULL)
|
||||
goto done;
|
||||
buf->first = tmp;
|
||||
if (buf->last_with_datap == &buf->first)
|
||||
if (buf->last_with_datap == &buf->first && chain->off)
|
||||
buf->last_with_datap = &tmp->next;
|
||||
|
||||
tmp->next = chain;
|
||||
|
@ -63,6 +63,8 @@
|
||||
|
||||
#include "regress.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
/* Validates that an evbuffer is good. Returns false if it isn't, true if it
|
||||
* is*/
|
||||
static int
|
||||
@ -757,6 +759,41 @@ test_evbuffer_reserve_with_empty(void *ptr)
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
|
||||
/* regression for evbuffer_expand_fast_() with invalid last_with_datap that has
|
||||
* been left after evbuffer_prepend() with empty chain in it */
|
||||
static void
|
||||
test_evbuffer_reserve_invalid_last_with_datap(void *ptr)
|
||||
{
|
||||
struct evbuffer *buf = NULL;
|
||||
struct evbuffer_iovec vec[2];
|
||||
const int nvec = ARRAY_SIZE(vec);
|
||||
int i, avec;
|
||||
|
||||
buf = evbuffer_new();
|
||||
tt_assert(buf);
|
||||
|
||||
/* prepend with an empty chain */
|
||||
evbuffer_add_reference(buf, "", 0, NULL, NULL);
|
||||
evbuffer_prepend(buf, "foo", 3);
|
||||
/* after invalid last_with_datap will create new chain */
|
||||
evbuffer_add(buf, "", 0);
|
||||
/* we need to create at least 2 "used" (in evbuffer_expand_fast_()) chains */
|
||||
tt_int_op(avec = evbuffer_reserve_space(buf, 1<<12, vec, nvec), >=, 1);
|
||||
for (i = 0; i < avec; ++i)
|
||||
vec[i].iov_len = 0;
|
||||
tt_int_op(evbuffer_commit_space(buf, vec, avec), ==, 0);
|
||||
|
||||
/* and an actual problem, that triggers an assert(chain == buf->first) in
|
||||
* evbuffer_expand_fast_() */
|
||||
tt_int_op(evbuffer_reserve_space(buf, 1<<13, vec, nvec), >=, 1);
|
||||
|
||||
evbuffer_validate(buf);
|
||||
|
||||
end:
|
||||
if (buf)
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
test_evbuffer_expand(void *ptr)
|
||||
{
|
||||
@ -2240,6 +2277,58 @@ end:
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
test_evbuffer_empty_reference_prepend(void *ptr)
|
||||
{
|
||||
struct evbuffer *buf = NULL;
|
||||
|
||||
buf = evbuffer_new();
|
||||
tt_assert(buf);
|
||||
|
||||
/** empty chain could leave invalid last_with_datap */
|
||||
evbuffer_add_reference(buf, "", 0, NULL, NULL);
|
||||
evbuffer_validate(buf);
|
||||
evbuffer_prepend(buf, "foo", 3);
|
||||
|
||||
evbuffer_validate(buf);
|
||||
tt_assert(!strncmp((char *)evbuffer_pullup(buf, -1), "foo", 3));
|
||||
evbuffer_validate(buf);
|
||||
|
||||
end:
|
||||
if (buf)
|
||||
evbuffer_free(buf);
|
||||
}
|
||||
static void
|
||||
test_evbuffer_empty_reference_prepend_buffer(void *ptr)
|
||||
{
|
||||
struct evbuffer *buf1 = NULL, *buf2 = NULL;
|
||||
|
||||
buf1 = evbuffer_new();
|
||||
tt_assert(buf1);
|
||||
buf2 = evbuffer_new();
|
||||
tt_assert(buf2);
|
||||
|
||||
/** empty chain could leave invalid last_with_datap */
|
||||
evbuffer_add_reference(buf1, "", 0, NULL, NULL);
|
||||
evbuffer_validate(buf1);
|
||||
evbuffer_add(buf2, "foo", 3);
|
||||
evbuffer_validate(buf2);
|
||||
evbuffer_prepend_buffer(buf2, buf1);
|
||||
evbuffer_validate(buf2);
|
||||
|
||||
tt_assert(!strncmp((char *)evbuffer_pullup(buf2, -1), "foo", 3));
|
||||
evbuffer_validate(buf2);
|
||||
|
||||
tt_assert(!strncmp((char *)evbuffer_pullup(buf1, -1), "", 0));
|
||||
evbuffer_validate(buf2);
|
||||
|
||||
end:
|
||||
if (buf1)
|
||||
evbuffer_free(buf1);
|
||||
if (buf2)
|
||||
evbuffer_free(buf2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_evbuffer_peek_first_gt(void *info)
|
||||
{
|
||||
@ -2637,6 +2726,7 @@ struct testcase_t evbuffer_testcases[] = {
|
||||
{ "reserve_many2", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"add" },
|
||||
{ "reserve_many3", test_evbuffer_reserve_many, 0, &nil_setup, (void*)"fill" },
|
||||
{ "reserve_with_empty", test_evbuffer_reserve_with_empty, 0, NULL, NULL },
|
||||
{ "reserve_invalid_last_with_datap", test_evbuffer_reserve_invalid_last_with_datap, TT_FORK, NULL, NULL },
|
||||
{ "expand", test_evbuffer_expand, 0, NULL, NULL },
|
||||
{ "expand_overflow", test_evbuffer_expand_overflow, 0, NULL, NULL },
|
||||
{ "add1", test_evbuffer_add1, 0, NULL, NULL },
|
||||
@ -2654,6 +2744,8 @@ struct testcase_t evbuffer_testcases[] = {
|
||||
{ "multicast", test_evbuffer_multicast, 0, NULL, NULL },
|
||||
{ "multicast_drain", test_evbuffer_multicast_drain, 0, NULL, NULL },
|
||||
{ "prepend", test_evbuffer_prepend, TT_FORK, NULL, NULL },
|
||||
{ "empty_reference_prepend", test_evbuffer_empty_reference_prepend, TT_FORK, NULL, NULL },
|
||||
{ "empty_reference_prepend_buffer", test_evbuffer_empty_reference_prepend_buffer, TT_FORK, NULL, NULL },
|
||||
{ "peek", test_evbuffer_peek, 0, NULL, NULL },
|
||||
{ "peek_first_gt", test_evbuffer_peek_first_gt, 0, NULL, NULL },
|
||||
{ "freeze_start", test_evbuffer_freeze, 0, &nil_setup, (void*)"start" },
|
||||
|
Loading…
x
Reference in New Issue
Block a user