SIGN IN SIGN UP

BUG/MINOR: h2: don't use a block pointer to roll back a partial HTX conversion

h2_make_htx_request(), h2_make_htx_response() and h2_make_htx_trailers() save a
pointer on the tail HTX block on entry and use it on their error path to remove
everything they added:

	struct htx_blk *tailblk = htx_get_tail_blk(htx);
	...
 fail:
	htx_truncate_blk(htx, tailblk);

An HTX block pointer is not a stable reference: it is computed from a block
*position* ("htx->blocks + htx->size - (pos + 1) * sizeof(struct htx_blk)"), so
it only designates the same block as long as the block table is not compacted.
htx_add_header()/htx_add_trailer() end up in htx_reserve_nxblk(), which calls
htx_defrag_blks() when the table has grown down to the payload while
htx->head > 0. After such a compaction all the blocks move down by the old
value of htx->head, but <tailblk> still points at the same address, hence at a
block located <head> positions further in the message. htx_truncate_blk() would
then truncate at the wrong place, either leaving partially converted headers or
trailers in the message, or dropping valid blocks that were there before.

This only concerns the trailers, and possibly the response on the backend side,
because the destination message may already hold payload with a partially
consumed head there, while a request is always converted into an empty buffer
which cannot defragment.

Let's save the amount of data present on entry and use htx_truncate() instead,
which relies on a byte offset and is therefore immune to any block move. This
is the same pattern as the one already used by htx_append_msg().

This has been there since the H2 to HTX conversion was introduced, so it should
be backported to all supported versions.
W
Willy Tarreau committed
865351d4ed7cb883349fe8b61ee1aacade8f467e
Parent: 84c3c96
Committed by Christopher Faulet <cfaulet@haproxy.com> on 7/27/2026, 1:29:50 PM