[Lldb-commits] [lldb] 30183cb - [lldb] Don't run code for CanJIT() while creating the ObjC runtime (#227555)

via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 2 17:55:40 PDT 2026


Author: Jonas Devlieghere
Date: 2026-10-03T00:55:26Z
New Revision: 30183cb96ab0fb33d4f7aebd5126e75b852f3ba3

URL: https://github.com/llvm/llvm-project/commit/30183cb96ab0fb33d4f7aebd5126e75b852f3ba3
DIFF: https://github.com/llvm/llvm-project/commit/30183cb96ab0fb33d4f7aebd5126e75b852f3ba3.diff

LOG: [lldb] Don't run code for CanJIT() while creating the ObjC runtime (#227555)

When libobjc lacks class_getMethodImplementation, the ObjC trampoline
handler calls CanJIT() to decide whether to warn. Without the _M
packet, CanJIT() allocated memory by calling mmap in the inferior.
Setting up that call unwinds the stack, which asks for the ObjC
runtime. The runtime isn't registered yet, so LLDB creates another one
and recurses until the stack overflows.

Ask the process plugin whether it can allocate memory instead of
trying it. ProcessGDBRemote probes the _M packet and otherwise checks
for an mmap symbol, neither of which runs code in the inferior.

rdar://188335027

Added: 
    lldb/test/API/functionalities/gdb_remote_client/TestObjCRuntimeNoInferiorCall.py
    lldb/test/API/functionalities/gdb_remote_client/libobjc.A.dylib.yaml

Modified: 
    lldb/include/lldb/Target/Process.h
    lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
    lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
    lldb/source/Target/Process.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 984a4ef880800..207c9cf290035 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1864,6 +1864,10 @@ class Process : public std::enable_shared_from_this<Process>,
     return LLDB_INVALID_ADDRESS;
   }
 
+  /// Determines whether DoAllocateMemory is expected to succeed, without
+  /// running code in the process.
+  virtual bool DoCanAllocateMemory() { return false; }
+
   virtual Status WriteObjectFile(std::vector<ObjectFile::LoadableData> entries);
 
   /// The public interface to allocating memory in the process.

diff  --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
index 73fd92f11cdff..e1361dc31fda2 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
@@ -75,6 +75,7 @@ class ProcessWindows : public Process, public ProcessDebugger {
                        Status &error) override;
   lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
                                 Status &error) override;
+  bool DoCanAllocateMemory() override { return true; }
   Status DoDeallocateMemory(lldb::addr_t ptr) override;
 
   lldb::addr_t GetImageInfoAddress() override;

diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 0cb20712c1655..5d1722868cfff 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3404,6 +3404,27 @@ size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf,
   return 0;
 }
 
+bool ProcessGDBRemote::DoCanAllocateMemory() {
+  // Probe the _M packet. Falling back to mmap() only needs its symbol.
+  if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolCalculate) {
+    addr_t addr = m_gdb_comm.AllocateMemory(8, ePermissionsReadable |
+                                                   ePermissionsWritable |
+                                                   ePermissionsExecutable);
+    if (addr != LLDB_INVALID_ADDRESS)
+      m_gdb_comm.DeallocateMemory(addr);
+  }
+  if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes)
+    return true;
+
+  ModuleFunctionSearchOptions options;
+  options.include_symbols = true;
+  options.include_inlines = false;
+  SymbolContextList sc_list;
+  GetTarget().GetImages().FindFunctions(
+      ConstString("mmap"), eFunctionNameTypeFull, options, sc_list);
+  return !sc_list.IsEmpty();
+}
+
 lldb::addr_t ProcessGDBRemote::DoAllocateMemory(size_t size,
                                                 uint32_t permissions,
                                                 Status &error) {

diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index d23af7f41849f..018d0699ef158 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -167,6 +167,8 @@ class ProcessGDBRemote : public Process,
   lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
                                 Status &error) override;
 
+  bool DoCanAllocateMemory() override;
+
   Status DoDeallocateMemory(lldb::addr_t ptr) override;
 
   // Process STDIO

diff  --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index beb048786fb51..fe58b732a6497 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2758,27 +2758,9 @@ addr_t Process::CallocateMemory(size_t size, uint32_t permissions,
 bool Process::CanJIT() {
   if (m_can_jit == eCanJITDontKnow) {
     Log *log = GetLog(LLDBLog::Process);
-    Status err;
-
-    uint64_t allocated_memory = AllocateMemory(
-        8, ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable,
-        err);
-
-    if (err.Success()) {
-      m_can_jit = eCanJITYes;
-      LLDB_LOGF(log,
-                "Process::%s pid %" PRIu64
-                " allocation test passed, CanJIT () is true",
-                __FUNCTION__, GetID());
-    } else {
-      m_can_jit = eCanJITNo;
-      LLDB_LOGF(log,
-                "Process::%s pid %" PRIu64
-                " allocation test failed, CanJIT () is false: %s",
-                __FUNCTION__, GetID(), err.AsCString());
-    }
-
-    DeallocateMemory(allocated_memory);
+    m_can_jit = DoCanAllocateMemory() ? eCanJITYes : eCanJITNo;
+    LLDB_LOGF(log, "Process::%s pid %" PRIu64 " CanJIT () is %s", __FUNCTION__,
+              GetID(), m_can_jit == eCanJITYes ? "true" : "false");
   }
 
   return m_can_jit == eCanJITYes;

diff  --git a/lldb/test/API/functionalities/gdb_remote_client/TestObjCRuntimeNoInferiorCall.py b/lldb/test/API/functionalities/gdb_remote_client/TestObjCRuntimeNoInferiorCall.py
new file mode 100644
index 0000000000000..9601f57898801
--- /dev/null
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestObjCRuntimeNoInferiorCall.py
@@ -0,0 +1,99 @@
+"""
+Test that creating the Objective-C runtime doesn't run code in the inferior.
+The stub doesn't support _M, so falling back to mmap would.
+"""
+
+import json
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test.gdbclientutils import *
+from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
+
+GPRS = ["x%d" % i for i in range(31)] + ["sp", "pc"]
+
+TARGET_XML = """<?xml version="1.0"?>
+<target version="1.0">
+  <architecture>aarch64</architecture>
+  <feature name="org.gnu.gdb.aarch64.core">
+%s
+    <reg name="cpsr" bitsize="32"/>
+  </feature>
+</target>""" % "\n".join(
+    '    <reg name="%s" bitsize="64"/>' % r for r in GPRS
+)
+
+
+class MyResponder(MockGDBServerResponder):
+    def __init__(self, objc_path):
+        MockGDBServerResponder.__init__(self)
+        self.objc_path = objc_path
+
+    def qHostInfo(self):
+        return "cputype:16777228;cpusubtype:0;ostype:macosx;vendor:apple;os_version:14.0;endian:little;ptrsize:8;"
+
+    def qProcessInfo(self):
+        return "pid:1;cputype:100000c;cpusubtype:0;ostype:macosx;vendor:apple;endian:little;ptrsize:8;"
+
+    def qfThreadInfo(self):
+        return "m1"
+
+    def haltReason(self):
+        return "T02thread:1;"
+
+    def qXferRead(self, obj, annex, offset, length):
+        if annex == "target.xml":
+            return TARGET_XML, False
+        return None, False
+
+    def readRegister(self, regnum):
+        return "E01"
+
+    def readRegisters(self):
+        regs = {"sp": 0x16FDFF000, "pc": 0x1000002F0}
+        gprs = "".join(regs.get(r, 0).to_bytes(8, "little").hex() for r in GPRS)
+        return gprs + "00000000"
+
+    def jGetLoadedDynamicLibrariesInfos(self, packet):
+        if "fetch_all_solibs" not in packet:
+            return "OK"
+        image = {
+            "load_address": 0x100000000,
+            "mod_date": 0,
+            "pathname": self.objc_path,
+            "uuid": "33E94484-A695-3E4B-9C53-C826762C99F2",
+            "mach_header": {
+                "magic": 0xFEEDFACF,
+                "cputype": 0x100000C,
+                "cpusubtype": 0,
+                "filetype": 2,
+                "flags": 5,
+            },
+            "segments": [
+                {
+                    "name": "__TEXT",
+                    "vmaddr": 0x100000000,
+                    "vmsize": 0x4000,
+                    "fileoff": 0,
+                    "filesize": 0x4000,
+                    "maxprot": 5,
+                }
+            ],
+        }
+        return escape_binary(json.dumps({"images": [image]}))
+
+
+class TestObjCRuntimeNoInferiorCall(GDBRemoteTestBase):
+    @requireNotWasm("exercises the Darwin dynamic loader")
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    @skipIfLLVMTargetMissing("AArch64")
+    def test(self):
+        target = self.createTarget("libobjc.A.dylib.yaml")
+        self.server.responder = MyResponder(target.GetExecutable().fullpath)
+        self.connect(target)
+
+        received = self.server.responder.packetLog.get_received()
+        self.assertEqual(
+            [p for p in received if p == "c" or p.startswith("vCont;")], []
+        )

diff  --git a/lldb/test/API/functionalities/gdb_remote_client/libobjc.A.dylib.yaml b/lldb/test/API/functionalities/gdb_remote_client/libobjc.A.dylib.yaml
new file mode 100644
index 0000000000000..0d37a392c576b
--- /dev/null
+++ b/lldb/test/API/functionalities/gdb_remote_client/libobjc.A.dylib.yaml
@@ -0,0 +1,106 @@
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x0
+  filetype:        0x2
+  ncmds:           7
+  sizeofcmds:      392
+  flags:           0x5
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __PAGEZERO
+    vmaddr:          0
+    vmsize:          4294967296
+    fileoff:         0
+    filesize:        0
+    maxprot:         0
+    initprot:        0
+    nsects:          0
+    flags:           0
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         152
+    segname:         __TEXT
+    vmaddr:          4294967296
+    vmsize:          16384
+    fileoff:         0
+    filesize:        16384
+    maxprot:         5
+    initprot:        5
+    nsects:          1
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x1000002E8
+        size:            16
+        offset:          0x2E8
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         000080D2C0035FD600008052C0035FD6
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          4294983680
+    vmsize:          16384
+    fileoff:         16384
+    filesize:        88
+    maxprot:         1
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          16384
+    nsyms:           3
+    stroff:          16432
+    strsize:         40
+  - cmd:             LC_UUID
+    cmdsize:         24
+    uuid:            33E94484-A695-3E4B-9C53-C826762C99F2
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         24
+    platform:        1
+    minos:           917504
+    sdk:             917504
+    ntools:          0
+  - cmd:             LC_MAIN
+    cmdsize:         24
+    entryoff:        752
+    stacksize:       0
+LinkEditData:
+  NameList:
+    - n_strx:          2
+      n_type:          0x3
+      n_sect:          1
+      n_desc:          16
+      n_value:         4294967296
+    - n_strx:          22
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968048
+    - n_strx:          28
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968040
+  StringTable:
+    - ' '
+    - __mh_execute_header
+    - _main
+    - _mmap
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+...


        


More information about the lldb-commits mailing list