diff --git a/llvm/include/llvm/Support/LEB128.h b/llvm/include/llvm/Support/LEB128.h index 0b8cb6781aec4..bf45131582005 100644 --- a/llvm/include/llvm/Support/LEB128.h +++ b/llvm/include/llvm/Support/LEB128.h @@ -149,7 +149,12 @@ inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr, Value = 0; break; } - Value += Slice << Shift; + // Once Shift reaches 64 the remaining bytes have already been validated + // above to be pure zero-extension, so they contribute nothing. Performing + // "Slice << Shift" with Shift >= 64 would be undefined behavior, so skip + // it. + if (LLVM_LIKELY(Shift < 64)) + Value += Slice << Shift; Shift += 7; } while (*p++ >= 128); if (n) @@ -187,7 +192,12 @@ inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr, *n = (unsigned)(p - orig_p); return 0; } - Value |= Slice << Shift; + // Once Shift reaches 64 the remaining bytes have already been validated + // above to be pure sign-extension, so they contribute nothing. Performing + // "Slice << Shift" with Shift >= 64 would be undefined behavior, so skip + // it. + if (LLVM_LIKELY(Shift < 64)) + Value |= Slice << Shift; Shift += 7; ++p; } while (Byte >= 128); diff --git a/llvm/unittests/Support/LEB128Test.cpp b/llvm/unittests/Support/LEB128Test.cpp index 0c54a2846903b..dc80f7c4e71ea 100644 --- a/llvm/unittests/Support/LEB128Test.cpp +++ b/llvm/unittests/Support/LEB128Test.cpp @@ -139,6 +139,11 @@ TEST(LEB128Test, DecodeULEB128) { EXPECT_DECODE_ULEB128_EQ(0x80000000'00000000ul, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01"); + // Decode overlong ULEB128 whose trailing zero-extension bytes push the shift + // amount to 64 or beyond. + EXPECT_DECODE_ULEB128_EQ(0u, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x00"); + EXPECT_DECODE_ULEB128_EQ(1u, "\x81\x80\x80\x80\x80\x80\x80\x80\x80\x80\x00"); + #undef EXPECT_DECODE_ULEB128_EQ } @@ -216,6 +221,12 @@ TEST(LEB128Test, DecodeSLEB128) { EXPECT_DECODE_SLEB128_EQ(INT64_MAX, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00"); + // Decode overlong SLEB128 whose trailing sign-extension bytes push the shift + // amount to 64 or beyond. + EXPECT_DECODE_SLEB128_EQ(0L, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x00"); + EXPECT_DECODE_SLEB128_EQ(-1L, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + EXPECT_DECODE_SLEB128_EQ(-2L, "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"); + #undef EXPECT_DECODE_SLEB128_EQ }