[Lldb-commits] [lldb] [lldb][Windows] Disable debug heap by default (PR #212126)
via lldb-commits
lldb-commits at lists.llvm.org
Sun Jul 26 08:04:31 PDT 2026
https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/212126
This disables Windows' default debug heap when launching a process.
The motivation is similar to what Microsoft wrote on their [blog post for Visual Studio 2015](https://devblogs.microsoft.com/cppblog/c-debugging-improvements-in-visual-studio-14/) where they disabled it: The debug heap comes with a performance cost and the [C runtime already does some heap checking](https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-debug-heap-details?view=msvc-170).
Towards #201690. Notably, lldb-dap won't set this when launching in a terminal. I think we'd want an option similar to `disableASLR` for lldb-dap.
>From 6c09df20fe3b742e31c14b9756046c57a138f626 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Sun, 26 Jul 2026 14:33:07 +0200
Subject: [PATCH] [lldb][Windows] Disable debug heap by default
---
lldb/include/lldb/Utility/Environment.h | 1 +
.../Plugins/Platform/Windows/CMakeLists.txt | 16 +++++++
.../Platform/Windows/PlatformWindows.cpp | 46 +++++++++++++++++-
.../Platform/Windows/PlatformWindows.h | 2 +
.../Windows/PlatformWindowsProperties.td | 10 ++++
lldb/test/API/windows/debug-heap/Makefile | 3 ++
.../debug-heap/TestWindowsDebugHeap.py | 47 +++++++++++++++++++
lldb/test/API/windows/debug-heap/main.c | 10 ++++
8 files changed, 134 insertions(+), 1 deletion(-)
create mode 100644 lldb/source/Plugins/Platform/Windows/PlatformWindowsProperties.td
create mode 100644 lldb/test/API/windows/debug-heap/Makefile
create mode 100644 lldb/test/API/windows/debug-heap/TestWindowsDebugHeap.py
create mode 100644 lldb/test/API/windows/debug-heap/main.c
diff --git a/lldb/include/lldb/Utility/Environment.h b/lldb/include/lldb/Utility/Environment.h
index 27d740402c30c..b0ef773da2cfe 100644
--- a/lldb/include/lldb/Utility/Environment.h
+++ b/lldb/include/lldb/Utility/Environment.h
@@ -44,6 +44,7 @@ class Environment : private llvm::StringMap<std::string> {
using Base::begin;
using Base::clear;
+ using Base::contains;
using Base::count;
using Base::empty;
using Base::end;
diff --git a/lldb/source/Plugins/Platform/Windows/CMakeLists.txt b/lldb/source/Plugins/Platform/Windows/CMakeLists.txt
index 7f00425224910..6559f1f9cb520 100644
--- a/lldb/source/Plugins/Platform/Windows/CMakeLists.txt
+++ b/lldb/source/Plugins/Platform/Windows/CMakeLists.txt
@@ -1,3 +1,15 @@
+lldb_tablegen(PlatformWindowsProperties.inc -gen-lldb-property-defs
+ SOURCE PlatformWindowsProperties.td
+ TARGET LLDBPluginPlatformWindowsPropertiesGen)
+
+lldb_tablegen(PlatformWindowsPropertiesEnum.inc -gen-lldb-property-enum-defs
+ SOURCE PlatformWindowsProperties.td
+ TARGET LLDBPluginPlatformWindowsPropertiesEnumGen)
+
+lldb_tablegen(PlatformWindowsProperties.json -dump-json
+ SOURCE PlatformWindowsProperties.td
+ TARGET LLDBPluginPlatformWindowsPropertiesJsonGen)
+
add_lldb_library(lldbPluginPlatformWindows PLUGIN
PlatformWindows.cpp
@@ -10,3 +22,7 @@ add_lldb_library(lldbPluginPlatformWindows PLUGIN
lldbTarget
lldbPluginPlatformGDB
)
+
+add_dependencies(lldbPluginPlatformWindows
+ LLDBPluginPlatformWindowsPropertiesGen
+ LLDBPluginPlatformWindowsPropertiesEnumGen)
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
index e7c590312b090..fdf6983801ae5 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
@@ -45,6 +45,35 @@ LLDB_PLUGIN_DEFINE(PlatformWindows)
static uint32_t g_initialize_count = 0;
+namespace {
+
+#define LLDB_PROPERTIES_windows
+#include "PlatformWindowsProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_windows
+#include "PlatformWindowsPropertiesEnum.inc"
+};
+
+class PluginProperties : public Properties {
+public:
+ PluginProperties() {
+ m_collection_sp = std::make_shared<OptionValueProperties>("windows");
+ m_collection_sp->Initialize(g_windows_properties_def);
+ }
+
+ bool DisableDebugHeap() const {
+ return GetPropertyAtIndexAs<bool>(ePropertyDisableDebugHeap, true);
+ }
+};
+
+static PluginProperties &GetGlobalProperties() {
+ static PluginProperties g_settings;
+ return g_settings;
+}
+
+} // end of anonymous namespace
+
PlatformSP PlatformWindows::CreateInstance(bool force,
const lldb_private::ArchSpec *arch) {
// The only time we create an instance is when we are creating a remote
@@ -92,6 +121,15 @@ llvm::StringRef PlatformWindows::GetPluginDescriptionStatic(bool is_host) {
: "Remote Windows user platform plug-in.";
}
+void PlatformWindows::DebuggerInitialize(Debugger &debugger) {
+ if (!PluginManager::GetSettingForPlatformPlugin(debugger, "windows")) {
+ PluginManager::CreateSettingForPlatformPlugin(
+ debugger, GetGlobalProperties().GetValueProperties(),
+ "Properties for the Windows platform plugin.",
+ /*is_global_property=*/true);
+ }
+}
+
void PlatformWindows::Initialize() {
Platform::Initialize();
@@ -105,7 +143,7 @@ void PlatformWindows::Initialize() {
PluginManager::RegisterPlugin(
PlatformWindows::GetPluginNameStatic(false),
PlatformWindows::GetPluginDescriptionStatic(false),
- PlatformWindows::CreateInstance);
+ PlatformWindows::CreateInstance, PlatformWindows::DebuggerInitialize);
}
}
@@ -559,6 +597,12 @@ ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info,
return Attach(attach_info, debugger, &target, error);
}
+ Environment &env = launch_info.GetEnvironment();
+ if (GetGlobalProperties().DisableDebugHeap() &&
+ !env.contains("_NO_DEBUG_HEAP")) {
+ env.try_emplace("_NO_DEBUG_HEAP", "1");
+ }
+
ProcessSP process_sp =
target.CreateProcess(launch_info.GetListener(),
launch_info.GetProcessPluginName(), nullptr, false);
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
index 771133f341e90..dff3113686c39 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
@@ -31,6 +31,8 @@ class PlatformWindows : public RemoteAwarePlatform {
static llvm::StringRef GetPluginDescriptionStatic(bool is_host);
+ static void DebuggerInitialize(Debugger &debugger);
+
llvm::StringRef GetPluginName() override {
return GetPluginNameStatic(IsHost());
}
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindowsProperties.td b/lldb/source/Plugins/Platform/Windows/PlatformWindowsProperties.td
new file mode 100644
index 0000000000000..dd34ce40bcde7
--- /dev/null
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindowsProperties.td
@@ -0,0 +1,10 @@
+include "../../../../include/lldb/Core/PropertiesBase.td"
+
+let Definition = "windows", Path = "platform.plugin.windows" in {
+ def DisableDebugHeap: Property<"disable-debug-heap", "Boolean">,
+ Global,
+ DefaultTrue,
+ Desc<"Specifies that the debug heap should not be used for debugging. "
+ "The Windows debug heap has additional checks for heap related bugs at the cost of a noticeable performance penalty. "
+ "By enabling this setting, _NO_DEBUG_HEAP=1 will be added to the environment.">;
+}
diff --git a/lldb/test/API/windows/debug-heap/Makefile b/lldb/test/API/windows/debug-heap/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/windows/debug-heap/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/windows/debug-heap/TestWindowsDebugHeap.py b/lldb/test/API/windows/debug-heap/TestWindowsDebugHeap.py
new file mode 100644
index 0000000000000..703eeb5ec9696
--- /dev/null
+++ b/lldb/test/API/windows/debug-heap/TestWindowsDebugHeap.py
@@ -0,0 +1,47 @@
+"""
+Test that LLDB disables the debug heap on Windows.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from typing import List
+
+
+ at skipUnlessWindows
+class DebugHeapTestCase(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def tearDown(self):
+ self.runCmd("settings clear platform.plugin.windows.disable-debug-heap")
+ return super().tearDown()
+
+ def _run_to_exit(self, envp: List[str]=[]):
+ self.build()
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(target, VALID_TARGET)
+ self.dbg.SetAsync(False)
+ process = target.LaunchSimple([], envp, self.get_process_working_directory())
+ self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
+ self.assertState(process.GetState(), lldb.eStateExited)
+ return process.GetSTDOUT(256)
+
+ def test_default(self):
+ output = self._run_to_exit()
+ self.assertIn("_NO_DEBUG_HEAP=1", output)
+ output = self._run_to_exit(["_NO_DEBUG_HEAP=2"])
+ self.assertIn("_NO_DEBUG_HEAP=2", output)
+
+ def test_disabled(self):
+ self.runCmd("settings set platform.plugin.windows.disable-debug-heap false")
+ output = self._run_to_exit()
+ self.assertNotIn("_NO_DEBUG_HEAP", output)
+ output = self._run_to_exit(["_NO_DEBUG_HEAP=2"])
+ self.assertIn("_NO_DEBUG_HEAP=2", output)
+
+ def test_enabled(self):
+ self.runCmd("settings set platform.plugin.windows.disable-debug-heap true")
+ output = self._run_to_exit()
+ self.assertIn("_NO_DEBUG_HEAP=1", output)
+ output = self._run_to_exit(["_NO_DEBUG_HEAP=2"])
+ self.assertIn("_NO_DEBUG_HEAP=2", output)
diff --git a/lldb/test/API/windows/debug-heap/main.c b/lldb/test/API/windows/debug-heap/main.c
new file mode 100644
index 0000000000000..e86991bba4902
--- /dev/null
+++ b/lldb/test/API/windows/debug-heap/main.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv, char **envp) {
+ for (char **p = envp; *p; ++p) {
+ if (strstr(*p, "_NO_DEBUG_HEAP=") == *p)
+ printf("%s\n", *p);
+ }
+ return 0;
+}
More information about the lldb-commits
mailing list