From: Aurelien DARRAGON Date: Tue, 11 Aug 2026 16:11:44 +0000 (+0200) Subject: IMPORT: slz: avoid undefined shifts when building the word byte by byte X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=52255282e0f26001f6e4befe39973e2f0f680e44;p=thirdparty%2Fhaproxy.git IMPORT: slz: avoid undefined shifts when building the word byte by byte On the architectures that do not define UNALIGNED_FASTER, the 32-bit word compared against the reference table is assembled one byte at a time: word = ((unsigned char)in[pos] << 8) + ((unsigned char)in[pos + 1] << 16) + ((unsigned char)in[pos + 2] << 24); Unexpectedly, an unsigned char is promoted to a *signed* int when shifting, so shifting a value >= 128 by 24 places can overflow it, which is undefined behaviour depending on build options. It happens to produce the expected result with the usual compilers, but ubsan on an i386 build reports it for about half of input bytes: src/slz.c:482:107: runtime error: left shift of 220 by 24 places cannot be represented in type 'int' Let's just properly cast the uchars to u32 before shifting (this does not change the produced code at all). This is libslz upstream commit fbbb46aa54a4d330c6037f72693e0f79c7853354 --- diff --git a/src/slz.c b/src/slz.c index d4fee4362..9d4659329 100644 --- a/src/slz.c +++ b/src/slz.c @@ -473,11 +473,11 @@ long slz_rfc1951_encode(struct slz_stream *strm, unsigned char *out, const unsig #ifndef UNALIGNED_FASTER if (rem >= 4) // is only used inside the loop below, hence the test for >= 4 - word = ((unsigned char)in[pos] << 8) + ((unsigned char)in[pos + 1] << 16) + ((unsigned char)in[pos + 2] << 24); + word = ((uint32_t)(unsigned char)in[pos] << 8) + ((uint32_t)(unsigned char)in[pos + 1] << 16) + ((uint32_t)(unsigned char)in[pos + 2] << 24); #endif while (rem >= 4) { #ifndef UNALIGNED_FASTER - word = ((unsigned char)in[pos + 3] << 24) + (word >> 8); + word = ((uint32_t)(unsigned char)in[pos + 3] << 24) + (word >> 8); #else word = *(uint32_t *)&in[pos]; #endif @@ -690,7 +690,7 @@ long slz_rfc1951_encode(struct slz_stream *strm, unsigned char *out, const unsig #ifdef UNALIGNED_LE_OK word = *(uint32_t *)&in[pos - 1]; #else - word = ((unsigned char)in[pos] << 8) + ((unsigned char)in[pos + 1] << 16) + ((unsigned char)in[pos + 2] << 24); + word = ((uint32_t)(unsigned char)in[pos] << 8) + ((uint32_t)(unsigned char)in[pos + 1] << 16) + ((uint32_t)(unsigned char)in[pos + 2] << 24); #endif } #endif