]> git.kaiwu.me - nginx.git/commitdiff
HTTP/3: avoid unaligned stores in Huffman encoding
author최대우 (Daewoo Choi) <daewoo.choi@hanwha.com>
Thu, 1 Oct 2026 03:59:44 +0000 (12:59 +0900)
committerAndrew Clayton <a.clayton@nginx.com>
Tue, 20 Oct 2026 12:54:33 +0000 (13:54 +0100)
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

index c03b153da8b8f1e94d8dc1a3ace96a1f724c522a..7fff5eb0e94983594e599343063909eb36ff0fad 100644 (file)
@@ -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);