https://github.com/qiyao created 
https://github.com/llvm/llvm-project/pull/207009

The empty-stack branch of `Evaluate_DW_OP_piece` resizes a `Value`'s data
buffer to the piece byte size and then `memset`s that many bytes:

```
    curr_piece.ResizeData(piece_byte_size);
    ::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
```

The `piece_byte_size` is an untrusted DWARF operand, and the resize result
is never checked.  `DataBufferHeap::SetByteSize` silently leaves the
buffer empty when the requested size cannot be allocated, so a huge
`DW_OP_piece` operand produces a `memset` over an unallocated buffer: a
wild write.  ASan reports it as a wild write from the
lldb-dwarf-expression-fuzzer; even without ASan it faults.  The unit test
feeds a `DW_OP_piece` whose ULEB128 operand encodes `INT64_MAX`:

```
[ RUN      ] DWARFExpression.DW_OP_piece_empty_stack_huge_size
 #2 SignalHandler(int, __siginfo*, void*)
 #4 DWARFExpression::Evaluate(...)
```

(SIGSEGV, the process aborts.)

Verify `ResizeData` actually produced the requested size and return an
error otherwise, matching the existing check in the load-address piece
path.

Adds `DWARFExpression.DW_OP_piece_empty_stack_huge_size`, which crashes
(SIGSEGV / ASan wild write) without the fix.


>From a9f4f192e6fbbcdee4ff0a505bcec0c2262b430f Mon Sep 17 00:00:00 2001
From: Yao Qi <[email protected]>
Date: Wed, 24 Jun 2026 16:02:35 +0100
Subject: [PATCH] [lldb] Check buffer allocation in DW_OP_piece empty-stack
 path

The empty-stack branch of `Evaluate_DW_OP_piece` resizes a `Value`'s data
buffer to the piece byte size and then `memset`s that many bytes:

```
    curr_piece.ResizeData(piece_byte_size);
    ::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
```

The `piece_byte_size` is an untrusted DWARF operand, and the resize result
is never checked.  `DataBufferHeap::SetByteSize` silently leaves the
buffer empty when the requested size cannot be allocated, so a huge
`DW_OP_piece` operand produces a `memset` over an unallocated buffer: a
wild write.  ASan reports it as a wild write from the
lldb-dwarf-expression-fuzzer; even without ASan it faults.  The unit test
feeds a `DW_OP_piece` whose ULEB128 operand encodes `INT64_MAX`:

```
[ RUN      ] DWARFExpression.DW_OP_piece_empty_stack_huge_size
 #2 SignalHandler(int, __siginfo*, void*)
 #4 DWARFExpression::Evaluate(...)
```

(SIGSEGV, the process aborts.)

Verify `ResizeData` actually produced the requested size and return an
error otherwise, matching the existing check in the load-address piece
path.

Adds `DWARFExpression.DW_OP_piece_empty_stack_huge_size`, which crashes
(SIGSEGV / ASan wild write) without the fix.
---
 lldb/source/Expression/DWARFExpression.cpp        | 5 ++++-
 lldb/unittests/Expression/DWARFExpressionTest.cpp | 9 +++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 5a3c99caeb1bb..90c61b2ff89eb 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1085,7 +1085,10 @@ static llvm::Error Evaluate_DW_OP_piece(EvalContext 
&eval_ctx,
     // In a multi-piece expression, this means that the current piece is
     // not available. Fill with zeros for now by resizing the data and
     // appending it
-    curr_piece.ResizeData(piece_byte_size);
+    if (curr_piece.ResizeData(piece_byte_size) != piece_byte_size)
+      return llvm::createStringError(
+          "failed to resize the piece buffer to %" PRIu64 " bytes",
+          piece_byte_size);
     // Note that "0" is not a correct value for the unknown bits.
     // It would be better to also return a mask of valid bits together
     // with the expression result, so the debugger can print missing
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 305c4af2582db..829e490213194 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -617,6 +617,15 @@ TEST(DWARFExpression, DW_OP_piece) {
       ExpectHostAddress(expected_host_buffer));
 }
 
+TEST(DWARFExpression, DW_OP_piece_empty_stack_huge_size) {
+  // An empty-stack DW_OP_piece with a byte size that cannot be allocated must
+  // report an error.  The ULEB128 operand here encodes INT64_MAX.
+  EXPECT_THAT_ERROR(Evaluate({DW_OP_piece, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                              0xff, 0xff, 0x7f})
+                        .takeError(),
+                    llvm::Failed());
+}
+
 TEST(DWARFExpression, DW_OP_implicit_value) {
   unsigned char bytes = 4;
 

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to