[lldb] [llvm] [lldb] Run the LLDB test suite under MTE on capable Apple HW (PR #185780)

Jonas Devlieghere via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 10 20:00:49 PDT 2026


https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/185780

>From bcf7a93795f62e64ba5db148fd413c1ac0c8f18b Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 10 Mar 2026 15:07:18 -0700
Subject: [PATCH 1/2] [lldb] Add darwin-mte-launcher

---
 lldb/tools/CMakeLists.txt                     |  1 +
 lldb/tools/darwin-mte-launch/CMakeLists.txt   |  6 ++
 .../darwin-mte-launch/darwin-mte-launch.cpp   | 74 +++++++++++++++++++
 3 files changed, 81 insertions(+)
 create mode 100644 lldb/tools/darwin-mte-launch/CMakeLists.txt
 create mode 100644 lldb/tools/darwin-mte-launch/darwin-mte-launch.cpp

diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt
index 4b54c1a50eb2f..7376c30958e06 100644
--- a/lldb/tools/CMakeLists.txt
+++ b/lldb/tools/CMakeLists.txt
@@ -20,6 +20,7 @@ endif()
 
 if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   add_lldb_tool_subdirectory(darwin-debug)
+  add_lldb_tool_subdirectory(darwin-mte-launch)
   if(NOT LLDB_USE_SYSTEM_DEBUGSERVER)
     add_lldb_tool_subdirectory(debugserver)
   endif()
diff --git a/lldb/tools/darwin-mte-launch/CMakeLists.txt b/lldb/tools/darwin-mte-launch/CMakeLists.txt
new file mode 100644
index 0000000000000..95212d7cbbb2f
--- /dev/null
+++ b/lldb/tools/darwin-mte-launch/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_lldb_tool(darwin-mte-launch
+  darwin-mte-launch.cpp
+
+  LINK_COMPONENTS
+    Support
+)
diff --git a/lldb/tools/darwin-mte-launch/darwin-mte-launch.cpp b/lldb/tools/darwin-mte-launch/darwin-mte-launch.cpp
new file mode 100644
index 0000000000000..f5f7f74279864
--- /dev/null
+++ b/lldb/tools/darwin-mte-launch/darwin-mte-launch.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/WithColor.h"
+#include <dlfcn.h>
+#include <spawn.h>
+#include <string.h>
+#include <vector>
+
+using namespace llvm;
+
+int main(int argc, const char *argv[], const char *envp[]) {
+  const char *program = argv[1];
+
+  posix_spawnattr_t attr;
+  int ret = posix_spawnattr_init(&attr);
+  if (ret != 0) {
+    WithColor::error() << "posix_spawnattr_init failed\n";
+    return EXIT_FAILURE;
+  }
+
+  typedef int (*posix_spawnattr_set_use_sec_transition_shims_np_t)(
+      posix_spawnattr_t *attr, uint32_t flags);
+  posix_spawnattr_set_use_sec_transition_shims_np_t
+      posix_spawnattr_set_use_sec_transition_shims_np_fn =
+          (posix_spawnattr_set_use_sec_transition_shims_np_t)dlsym(
+              RTLD_DEFAULT, "posix_spawnattr_set_use_sec_transition_shims_np");
+
+  if (!posix_spawnattr_set_use_sec_transition_shims_np_fn) {
+    WithColor::error()
+        << "posix_spawnattr_set_use_sec_transition_shims_np not available\n";
+    return EXIT_FAILURE;
+  }
+
+  ret = posix_spawnattr_set_use_sec_transition_shims_np_fn(&attr, /*unused=*/0);
+  if (ret != 0) {
+    WithColor::error()
+        << "posix_spawnattr_set_use_sec_transition_shims_np failed\n";
+    return EXIT_FAILURE;
+  }
+
+  std::vector<char *> new_args;
+  for (int i = 1; i < argc; ++i)
+    new_args.push_back(const_cast<char *>(argv[i]));
+  new_args.push_back(nullptr);
+
+  std::vector<char *> new_envp;
+  for (const char **e = envp; *e; ++e)
+    new_envp.push_back(const_cast<char *>(*e));
+  new_envp.push_back(const_cast<char *>("PYTHONMALLOC=malloc"));
+  new_envp.push_back(nullptr);
+
+  pid_t pid;
+  ret =
+      posix_spawn(&pid, program, NULL, &attr, new_args.data(), new_envp.data());
+  if (ret != 0) {
+    WithColor::error() << "posix_spawn() failed with error " << ret << "("
+                       << strerror(ret) << ")\n";
+    return EXIT_FAILURE;
+  }
+
+  int status;
+  if (waitpid(pid, &status, 0) == -1) {
+    WithColor::error() << "waitpid failed\n";
+    return EXIT_FAILURE;
+  }
+
+  return WEXITSTATUS(status);
+}

>From fad625190ddb90ebf498fe68d1360508feb65478 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 10 Mar 2026 17:07:34 -0700
Subject: [PATCH 2/2] [lldb] Run tests under MTE on capable HW

---
 lldb/cmake/modules/LLDBConfig.cmake | 24 ++++++++++++++++++++++++
 lldb/test/API/lit.site.cfg.py.in    |  1 +
 lldb/test/API/lldbtest.py           |  4 ++++
 lldb/test/CMakeLists.txt            |  5 +++++
 lldb/test/Shell/helper/toolchain.py |  4 ++++
 lldb/test/Shell/lit.site.cfg.py.in  |  1 +
 lldb/tools/CMakeLists.txt           |  4 +++-
 llvm/utils/lit/lit/llvm/subst.py    |  4 ++++
 8 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index 42af86b57cfcc..89989b2881b42 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -163,6 +163,30 @@ if (LLDB_ENABLE_LIBEDIT)
   set(CMAKE_EXTRA_INCLUDE_FILES)
 endif()
 
+if (APPLE)
+  set(default_enable_mte OFF)
+
+  # Default to ON on capable hardware when assertions are enabled.
+  if (LLVM_ENABLE_ASSERTIONS)
+    execute_process(
+        COMMAND sysctl -n hw.optional.arm.FEAT_MTE4
+        OUTPUT_VARIABLE SYSCTL_OUTPUT
+        ERROR_QUIET
+        RESULT_VARIABLE SYSCTL_RESULT
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+    if(SYSCTL_RESULT EQUAL 0)
+      set(default_enable_mte ON)
+    endif()
+  endif()
+
+  option(LLDB_ENABLE_MTE "Run the LLDB test suite with MTE enabled." ${default_enable_mte})
+
+  if (LLDB_ENABLE_MTE)
+    message(STATUS "Running the LLDB test suite with MTE")
+  endif()
+endif()
+
 if (LLDB_ENABLE_PYTHON)
   if(CMAKE_SYSTEM_NAME MATCHES "Windows")
     set(default_embed_python_home ON)
diff --git a/lldb/test/API/lit.site.cfg.py.in b/lldb/test/API/lit.site.cfg.py.in
index c4e4352fe7915..6cc4542bca75e 100644
--- a/lldb/test/API/lit.site.cfg.py.in
+++ b/lldb/test/API/lit.site.cfg.py.in
@@ -42,6 +42,7 @@ config.has_libcxx = @LLDB_HAS_LIBCXX@
 config.libcxx_libs_dir = "@LIBCXX_LIBRARY_DIR@"
 config.libcxx_include_dir = "@LIBCXX_GENERATED_INCLUDE_DIR@"
 config.libcxx_include_target_dir = "@LIBCXX_GENERATED_INCLUDE_TARGET_DIR@"
+config.lldb_launcher = "@LLDB_LAUNCHER@"
 # The API tests use their own module caches.
 config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-api")
 config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-api")
diff --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py
index d6b79ebc2c434..f586a34f9e95f 100644
--- a/lldb/test/API/lldbtest.py
+++ b/lldb/test/API/lldbtest.py
@@ -55,6 +55,10 @@ def execute(self, test, litConfig):
         # python exe as the first parameter of the command.
         cmd = [executable] + self.dotest_cmd + [testPath, "-p", testFile]
 
+        launcher = getattr(test.config, "lldb_launcher", None)
+        if launcher:
+            cmd = [launcher] + cmd
+
         if isLuaTest:
             cmd.extend(["--env", "LUA_EXECUTABLE=%s" % test.config.lua_executable])
             cmd.extend(["--env", "LLDB_LUA_CPATH=%s" % test.config.lldb_lua_cpath])
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index 513d1ec493ee1..8504c7d55e905 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -132,6 +132,11 @@ if(TARGET lldb-framework)
   add_lldb_test_dependency(lldb-framework)
 endif()
 
+if(TARGET darwin-mte-launch)
+  add_lldb_test_dependency(darwin-mte-launch)
+  set(LLDB_LAUNCHER ${LLVM_RUNTIME_OUTPUT_INTDIR}/darwin-mte-launch${CMAKE_EXECUTABLE_SUFFIX})
+endif()
+
 if (LLDB_CAN_USE_LLDB_RPC_SERVER)
   add_lldb_test_dependency(lldb-rpc-generate-sources)
 endif()
diff --git a/lldb/test/Shell/helper/toolchain.py b/lldb/test/Shell/helper/toolchain.py
index 66664561a249d..df20a4ae7af5e 100644
--- a/lldb/test/Shell/helper/toolchain.py
+++ b/lldb/test/Shell/helper/toolchain.py
@@ -118,24 +118,28 @@ def use_lldb_substitutions(config):
         build_script_args.append("--sysroot={0}".format(config.cmake_sysroot))
 
     lldb_init = _get_lldb_init_path(config)
+    launcher = getattr(config, "lldb_launcher", None)
 
     primary_tools = [
         ToolSubst(
             "%lldb",
             command=FindTool("lldb"),
             extra_args=get_lldb_args(config),
+            launcher=launcher,
             unresolved="fatal",
         ),
         ToolSubst(
             "%lldb-init",
             command=FindTool("lldb"),
             extra_args=["-S", lldb_init],
+            launcher=launcher,
             unresolved="fatal",
         ),
         ToolSubst(
             "%lldb-noinit",
             command=FindTool("lldb"),
             extra_args=["--no-lldbinit"],
+            launcher=launcher,
             unresolved="fatal",
         ),
         ToolSubst(
diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in
index 47beac002a19c..b260b2fce90b7 100644
--- a/lldb/test/Shell/lit.site.cfg.py.in
+++ b/lldb/test/Shell/lit.site.cfg.py.in
@@ -35,6 +35,7 @@ config.lldb_system_debugserver = @LLDB_USE_SYSTEM_DEBUGSERVER@
 config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
 config.lldb_has_lldbrpc = @LLDB_BUILD_LLDBRPC@
 config.have_dia_sdk = @LLVM_ENABLE_DIA_SDK@
+config.lldb_launcher = "@LLDB_LAUNCHER@"
 # The shell tests use their own module caches.
 config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-shell")
 config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-shell")
diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt
index 7376c30958e06..6d49b83eb6874 100644
--- a/lldb/tools/CMakeLists.txt
+++ b/lldb/tools/CMakeLists.txt
@@ -20,7 +20,9 @@ endif()
 
 if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   add_lldb_tool_subdirectory(darwin-debug)
-  add_lldb_tool_subdirectory(darwin-mte-launch)
+  if (LLDB_ENABLE_MTE)
+    add_lldb_tool_subdirectory(darwin-mte-launch)
+  endif()
   if(NOT LLDB_USE_SYSTEM_DEBUGSERVER)
     add_lldb_tool_subdirectory(debugserver)
   endif()
diff --git a/llvm/utils/lit/lit/llvm/subst.py b/llvm/utils/lit/lit/llvm/subst.py
index 09ab3555a6b44..39a6a75e4c79b 100644
--- a/llvm/utils/lit/lit/llvm/subst.py
+++ b/llvm/utils/lit/lit/llvm/subst.py
@@ -44,6 +44,7 @@ def __init__(
         verbatim=False,
         unresolved="warn",
         extra_args=None,
+        launcher=None,
     ):
         """Construct a ToolSubst.
 
@@ -79,6 +80,7 @@ def __init__(
         """
         self.unresolved = unresolved
         self.extra_args = extra_args
+        self.launcher = launcher
         self.key = key
         self.command = command if command is not None else FindTool(key)
         self.was_resolved = False
@@ -120,6 +122,8 @@ def resolve(self, config, search_dirs):
         if command_str:
             if self.extra_args:
                 command_str = " ".join([command_str] + self.extra_args)
+            if self.launcher:
+                command_str = self.launcher + " " + command_str
         else:
             if self.unresolved == "warn":
                 # Warn, but still provide a substitution.



More information about the llvm-commits mailing list