https://github.com/qiyao updated https://github.com/llvm/llvm-project/pull/207008
>From ff59e0b8da9b82c0cb5504d99c1d11e30e139b4a Mon Sep 17 00:00:00 2001 From: Yao Qi <[email protected]> Date: Wed, 24 Jun 2026 11:43:09 +0100 Subject: [PATCH 1/5] [lldb] Guard DW_OP_convert against null DWARF unit and empty stack `Evaluate_DW_OP_convert` dereferenced `eval_ctx.dwarf_cu` (the `DWARFExpression` Delegate) whenever the operand DIE offset was non-zero, and unconditionally read `eval_ctx.stack.back()`. When a DWARF expression is evaluated without a DWARF unit (as the lldb-dwarf-expression-fuzzer does), two operand shapes crash: - `DW_OP_convert` with a non-zero offset calls `dwarf_cu->GetDIEBitSizeAndSign(...)` on a null Delegate. - `DW_OP_convert` with nothing on the stack reads the back of an empty vector. The unit test feeds both with `dwarf_cu == nullptr` and crashes: ``` [ RUN ] DWARFExpression.DW_OP_convert #2 SignalHandler(int, __siginfo*, void*) #4 DWARFExpression::Evaluate(...) #5 Evaluate(ArrayRef<unsigned char>, ...) ``` (SIGSEGV, the process aborts.) Bail out with an error when the stack is empty, and when a non-zero DIE offset is requested without a DWARF unit, instead of crashing. Extends `DWARFExpression.DW_OP_convert` with these two cases, which crash without the fix. --- lldb/source/Expression/DWARFExpression.cpp | 6 ++++++ lldb/unittests/Expression/DWARFExpressionTest.cpp | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 5a3c99caeb1bb..aa4fd62f313d7 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -1201,6 +1201,9 @@ static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx, static llvm::Error Evaluate_DW_OP_convert(EvalContext &eval_ctx, uint64_t relative_die_offset) { + if (eval_ctx.stack.empty()) + return llvm::createStringError("DW_OP_convert needs an argument"); + uint64_t bit_size; bool sign; if (relative_die_offset == 0) { @@ -1214,6 +1217,9 @@ static llvm::Error Evaluate_DW_OP_convert(EvalContext &eval_ctx, if (!bit_size) return llvm::createStringError("unspecified architecture"); } else { + if (!eval_ctx.dwarf_cu) + return llvm::createStringError( + "DW_OP_convert with a DIE offset requires a DWARF unit"); auto bit_size_sign_or_err = eval_ctx.dwarf_cu->GetDIEBitSizeAndSign(relative_die_offset); if (!bit_size_sign_or_err) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 305c4af2582db..2bb939778d7e4 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -574,6 +574,20 @@ TEST(DWARFExpression, DW_OP_convert) { EXPECT_THAT_ERROR( t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), llvm::Failed()); + + // A non-zero DIE offset with no DWARF unit must report an error rather than + // dereferencing a null Delegate (caught by lldb-dwarf-expression-fuzzer). + EXPECT_THAT_ERROR( + Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x01}, nullptr, nullptr) + .takeError(), + llvm::Failed()); + + // DW_OP_convert with an empty stack must report an error rather than + // accessing the back of an empty stack (caught by + // lldb-dwarf-expression-fuzzer). + EXPECT_THAT_ERROR( + Evaluate({DW_OP_convert, 0x00}, nullptr, nullptr).takeError(), + llvm::Failed()); } TEST(DWARFExpression, DW_OP_stack_value) { >From e82f4459e3fc7949d7a387b47863d03878b83af5 Mon Sep 17 00:00:00 2001 From: Yao Qi <[email protected]> Date: Thu, 2 Jul 2026 23:22:03 +0100 Subject: [PATCH 2/5] Update lldb/unittests/Expression/DWARFExpressionTest.cpp Co-authored-by: Michael Buch <[email protected]> --- lldb/unittests/Expression/DWARFExpressionTest.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 2bb939778d7e4..a45ab7242b3bc 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -575,8 +575,7 @@ TEST(DWARFExpression, DW_OP_convert) { t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), llvm::Failed()); - // A non-zero DIE offset with no DWARF unit must report an error rather than - // dereferencing a null Delegate (caught by lldb-dwarf-expression-fuzzer). + // A non-zero DIE offset with no DWARF unit. EXPECT_THAT_ERROR( Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x01}, nullptr, nullptr) .takeError(), >From 09a35cdae2e7aee87038be53f526e31865b9e9a6 Mon Sep 17 00:00:00 2001 From: Yao Qi <[email protected]> Date: Thu, 2 Jul 2026 23:22:12 +0100 Subject: [PATCH 3/5] Update lldb/unittests/Expression/DWARFExpressionTest.cpp Co-authored-by: Michael Buch <[email protected]> --- lldb/unittests/Expression/DWARFExpressionTest.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index a45ab7242b3bc..fc0b7fb05cd71 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -581,9 +581,7 @@ TEST(DWARFExpression, DW_OP_convert) { .takeError(), llvm::Failed()); - // DW_OP_convert with an empty stack must report an error rather than - // accessing the back of an empty stack (caught by - // lldb-dwarf-expression-fuzzer). + // DW_OP_convert with an empty stack. EXPECT_THAT_ERROR( Evaluate({DW_OP_convert, 0x00}, nullptr, nullptr).takeError(), llvm::Failed()); >From f08fe0ae84ce018cad55b5514ebf4f850ab5c8ca Mon Sep 17 00:00:00 2001 From: Yao Qi <[email protected]> Date: Thu, 2 Jul 2026 23:40:39 +0100 Subject: [PATCH 4/5] replace llvm::Failed with llvm::FailedWithMessage --- lldb/unittests/Expression/DWARFExpressionTest.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index fc0b7fb05cd71..59dbc38d5bf2f 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -579,12 +579,13 @@ TEST(DWARFExpression, DW_OP_convert) { EXPECT_THAT_ERROR( Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x01}, nullptr, nullptr) .takeError(), - llvm::Failed()); + llvm::FailedWithMessage( + "DW_OP_convert with a DIE offset requires a DWARF unit")); // DW_OP_convert with an empty stack. EXPECT_THAT_ERROR( Evaluate({DW_OP_convert, 0x00}, nullptr, nullptr).takeError(), - llvm::Failed()); + llvm::FailedWithMessage("DW_OP_convert needs an argument")); } TEST(DWARFExpression, DW_OP_stack_value) { >From 0ec4769b5cf677c7c71a7be2f1968efb2ec5777f Mon Sep 17 00:00:00 2001 From: Yao Qi <[email protected]> Date: Fri, 3 Jul 2026 08:31:58 +0100 Subject: [PATCH 5/5] Remove unreachable empty-stack check in Evaluate_DW_OP_convert In previous commit, `llvm::Failed` is replaced with `llvm::FailedWithMessage`, it shows that The empty-stack guard in `Evaluate_DW_OP_convert` was a deadcode. Before the opcode switch dispatches to it, `DWARFExpression::Evaluate` already runs a generic arity precondition check. Since `OperationArity(DW_OP_convert)` is 1, an empty stack is rejected there first with ``` "DW_OP_convert needs at least 1 stack entries (stack has 0 entries)" ``` so the function-specific "DW_OP_convert needs an argument" error could never be produced. Remove the redundant check and update the unit test to expect the generic message that actually fires. This test covers the error message from generic arity precondition check. No functional change: DW_OP_convert on an empty stack still fails, only the diagnostic wording differs. --- lldb/source/Expression/DWARFExpression.cpp | 3 --- lldb/unittests/Expression/DWARFExpressionTest.cpp | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index aa4fd62f313d7..985a2dfecd38f 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -1201,9 +1201,6 @@ static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx, static llvm::Error Evaluate_DW_OP_convert(EvalContext &eval_ctx, uint64_t relative_die_offset) { - if (eval_ctx.stack.empty()) - return llvm::createStringError("DW_OP_convert needs an argument"); - uint64_t bit_size; bool sign; if (relative_die_offset == 0) { diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 59dbc38d5bf2f..75162ca0b5f3e 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -585,7 +585,8 @@ TEST(DWARFExpression, DW_OP_convert) { // DW_OP_convert with an empty stack. EXPECT_THAT_ERROR( Evaluate({DW_OP_convert, 0x00}, nullptr, nullptr).takeError(), - llvm::FailedWithMessage("DW_OP_convert needs an argument")); + llvm::FailedWithMessage("DW_OP_convert needs at least 1 stack entries " + "(stack has 0 entries)")); } TEST(DWARFExpression, DW_OP_stack_value) { _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
