https://github.com/firmiana402 created https://github.com/llvm/llvm-project/pull/201288
## Summary LLDB currently accepts and evaluates some ill-typed DWARF typed binary operations whose two operands have different base types. DWARF v5 typed-expression rules require arithmetic/logical and relational binary operators to operate on operands of the same type, either the same base type or the generic type. (see [DWARF v5 doc](https://dwarfstd.org/doc/DWARF5.pdf) Section 2.5.1.4) This patch adds an explicit compatibility check before evaluating the affected binary operators. ## Example A DWARF expression illustrating the issue is: ```text DW_OP_constu 0xff DW_OP_convert <unsigned char> DW_OP_constu 0x1 DW_OP_convert <short unsigned int> DW_OP_plus DW_OP_stack_value ``` The left operand is typed as unsigned char, while the right operand is typed as short unsigned int. These are different DWARF base types, so `DW_OP_plus` should reject the expression instead of evaluating it. In differential testing, GDB rejects this kind of expression with: ```text Incompatible types on DWARF stack ``` Before this patch, LLDB continued evaluating the expression and produced a concrete result through the existing `Scalar` arithmetic path. ## Affected operations The issue is not specific to DW_OP_plus. The same acceptance pattern was observed for mixed-base-type typed operands across these binary operations: - Arithmetic: `DW_OP_plus`, `DW_OP_minus`, `DW_OP_div`, `DW_OP_mod` - Bitwise: `DW_OP_and`, `DW_OP_or`, `DW_OP_xor` - Shifts: `DW_OP_shl`, `DW_OP_shr`, `DW_OP_shra` - Relations: `DW_OP_lt`, `DW_OP_le`, `DW_OP_gt`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_ne` ## Implementation notes LLDB's DWARF expression stack currently stores `Value` objects, whose scalar payload is represented by `Scalar`. `Scalar` does not preserve the original DWARF base type DIE, but it does carry the pieces of base-type information used by the evaluator: - scalar kind - byte size - integer signedness This patch therefore checks those `Scalar` properties before dispatching each affected binary operation to the existing arithmetic/comparison logic. If the two operands do not match, evaluation now stops with an error. >From f1b02e03761213e92d2e782c0b367d9d56cd240a Mon Sep 17 00:00:00 2001 From: firmiana402 <[email protected]> Date: Wed, 3 Jun 2026 11:31:09 +0800 Subject: [PATCH] [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(); _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
