Skip to content

Commit

Permalink
[Support] Add end/error to decode[US]LEB128AndInc
Browse files Browse the repository at this point in the history
Follow-up to #85739 to encourage error checking. We make `end` mandatory
and add decodeULEB128AndIncUnsafe to be used without `end`.

Pull Request: #90006
  • Loading branch information
MaskRay authored May 8, 2024
1 parent 6d89014 commit efad149
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 13 deletions.
14 changes: 10 additions & 4 deletions llvm/include/llvm/Support/LEB128.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,26 @@ inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
return Value;
}

inline uint64_t decodeULEB128AndInc(const uint8_t *&p) {
inline uint64_t decodeULEB128AndInc(const uint8_t *&p, const uint8_t *end,
const char **error = nullptr) {
unsigned n;
auto ret = decodeULEB128(p, &n);
auto ret = decodeULEB128(p, &n, end, error);
p += n;
return ret;
}

inline int64_t decodeSLEB128AndInc(const uint8_t *&p) {
inline int64_t decodeSLEB128AndInc(const uint8_t *&p, const uint8_t *end,
const char **error = nullptr) {
unsigned n;
auto ret = decodeSLEB128(p, &n);
auto ret = decodeSLEB128(p, &n, end, error);
p += n;
return ret;
}

inline uint64_t decodeULEB128AndIncUnsafe(const uint8_t *&p) {
return decodeULEB128AndInc(p, nullptr);
}

/// Utility function to get the size of the ULEB128-encoded value.
extern unsigned getULEB128Size(uint64_t Value);

Expand Down
25 changes: 24 additions & 1 deletion llvm/unittests/Support/LEB128Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ TEST(LEB128Test, DecodeInvalidULEB128) {
EXPECT_NE(Error, nullptr); \
EXPECT_EQ(0ul, Actual); \
EXPECT_EQ(ERROR_OFFSET, ErrorOffset); \
Value = reinterpret_cast<const uint8_t *>(VALUE); \
Error = nullptr; \
Actual = decodeULEB128AndInc(Value, Value + strlen(VALUE), &Error); \
EXPECT_NE(Error, nullptr); \
EXPECT_EQ(0ul, Actual); \
EXPECT_EQ(ERROR_OFFSET, Value - reinterpret_cast<const uint8_t *>(VALUE)); \
} while (0)

// Buffer overflow.
Expand Down Expand Up @@ -224,6 +230,12 @@ TEST(LEB128Test, DecodeInvalidSLEB128) {
EXPECT_NE(Error, nullptr); \
EXPECT_EQ(0ul, Actual); \
EXPECT_EQ(ERROR_OFFSET, ErrorOffset); \
Value = reinterpret_cast<const uint8_t *>(VALUE); \
Error = nullptr; \
Actual = decodeSLEB128AndInc(Value, Value + strlen(VALUE), &Error); \
EXPECT_NE(Error, nullptr); \
EXPECT_EQ(0ul, Actual); \
EXPECT_EQ(ERROR_OFFSET, Value - reinterpret_cast<const uint8_t *>(VALUE)); \
} while (0)

// Buffer overflow.
Expand All @@ -246,7 +258,7 @@ TEST(LEB128Test, DecodeAndInc) {
#define EXPECT_LEB128(FUN, VALUE, SIZE) \
do { \
const uint8_t *V = reinterpret_cast<const uint8_t *>(VALUE), *P = V; \
auto Expected = FUN(P), Actual = FUN##AndInc(P); \
auto Expected = FUN(P), Actual = FUN##AndInc(P, P + strlen(VALUE)); \
EXPECT_EQ(Actual, Expected); \
EXPECT_EQ(P - V, SIZE); \
} while (0)
Expand All @@ -255,6 +267,17 @@ TEST(LEB128Test, DecodeAndInc) {
EXPECT_LEB128(decodeSLEB128, "\x7f", 1);
EXPECT_LEB128(decodeSLEB128, "\x80\x01", 2);
#undef EXPECT_LEB128

#define EXPECT_LEB128(FUN, VALUE, SIZE) \
do { \
const uint8_t *V = reinterpret_cast<const uint8_t *>(VALUE), *P = V; \
auto Expected = FUN(P), Actual = FUN##AndIncUnsafe(P); \
EXPECT_EQ(Actual, Expected); \
EXPECT_EQ(P - V, SIZE); \
} while (0)
EXPECT_LEB128(decodeULEB128, "\x7f", 1);
EXPECT_LEB128(decodeULEB128, "\x80\x01", 2);
#undef EXPECT_LEB128
}

TEST(LEB128Test, SLEB128Size) {
Expand Down
16 changes: 8 additions & 8 deletions llvm/utils/TableGen/DecoderEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2301,7 +2301,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
}
case MCD::OPC_CheckField: {
// Decode the start value.
unsigned Start = decodeULEB128AndInc(++Ptr);
unsigned Start = decodeULEB128AndIncUnsafe(++Ptr);
unsigned Len = *Ptr;)";
if (IsVarLenInst)
OS << "\n makeUp(insn, Start + Len);";
Expand All @@ -2328,7 +2328,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
}
case MCD::OPC_CheckPredicate: {
// Decode the Predicate Index value.
unsigned PIdx = decodeULEB128AndInc(++Ptr);
unsigned PIdx = decodeULEB128AndIncUnsafe(++Ptr);
// NumToSkip is a plain 24-bit integer.
unsigned NumToSkip = *Ptr++;
NumToSkip |= (*Ptr++) << 8;
Expand All @@ -2345,8 +2345,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
}
case MCD::OPC_Decode: {
// Decode the Opcode value.
unsigned Opc = decodeULEB128AndInc(++Ptr);
unsigned DecodeIdx = decodeULEB128AndInc(Ptr);
unsigned Opc = decodeULEB128AndIncUnsafe(++Ptr);
unsigned DecodeIdx = decodeULEB128AndIncUnsafe(Ptr);
MI.clear();
MI.setOpcode(Opc);
Expand All @@ -2366,8 +2366,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
}
case MCD::OPC_TryDecode: {
// Decode the Opcode value.
unsigned Opc = decodeULEB128AndInc(++Ptr);
unsigned DecodeIdx = decodeULEB128AndInc(Ptr);
unsigned Opc = decodeULEB128AndIncUnsafe(++Ptr);
unsigned DecodeIdx = decodeULEB128AndIncUnsafe(Ptr);
// NumToSkip is a plain 24-bit integer.
unsigned NumToSkip = *Ptr++;
NumToSkip |= (*Ptr++) << 8;
Expand Down Expand Up @@ -2399,8 +2399,8 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
}
case MCD::OPC_SoftFail: {
// Decode the mask values.
uint64_t PositiveMask = decodeULEB128AndInc(++Ptr);
uint64_t NegativeMask = decodeULEB128AndInc(Ptr);
uint64_t PositiveMask = decodeULEB128AndIncUnsafe(++Ptr);
uint64_t NegativeMask = decodeULEB128AndIncUnsafe(Ptr);
bool Fail = (insn & PositiveMask) != 0 || (~insn & NegativeMask) != 0;
if (Fail)
S = MCDisassembler::SoftFail;
Expand Down

0 comments on commit efad149

Please sign in to comment.