mirror of
https://github.com/nginx/nginx.git
synced 2026-05-13 09:36:42 +00:00
HTTP/2: make ngx_http_huff_encode() output path alignment-safe
In ngx_http_huff_encode(), the original output path used ngx_http_huff_encode_buf(dst, buf), which may expand to wide stores through (uint64_t *) or (uint32_t *) casts on the destination byte buffer. On an aarch64 cross-compiled environment, this was observed to corrupt some HTTP/2 response headers such as Date. This change preserves the existing HPACK Huffman encoding semantics and only changes how encoded bytes are written to dst: - keep the existing code/len table lookup logic - keep encoded length calculation unchanged - keep RFC 7541 padding behavior unchanged - replace architecture-sensitive wide-store output with byte-wise writes The new implementation accumulates bits in buf and emits bytes sequentially through u_char *dst, avoiding alignment-sensitive stores on the destination buffer and improving portability across cross-toolchains and architectures.
This commit is contained in:
parent
3b5da468b3
commit
fde95f8243
1 changed files with 36 additions and 79 deletions
|
|
@ -156,99 +156,56 @@ 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))
|
||||
#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))
|
||||
#endif
|
||||
|
||||
#else /* NGX_PTR_SIZE == 4 */
|
||||
|
||||
#define ngx_http_huff_encode_buf(dst, buf) \
|
||||
(*(uint32_t *) (dst) = htonl(buf))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
size_t
|
||||
ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower)
|
||||
{
|
||||
u_char *end;
|
||||
size_t hlen;
|
||||
ngx_uint_t buf, pending, code;
|
||||
ngx_http_huff_encode_code_t *table, *next;
|
||||
u_char ch;
|
||||
size_t hlt, pending;
|
||||
ngx_uint_t i;
|
||||
uint64_t buf;
|
||||
ngx_http_huff_encode_code_t *table, *code;
|
||||
|
||||
table = lower ? ngx_http_huff_encode_table_lc
|
||||
: ngx_http_huff_encode_table;
|
||||
hlen = 0;
|
||||
|
||||
hlt = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
ch = src[i];
|
||||
hlt += table[ch].len;
|
||||
}
|
||||
|
||||
hlt = (hlt + 7) / 8;
|
||||
|
||||
if (dst == NULL) {
|
||||
return hlt;
|
||||
}
|
||||
|
||||
buf = 0;
|
||||
pending = 0;
|
||||
|
||||
end = src + len;
|
||||
for (i = 0; i < len; i++) {
|
||||
ch = src[i];
|
||||
code = &table[ch];
|
||||
|
||||
while (src != end) {
|
||||
next = &table[*src++];
|
||||
buf <<= code->len;
|
||||
buf |= code->code;
|
||||
pending += code->len;
|
||||
|
||||
code = next->code;
|
||||
pending += next->len;
|
||||
|
||||
/* accumulate bits */
|
||||
if (pending < sizeof(buf) * 8) {
|
||||
buf |= code << (sizeof(buf) * 8 - pending);
|
||||
continue;
|
||||
/*
|
||||
* Emit encoded output one byte at a time to avoid
|
||||
* alignment-sensitive wide stores on the destination buffer.
|
||||
*/
|
||||
while (pending >= 8) {
|
||||
pending -= 8;
|
||||
*dst++ = (u_char) (buf >> pending);
|
||||
}
|
||||
|
||||
if (hlen + sizeof(buf) >= len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pending -= sizeof(buf) * 8;
|
||||
|
||||
buf |= code >> pending;
|
||||
|
||||
ngx_http_huff_encode_buf(&dst[hlen], buf);
|
||||
|
||||
hlen += sizeof(buf);
|
||||
|
||||
buf = pending ? code << (sizeof(buf) * 8 - pending) : 0;
|
||||
}
|
||||
|
||||
if (pending == 0) {
|
||||
return hlen;
|
||||
if (pending > 0) {
|
||||
buf <<= (8 - pending);
|
||||
buf |= (uint64_t) (0xff >> pending);
|
||||
*dst++ = (u_char) buf;
|
||||
}
|
||||
|
||||
buf |= (ngx_uint_t) -1 >> pending;
|
||||
|
||||
pending = ngx_align(pending, 8);
|
||||
|
||||
if (hlen + pending / 8 >= len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf >>= sizeof(buf) * 8 - pending;
|
||||
|
||||
do {
|
||||
pending -= 8;
|
||||
dst[hlen++] = (u_char) (buf >> pending);
|
||||
} while (pending);
|
||||
|
||||
return hlen;
|
||||
return hlt;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue