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

Reply via email to