When receiving a large POST which spans multiple buffers, if the current
rxbuf is full we try to allocate a new buffer. But if the allocation
fails due to an enforced tune.buffers.limit for example, we leave and
try to switch back the buffer to htx via htx_to_buf(htx, scbuf) while
scbuf has become NULL, causing a crash.
Let's just properly reset the htx pointer between each buffer switch
so as not to attempt this operation. This is difficult to reproduce,
but could be triggered once with tune.buffers.limit set to 6, with
1 to 3 pending HTTP/1 requests and a 60kB H2 POST.
This was introduced in 3.1 by commit
4eb3ff1d3 ("MAJOR: mux-h2: make
streams use the connection's buffers"), so the fix must be backported
to 3.2.
block = htx_free_data_space(htx);
if (!block) {
if (h2s_get_rxbuf(h2s))
- goto next_buffer;
+ goto switch_buffer;
h2c->flags |= H2_CF_DEM_SFULL;
TRACE_STATE("h2s rxbuf is full", H2_EV_RX_FRAME|H2_EV_RX_DATA|H2_EV_H2S_BLK, h2c->conn, h2s);
if (sent < flen) {
if (h2s_get_rxbuf(h2s))
- goto next_buffer;
+ goto switch_buffer;
h2c->flags |= H2_CF_DEM_SFULL;
TRACE_STATE("h2s rxbuf is full", H2_EV_RX_FRAME|H2_EV_RX_DATA|H2_EV_H2S_BLK, h2c->conn, h2s);
goto try_again;
+ switch_buffer:
+ /* the current rxbuf is full and a new slot was assigned to the
+ * stream: release the current HTX message before switching to the
+ * next buffer, whose allocation may fail.
+ */
+ htx_to_buf(htx, scbuf);
+ htx = NULL;
+ goto next_buffer;
+
end_transfer:
/* here we're done with the frame, all the payload (except padding) was
* transferred. So let's consume the padding now.