From b38c9d8068ab55504aa4311f729803b503579520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EB=8C=80=EC=9A=B0=20=28Daewoo=20Choi=29?= Date: Thu, 1 Oct 2026 12:59:44 +0900 Subject: [PATCH] HTTP/3: avoid unaligned stores in Huffman encoding The encoder wrote accumulated bits by casting the destination to uint64_t *, or uint32_t * on 32-bit platforms, and assigning through it, which requires the destination to be suitably aligned. In HTTP/2 the destination is a temporary buffer from ngx_palloc() and is always aligned. In HTTP/3 it points past a variable number of prefix integer bytes, so its alignment is arbitrary and the store is undefined behaviour. Byte order conversion is now separated from the store, which is done with ngx_memcpy(). --- src/http/ngx_http_huff_encode.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/src/http/ngx_http_huff_encode.c b/src/http/ngx_http_huff_encode.c index c03b153da..7fff5eb0e 100644 --- a/src/http/ngx_http_huff_encode.c +++ b/src/http/ngx_http_huff_encode.c @@ -158,32 +158,19 @@ static ngx_http_huff_encode_code_t ngx_http_huff_encode_table_lc[256] = #if (NGX_PTR_SIZE == 8) -#if (NGX_HAVE_LITTLE_ENDIAN) - -#if (NGX_HAVE_GCC_BSWAP64) -#define ngx_http_huff_encode_buf(dst, buf) \ - (*(uint64_t *) (dst) = __builtin_bswap64(buf)) +#if !(NGX_HAVE_LITTLE_ENDIAN) +#define ngx_http_huff_encode_hton(buf) (buf) +#elif (NGX_HAVE_GCC_BSWAP64) +#define ngx_http_huff_encode_hton(buf) __builtin_bswap64(buf) #else -#define ngx_http_huff_encode_buf(dst, buf) \ - ((dst)[0] = (u_char) ((buf) >> 56), \ - (dst)[1] = (u_char) ((buf) >> 48), \ - (dst)[2] = (u_char) ((buf) >> 40), \ - (dst)[3] = (u_char) ((buf) >> 32), \ - (dst)[4] = (u_char) ((buf) >> 24), \ - (dst)[5] = (u_char) ((buf) >> 16), \ - (dst)[6] = (u_char) ((buf) >> 8), \ - (dst)[7] = (u_char) (buf)) -#endif - -#else /* !NGX_HAVE_LITTLE_ENDIAN */ -#define ngx_http_huff_encode_buf(dst, buf) \ - (*(uint64_t *) (dst) = (buf)) +#define ngx_http_huff_encode_hton(buf) \ + ((uint64_t) htonl((uint32_t) (buf)) << 32 \ + | htonl((uint32_t) ((buf) >> 32))) #endif #else /* NGX_PTR_SIZE == 4 */ -#define ngx_http_huff_encode_buf(dst, buf) \ - (*(uint32_t *) (dst) = htonl(buf)) +#define ngx_http_huff_encode_hton(buf) htonl(buf) #endif @@ -224,7 +211,8 @@ ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) buf |= code >> pending; - ngx_http_huff_encode_buf(&dst[hlen], buf); + buf = ngx_http_huff_encode_hton(buf); + ngx_memcpy(&dst[hlen], &buf, sizeof(buf)); hlen += sizeof(buf);