bswap: convert to unsigned before shifting in get_be32
authorRené Scharfe <l.s.r@web.de>
Sat, 15 Jul 2017 19:11:14 +0000 (21:11 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 17 Jul 2017 21:54:13 +0000 (14:54 -0700)
The pointer p is dereferenced and we get an unsigned char. Before
shifting it's automatically promoted to int. Left-shifting a signed
32-bit value bigger than 127 by 24 places is undefined. Explicitly
convert to a 32-bit unsigned type to avoid undefined behaviour if
the highest bit is set.

Found with Clang's UBSan.

Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
compat/bswap.h
index d47c0035449b412ee074c9a94c0f5281211f5f7e..4582c1107ae58a9e8c1cc53fc34bcf46fc40bec2 100644 (file)
@@ -166,10 +166,10 @@ static inline uint64_t git_bswap64(uint64_t x)
        (*((unsigned char *)(p) + 0) << 8) | \
        (*((unsigned char *)(p) + 1) << 0) )
 #define get_be32(p)    ( \
-       (*((unsigned char *)(p) + 0) << 24) | \
-       (*((unsigned char *)(p) + 1) << 16) | \
-       (*((unsigned char *)(p) + 2) <<  8) | \
-       (*((unsigned char *)(p) + 3) <<  0) )
+       ((uint32_t)*((unsigned char *)(p) + 0) << 24) | \
+       ((uint32_t)*((unsigned char *)(p) + 1) << 16) | \
+       ((uint32_t)*((unsigned char *)(p) + 2) <<  8) | \
+       ((uint32_t)*((unsigned char *)(p) + 3) <<  0) )
 #define put_be32(p, v) do { \
        unsigned int __v = (v); \
        *((unsigned char *)(p) + 0) = __v >> 24; \