diff options
author | Azat Khuzhin <azat@libevent.org> | 2019-03-03 16:29:52 +0300 |
---|---|---|
committer | Azat Khuzhin <azat@libevent.org> | 2019-03-03 18:55:25 +0300 |
commit | 5b19c9f62beb506ae0aaa507c2358c52a0a91e2a (patch) | |
tree | 3ac478aeaee9d519359dca2098a124186910ea06 /buffer.c | |
parent | fdfabbec00b36bc6d5e69b5d8719e70d6f4e5b7b (diff) | |
download | libevent-5b19c9f62beb506ae0aaa507c2358c52a0a91e2a.tar.gz |
buffer: do not rely on ->off in advance_last_with_data()
advance_last_with_data() adjusts evbuffer.last_with_datap, and if we
will have empty chain in the middle advance_last_with_data() will stop,
while it should not, since while empty chains is not regular thing they
can pops up in various places like, and while I did not look through all
of them the most tricky I would say is:
evbuffer_reverse_space()/evbuffer_commit_space()
evbuffer_add_reference()
Test case from:
https://github.com/envoyproxy/envoy/pull/6062
Fixes: #778
v2: keep last_with_datap really last with data, i.e. update only if
chain has data in it
Diffstat (limited to 'buffer.c')
-rw-r--r-- | buffer.c | 10 |
1 files changed, 7 insertions, 3 deletions
@@ -704,13 +704,17 @@ static int advance_last_with_data(struct evbuffer *buf) { int n = 0; + struct evbuffer_chain **chainp = buf->last_with_datap; + ASSERT_EVBUFFER_LOCKED(buf); - if (!*buf->last_with_datap) + if (!*chainp) return 0; - while ((*buf->last_with_datap)->next && (*buf->last_with_datap)->next->off) { - buf->last_with_datap = &(*buf->last_with_datap)->next; + while ((*chainp)->next) { + chainp = &(*chainp)->next; + if ((*chainp)->off) + buf->last_with_datap = chainp; ++n; } return n; |