https://github.com/firmiana402 updated https://github.com/llvm/llvm-project/pull/201288
>From f1b02e03761213e92d2e782c0b367d9d56cd240a Mon Sep 17 00:00:00 2001 From: firmiana402 <[email protected]> Date: Wed, 3 Jun 2026 11:31:09 +0800 Subject: [PATCH 1/3] [lldb] Reject mixed typed DWARF binary operands --- lldb/source/Expression/DWARFExpression.cpp | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 106e3b4d59283..c04fcc34b7dfa 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -1291,6 +1291,32 @@ static llvm::Error Evaluate_DW_OP_call_frame_cfa(EvalContext &eval_ctx) { return llvm::Error::success(); } +static llvm::Error CheckScalarOperandsHaveSameType(const Scalar &lhs, + const Scalar &rhs, + LocationAtom opcode) { + // Scalar does not preserve the original DWARF DIE, but it does carry the + // pieces of base-type information used by the evaluator: kind, size, and + // integer signedness. + if (lhs.GetType() != rhs.GetType()) + return llvm::createStringError( + "%s requires operands to have the same type", + DW_OP_value_to_name(opcode)); + + if (lhs.GetByteSize() != rhs.GetByteSize()) + return llvm::createStringError( + "%s requires operands to have the same type", + DW_OP_value_to_name(opcode)); + + // Floating scalars do not have integer signedness, so only compare + // signedness after establishing that both operands are integers. + if (lhs.GetType() == Scalar::e_int && lhs.IsSigned() != rhs.IsSigned()) + return llvm::createStringError( + "%s requires operands to have the same type", + DW_OP_value_to_name(opcode)); + + return llvm::Error::success(); +} + llvm::Expected<Value> DWARFExpression::Evaluate( ExecutionContext *exe_ctx, RegisterContext *reg_ctx, lldb::ModuleSP module_sp, const DataExtractor &opcodes, @@ -1470,12 +1496,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_and: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() & tmp.GetScalar(); break; case DW_OP_div: { + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); if (tmp.GetScalar().IsZero()) return llvm::createStringError("divide by zero"); @@ -1493,12 +1527,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate( } break; case DW_OP_minus: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() - tmp.GetScalar(); break; case DW_OP_mod: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() % tmp.GetScalar(); @@ -1521,12 +1563,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_or: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() | tmp.GetScalar(); break; case DW_OP_plus: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() += tmp.GetScalar(); @@ -1541,12 +1591,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate( } break; case DW_OP_shl: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() <<= tmp.GetScalar(); break; case DW_OP_shr: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); if (!stack.back().GetScalar().ShiftRightLogical(tmp.GetScalar())) @@ -1554,12 +1612,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_shra: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() >>= tmp.GetScalar(); break; case DW_OP_xor: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() ^ tmp.GetScalar(); @@ -1601,36 +1667,60 @@ llvm::Expected<Value> DWARFExpression::Evaluate( } break; case DW_OP_eq: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() == tmp.GetScalar(); break; case DW_OP_ge: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() >= tmp.GetScalar(); break; case DW_OP_gt: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() > tmp.GetScalar(); break; case DW_OP_le: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() <= tmp.GetScalar(); break; case DW_OP_lt: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() < tmp.GetScalar(); break; case DW_OP_ne: + if (llvm::Error err = CheckScalarOperandsHaveSameType( + stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), + opcode)) + return err; tmp = stack.back(); stack.pop_back(); stack.back().GetScalar() = stack.back().GetScalar() != tmp.GetScalar(); >From dd117340160e242853d09b2c57477de6d762c243 Mon Sep 17 00:00:00 2001 From: firmiana402 <[email protected]> Date: Thu, 4 Jun 2026 11:00:50 +0800 Subject: [PATCH 2/3] [lldb] Test mixed typed DWARF binary operands --- .../Expression/DWARFExpressionTest.cpp | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 00ee6b13ad93c..ddbbdc91711ff 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -576,6 +576,54 @@ TEST(DWARFExpression, DW_OP_convert) { llvm::Failed()); } +TEST(DWARFExpression, TypedBinaryOpsRejectMismatchedTypes) { + class TypedDwarfDelegate : public MockDwarfDelegate { + public: + enum : uint8_t { + UnsignedChar = 1, + SignedChar = 2, + UnsignedShort = 3, + }; + + llvm::Expected<std::pair<uint64_t, bool>> + GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override { + switch (relative_die_offset) { + case UnsignedChar: + return std::pair<uint64_t, bool>{8, false}; + case SignedChar: + return std::pair<uint64_t, bool>{8, true}; + case UnsignedShort: + return std::pair<uint64_t, bool>{16, false}; + default: + return llvm::createStringError("unknown base type offset"); + } + } + }; + + TypedDwarfDelegate unit; + constexpr uint8_t opcodes[] = { + DW_OP_plus, DW_OP_minus, DW_OP_div, DW_OP_mod, DW_OP_and, DW_OP_or, + DW_OP_xor, DW_OP_shl, DW_OP_shr, DW_OP_shra, DW_OP_lt, DW_OP_le, + DW_OP_gt, DW_OP_ge, DW_OP_eq, DW_OP_ne, + }; + + for (uint8_t opcode : opcodes) { + std::vector<uint8_t> expr = { + DW_OP_constu, 0xff, 0x01, DW_OP_convert, + TypedDwarfDelegate::UnsignedChar, DW_OP_lit1, DW_OP_convert, + TypedDwarfDelegate::UnsignedShort, opcode, DW_OP_stack_value}; + EXPECT_THAT_EXPECTED(Evaluate(expr, {}, &unit), llvm::Failed()) + << "opcode 0x" << llvm::utohexstr(opcode); + } + + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_constu, 0xff, 0x01, DW_OP_convert, + TypedDwarfDelegate::UnsignedChar, DW_OP_lit1, DW_OP_convert, + TypedDwarfDelegate::SignedChar, DW_OP_plus, DW_OP_stack_value}, + {}, &unit), + llvm::Failed()); +} + TEST(DWARFExpression, DW_OP_stack_value) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); } >From 1749a4c867c632410cd8334ddddab65defb586af Mon Sep 17 00:00:00 2001 From: firmiana402 <[email protected]> Date: Fri, 5 Jun 2026 23:16:20 +0800 Subject: [PATCH 3/3] Relax generic DWARF operand checks and format code --- lldb/source/Expression/DWARFExpression.cpp | 72 +++++++++++-------- .../Expression/DWARFExpressionTest.cpp | 32 +++++++-- 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index c04fcc34b7dfa..25d9f8ca38682 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -1293,26 +1293,40 @@ static llvm::Error Evaluate_DW_OP_call_frame_cfa(EvalContext &eval_ctx) { static llvm::Error CheckScalarOperandsHaveSameType(const Scalar &lhs, const Scalar &rhs, - LocationAtom opcode) { + LocationAtom opcode, + size_t address_size) { // Scalar does not preserve the original DWARF DIE, but it does carry the // pieces of base-type information used by the evaluator: kind, size, and // integer signedness. if (lhs.GetType() != rhs.GetType()) - return llvm::createStringError( - "%s requires operands to have the same type", - DW_OP_value_to_name(opcode)); + return llvm::createStringError("%s requires operands to have the same type", + DW_OP_value_to_name(opcode)); if (lhs.GetByteSize() != rhs.GetByteSize()) - return llvm::createStringError( - "%s requires operands to have the same type", - DW_OP_value_to_name(opcode)); + return llvm::createStringError("%s requires operands to have the same type", + DW_OP_value_to_name(opcode)); - // Floating scalars do not have integer signedness, so only compare - // signedness after establishing that both operands are integers. - if (lhs.GetType() == Scalar::e_int && lhs.IsSigned() != rhs.IsSigned()) - return llvm::createStringError( - "%s requires operands to have the same type", - DW_OP_value_to_name(opcode)); + // Only integer scalars have signedness, so non-integer operands have no + // further scalar type information to compare after kind and size match. + if (lhs.GetType() != Scalar::e_int) + return llvm::Error::success(); + + // DWARF generic values are address-sized integers with unspecified + // signedness. LLDB does not explicitly preserve genericness on the expression + // stack, so treat integers at least as wide as the generic type as + // potentially generic to keep existing expressions compatible. For example, + // DW_OP_constu and DW_OP_consts currently do not always use to_generic due to + // https://github.com/llvm/llvm-project/issues/47431. A precise fix would + // require tracking genericness directly, which is a larger type-system + // change, so do not use signedness to reject these operands here. + if (address_size != 0 && lhs.GetByteSize() >= address_size) + return llvm::Error::success(); + + // For non-generic integer operands, signedness is part of the base-type + // information preserved by Scalar, so require it to match. + if (lhs.IsSigned() != rhs.IsSigned()) + return llvm::createStringError("%s requires operands to have the same type", + DW_OP_value_to_name(opcode)); return llvm::Error::success(); } @@ -1498,7 +1512,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_and: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1508,7 +1522,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_div: { if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); if (tmp.GetScalar().IsZero()) @@ -1529,7 +1543,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_minus: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1539,7 +1553,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_mod: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1565,7 +1579,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_or: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1575,7 +1589,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_plus: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1593,7 +1607,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_shl: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1603,7 +1617,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_shr: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1614,7 +1628,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_shra: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1624,7 +1638,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_xor: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1669,7 +1683,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_eq: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1679,7 +1693,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_ge: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1689,7 +1703,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_gt: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1699,7 +1713,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_le: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1709,7 +1723,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_lt: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); @@ -1719,7 +1733,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_ne: if (llvm::Error err = CheckScalarOperandsHaveSameType( stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode)) + opcode, address_size)) return err; tmp = stack.back(); stack.pop_back(); diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index ddbbdc91711ff..9a5c2a4258471 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -602,16 +602,22 @@ TEST(DWARFExpression, TypedBinaryOpsRejectMismatchedTypes) { TypedDwarfDelegate unit; constexpr uint8_t opcodes[] = { - DW_OP_plus, DW_OP_minus, DW_OP_div, DW_OP_mod, DW_OP_and, DW_OP_or, + DW_OP_plus, DW_OP_minus, DW_OP_div, DW_OP_mod, DW_OP_and, DW_OP_or, DW_OP_xor, DW_OP_shl, DW_OP_shr, DW_OP_shra, DW_OP_lt, DW_OP_le, DW_OP_gt, DW_OP_ge, DW_OP_eq, DW_OP_ne, }; for (uint8_t opcode : opcodes) { - std::vector<uint8_t> expr = { - DW_OP_constu, 0xff, 0x01, DW_OP_convert, - TypedDwarfDelegate::UnsignedChar, DW_OP_lit1, DW_OP_convert, - TypedDwarfDelegate::UnsignedShort, opcode, DW_OP_stack_value}; + std::vector<uint8_t> expr = {DW_OP_constu, + 0xff, + 0x01, + DW_OP_convert, + TypedDwarfDelegate::UnsignedChar, + DW_OP_lit1, + DW_OP_convert, + TypedDwarfDelegate::UnsignedShort, + opcode, + DW_OP_stack_value}; EXPECT_THAT_EXPECTED(Evaluate(expr, {}, &unit), llvm::Failed()) << "opcode 0x" << llvm::utohexstr(opcode); } @@ -624,6 +630,22 @@ TEST(DWARFExpression, TypedBinaryOpsRejectMismatchedTypes) { llvm::Failed()); } +TEST(DWARFExpression, GenericBinaryOpsAllowDifferentSignedness) { + // The DWARF generic type has unspecified signedness, so differently signed + // address-sized generic values are still compatible operands. + uint8_t expr[] = {DW_OP_lit8, DW_OP_consts, 4, DW_OP_minus, + DW_OP_stack_value}; + DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, + /*addr_size*/ 8); + EXPECT_THAT_EXPECTED( + DWARFExpression::Evaluate(/*exe_ctx=*/nullptr, /*reg_ctx=*/nullptr, + /*module_sp=*/{}, extractor, + /*unit=*/nullptr, lldb::eRegisterKindLLDB, + /*initial_value_ptr=*/nullptr, + /*object_address_ptr=*/nullptr), + ExpectScalar(4)); +} + TEST(DWARFExpression, DW_OP_stack_value) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
