https://github.com/aokblast updated 
https://github.com/llvm/llvm-project/pull/208876

>From ff1c952537629af987c846f3447278767925688d Mon Sep 17 00:00:00 2001
From: ShengYi Hung <[email protected]>
Date: Sat, 11 Jul 2026 11:43:20 +0800
Subject: [PATCH] [LLDB] Detect Memory overlapping between AllocateMemory and
 MemoryInfo

IRMemoryMap estimates a free address range using memory information.
However, the memory returns by AllocateMemory can overlap with the
ranges reported by MemoryInfo (internally backed by PT_VM_ENTRY),
because the kernel is unaware of allocations made during the probing
process.

As a result, two allocatios may silently insert duplicate key for
different objects, leading to intermittent test failure. The issue is
nodeterministic because it depends on the underlying malloc
implementation and ASLR.

Fix this by detecting overlapping allocations after AllocateMemory. If
an overlap is found, fall back to the address-guessing path, which
perform the necessary overlap checks before committing the allocation.

Also, return and print  message in IRInterpreter in unsecessful allocation.
---
 lldb/include/lldb/Expression/IRMemoryMap.h |  6 +++
 lldb/source/Expression/IRInterpreter.cpp   |  7 ++-
 lldb/source/Expression/IRMemoryMap.cpp     | 50 +++++++++++++++++++++-
 3 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/Expression/IRMemoryMap.h 
b/lldb/include/lldb/Expression/IRMemoryMap.h
index 56f79444764e6..f236b33deea50 100644
--- a/lldb/include/lldb/Expression/IRMemoryMap.h
+++ b/lldb/include/lldb/Expression/IRMemoryMap.h
@@ -134,6 +134,12 @@ class IRMemoryMap {
   // memory map.
   bool IntersectsAllocation(lldb::addr_t addr, size_t size) const;
 
+  // Returns true if the given range intersects a host-only allocation.
+  // Host-only allocations have no backing memory in the process, so the
+  // process may hand out addresses inside them for real allocations; such
+  // collisions must be detected and avoided.
+  bool IntersectsHostOnlyAllocation(lldb::addr_t addr, size_t size) const;
+
   // Returns true if the two given allocations intersect each other.
   static bool AllocationsIntersect(lldb::addr_t addr1, size_t size1,
                                    lldb::addr_t addr2, size_t size2);
diff --git a/lldb/source/Expression/IRInterpreter.cpp 
b/lldb/source/Expression/IRInterpreter.cpp
index 69e7d0b327803..cb5151f6823a1 100644
--- a/lldb/source/Expression/IRInterpreter.cpp
+++ b/lldb/source/Expression/IRInterpreter.cpp
@@ -722,6 +722,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, 
llvm::Function &function,
   if (frame.m_frame_process_address == LLDB_INVALID_ADDRESS) {
     error =
         lldb_private::Status::FromErrorString("Couldn't allocate stack frame");
+    return false;
   }
 
   int arg_index = 0;
@@ -737,7 +738,11 @@ bool IRInterpreter::Interpret(llvm::Module &module, 
llvm::Function &function,
 
     lldb::addr_t ptr = args[arg_index];
 
-    frame.MakeArgument(&*ai, ptr);
+    if (!frame.MakeArgument(&*ai, ptr)) {
+      error = lldb_private::Status::FromErrorString(
+          "Couldn't write an argument into the interpreter's stack frame");
+      return false;
+    }
   }
 
   frame.Jump(&function.front());
diff --git a/lldb/source/Expression/IRMemoryMap.cpp 
b/lldb/source/Expression/IRMemoryMap.cpp
index fd46a48930bd4..e99480a99de59 100644
--- a/lldb/source/Expression/IRMemoryMap.cpp
+++ b/lldb/source/Expression/IRMemoryMap.cpp
@@ -74,8 +74,16 @@ lldb::addr_t IRMemoryMap::FindSpace(size_t size) {
 
     if (!alloc_error.Success())
       return LLDB_INVALID_ADDRESS;
-    else
+
+    // The process knows nothing about host-only allocations handed out by the
+    // guessing algorithm below, so the address it returned may collide with
+    // one of them.  Give the memory back and fall through to hunting for a
+    // free range above the existing allocations instead.
+    if (!IntersectsHostOnlyAllocation(ret, size))
       return ret;
+
+    process_sp->DeallocateMemory(ret);
+    ret = LLDB_INVALID_ADDRESS;
   }
 
   // At this point we know that we need to hunt.
@@ -244,6 +252,26 @@ bool IRMemoryMap::IntersectsAllocation(lldb::addr_t addr, 
size_t size) const {
   return false;
 }
 
+bool IRMemoryMap::IntersectsHostOnlyAllocation(lldb::addr_t addr,
+                                               size_t size) const {
+  if (addr == LLDB_INVALID_ADDRESS)
+    return false;
+
+  // Unlike IntersectsAllocation, scan all allocations: the map's recorded
+  // extents for process-backed allocations may overlap each other (e.g.
+  // zero-sized requests over-record their size), so the disjoint-intervals
+  // assumption that allows a neighbors-only check does not hold.
+  for (const auto &[base, allocation] : m_allocations) {
+    if (allocation.m_policy != eAllocationPolicyHostOnly)
+      continue;
+    if (AllocationsIntersect(addr, size, allocation.m_process_start,
+                             allocation.m_size))
+      return true;
+  }
+
+  return false;
+}
+
 bool IRMemoryMap::AllocationsIntersect(lldb::addr_t addr1, size_t size1,
                                        lldb::addr_t addr2, size_t size2) {
   // Given two half open intervals [A, B) and [X, Y), the only 6 permutations
@@ -419,6 +447,26 @@ IRMemoryMap::Malloc(size_t size, uint8_t alignment, 
uint32_t permissions,
   lldb::addr_t mask = alignment - 1;
   aligned_address = (allocation_address + mask) & (~mask);
 
+  // A collision here means FindSpace or the process allocator returned an
+  // address that overlaps a live allocation.  Registering it anyway would
+  // silently fail (duplicate map key) or alias another allocation's memory,
+  // corrupting expression state in hard-to-debug ways.  Fail loudly instead.
+  //
+  // Only real (process-backed) allocations landing on top of a host-only
+  // allocation are a genuine collision: the process can't know about
+  // host-only address labels.  Overlaps among process-backed allocations are
+  // the process allocator's business, and our recorded extents may
+  // over-estimate the real reservation (e.g. for zero-sized requests), so
+  // don't second-guess them here.  Host-only allocations themselves come
+  // from FindSpace, which already avoids all existing allocations.
+  if (policy != eAllocationPolicyHostOnly &&
+      IntersectsHostOnlyAllocation(allocation_address, allocation_size)) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Couldn't malloc: allocation at 0x%" PRIx64
+                                   " collides with an existing allocation",
+                                   allocation_address);
+  }
+
   m_allocations.emplace(
       std::piecewise_construct, std::forward_as_tuple(aligned_address),
       std::forward_as_tuple(allocation_address, aligned_address,

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

Reply via email to