]> granicus.if.org Git - libevent/commitdiff
buffer: fix evbuffer_remove_buffer() with empty chain in front
authorAzat Khuzhin <azat@libevent.org>
Sat, 2 Mar 2019 19:50:00 +0000 (22:50 +0300)
committerAzat Khuzhin <azat@libevent.org>
Sun, 3 Mar 2019 15:00:37 +0000 (18:00 +0300)
In case we have empty chain (chain that do not have any data, i.e. ->off
== 0) at the beginning of the buffer, and no more full chains to move to
the dst, we will skip moving of this empty chain, and hence
last_with_datap will not be adjusted, and things will be broken after.

Fix this by not relying on ->off, just count if we have something to
move that's it.

Test case from:
  https://github.com/envoyproxy/envoy/pull/6062

Fixes: #774
buffer.c
test/regress_buffer.c

index f6ff84315c447cb5a7633806c36dc27c2db74122..7a8c8b696cbaf7bc4bc316a99622f6b738034121 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -1299,7 +1299,7 @@ evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
                chain = chain->next;
        }
 
-       if (nread) {
+       if (chain != src->first) {
                /* we can remove the chain */
                struct evbuffer_chain **chp;
                chp = evbuffer_free_trailing_empty_chains(dst);
index a7f27416f32d33b818ac1f5c8d695a2563cce853..67072ec8e03363bececec01ec9b617faa56e3131 100644 (file)
@@ -423,6 +423,33 @@ test_evbuffer_remove_buffer_with_empty3(void *ptr)
        evbuffer_free(buf);
 }
 
+static void
+test_evbuffer_remove_buffer_with_empty_front(void *ptr)
+{
+       struct evbuffer *buf1 = NULL, *buf2 = NULL;
+
+       buf1 = evbuffer_new();
+       tt_assert(buf1);
+
+       buf2 = evbuffer_new();
+       tt_assert(buf2);
+
+       tt_int_op(evbuffer_add_reference(buf1, "foo", 3, NULL, NULL), ==, 0);
+       tt_int_op(evbuffer_prepend(buf1, "", 0), ==, 0);
+       tt_int_op(evbuffer_remove_buffer(buf1, buf2, 1), ==, 1);
+       tt_int_op(evbuffer_add(buf1, "bar", 3), ==, 0);
+       tt_mem_op(evbuffer_pullup(buf1, -1), ==, "oobar", 5);
+
+       evbuffer_validate(buf1);
+       evbuffer_validate(buf2);
+
+ end:
+       if (buf1)
+               evbuffer_free(buf1);
+       if (buf2)
+               evbuffer_free(buf2);
+}
+
 static void
 test_evbuffer_add_buffer_with_empty(void *ptr)
 {
@@ -2522,6 +2549,7 @@ struct testcase_t evbuffer_testcases[] = {
        { "remove_buffer_with_empty", test_evbuffer_remove_buffer_with_empty, 0, NULL, NULL },
        { "remove_buffer_with_empty2", test_evbuffer_remove_buffer_with_empty2, 0, NULL, NULL },
        { "remove_buffer_with_empty3", test_evbuffer_remove_buffer_with_empty3, 0, NULL, NULL },
+       { "remove_buffer_with_empty_front", test_evbuffer_remove_buffer_with_empty_front, 0, NULL, NULL },
        { "add_buffer_with_empty", test_evbuffer_add_buffer_with_empty, 0, NULL, NULL },
        { "add_buffer_with_empty2", test_evbuffer_add_buffer_with_empty2, 0, NULL, NULL },
        { "reserve2", test_evbuffer_reserve2, 0, NULL, NULL },