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