[lldb-dap][Windows] Respect debug-heap setting when launching (#212290)

In #212126, a setting was added to control the heap used when debugging
on Windows. By default, we disable the debug-heap with
`_NO_DEBUG_HEAP=1`. When launching a program from lldb-dap with
`integratedTerminal` or `externalTerminal`, we need to tell the client
about that variable.

This adds the variable in the runInTerminal reverse request if needed.

Closes #201690.
This commit is contained in:
Nerixyz 2026-07-28 17:57:29 +02:00 committed by GitHub
parent ec1015a982
commit 2db6978f72
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 91 additions and 3 deletions

View file

@ -452,6 +452,11 @@ class _LocalProcess(_BaseProcess):
self._trace_on = trace_on
self._delayafterterminate = 0.1
@property
def args(self):
assert self._proc is not None, "No process"
return self._proc.args
@property
def pid(self):
assert self._proc is not None, "No process"
@ -534,8 +539,13 @@ class _LocalProcess(_BaseProcess):
class _RemoteProcess(_BaseProcess):
def __init__(self, install_remote):
self._pid = None
self._args = None
self._install_remote = install_remote
@property
def args(self):
assert self._args
@property
def pid(self):
return self._pid
@ -577,6 +587,7 @@ class _RemoteProcess(_BaseProcess):
"remote_platform.Launch('%s', '%s') failed: %s" % (dst_path, args, err)
)
self._pid = launch_info.GetProcessID()
self._args = args
def terminate(self):
lldb.remote_platform.Kill(self._pid)

View file

@ -448,7 +448,7 @@ class Session:
def verify_reverse_process_exited(self, exit_code: Optional[int] = None):
if process := self._reverse_process:
proc_exit_code = process.poll()
proc_exit_code = process.wait(timeout=1.0)
if proc_exit_code is None:
raise DAPError(
f"process is still running, "

View file

@ -0,0 +1,63 @@
"""
Test lldb-dap launch request.
"""
from lldbsuite.test.decorators import skipUnlessWindows, skipIfBuildType
from lldbsuite.test.tools.lldb_dap.types import LaunchArgs, Console
from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
from typing import List
@skipIfBuildType(["debug"])
@skipUnlessWindows
class TestDAP_launch_win_debug_heap(DAPTestCaseBase):
"""
Test that lldb-dap respects the debug heap setting on Windows when launching in an integrated terminal.
"""
def run_with(self, *, env: List[str] = [], init_commands: List[str] = []):
program = self.getBuildArtifact("a.out")
session = self.build_and_create_session()
process_event = session.launch(
LaunchArgs(
program=program,
env=env,
initCommands=init_commands,
console=Console.INTEGRATED_TERMINAL,
)
)
session.verify_process_exited(after=process_event)
output = session.get_stdout()
self.assertTrue(output, "expect program output")
return "\n".join(l for l in output.splitlines() if l.startswith("env["))
def test_default_overwrite(self):
env_output = self.run_with(env=["_NO_DEBUG_HEAP=2"])
self.assertIn("_NO_DEBUG_HEAP=2", env_output)
def test_enabled(self):
env_output = self.run_with(
init_commands=[
"settings set platform.plugin.windows.disable-debug-heap true"
],
)
self.assertIn("_NO_DEBUG_HEAP=1", env_output)
def test_disabled(self):
env_output = self.run_with(
init_commands=[
"settings set platform.plugin.windows.disable-debug-heap false"
]
)
self.assertNotIn("_NO_DEBUG_HEAP", env_output)
def test_disabled_overwrite(self):
env_output = self.run_with(
env=["_NO_DEBUG_HEAP=2"],
init_commands=[
"settings set platform.plugin.windows.disable-debug-heap false"
],
)
self.assertIn("_NO_DEBUG_HEAP=2", env_output)

View file

@ -130,6 +130,8 @@ class TestDAP_runInTerminal(lldbdap_testcase.DAPTestCaseBase):
self.assertIn(program, request["arguments"]["args"])
self.assertIn("foobar", request["arguments"]["args"])
self.assertIn("FOO", request["arguments"]["env"])
if sys.platform == "win32":
self.assertIn("_NO_DEBUG_HEAP", request["arguments"]["env"])
breakpoint_line = line_number(source, "// breakpoint")
@ -151,6 +153,10 @@ class TestDAP_runInTerminal(lldbdap_testcase.DAPTestCaseBase):
env = self.dap_server.request_evaluate("foo")["body"]["result"]
self.assertIn("bar", env)
if sys.platform == "win32":
env = self.dap_server.request_evaluate("nodebugheap")["body"]["result"]
self.assertIn('"1"', env)
self.continue_to_exit()
@skipIfAsan

View file

@ -8,6 +8,7 @@
int main(int argc, char *argv[]) {
const char *foo = getenv("FOO");
const char *nodebugheap = getenv("_NO_DEBUG_HEAP");
int counter = 1;
return 0; // breakpoint

View file

@ -96,6 +96,13 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
return llvm::make_error<DAPError>(
"program must be set to when using runInTerminal");
llvm::StringMap<protocol::String> env = arguments.env;
#ifdef _WIN32
if (dap.debugger.GetSetting("platform.plugin.windows.disable-debug-heap")
.GetBooleanValue(true))
env.try_emplace("_NO_DEBUG_HEAP", "1");
#endif
dap.is_attach = true;
lldb::SBAttachInfo attach_info;
@ -113,8 +120,8 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
#endif
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
arguments.configuration.program, arguments.args, arguments.env,
arguments.cwd, comm_file->GetPath(), debugger_pid, arguments.stdio,
arguments.configuration.program, arguments.args, env, arguments.cwd,
comm_file->GetPath(), debugger_pid, arguments.stdio,
arguments.console == protocol::eConsoleExternalTerminal);
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
std::move(reverse_request));