[Lldb-commits] [lldb] [lldb][test][Windows] Test attaching to a process past MAX_PATH (PR #229396)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Tue Oct 6 05:34:01 PDT 2026
https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/229396
This patch adds a test to attempt attaching to a process past MAX_PATH
Spawn the longpath test program from a path longer than MAX_PATH, attach to it by pid from an empty target, and check that the target has a known architecture, frame 0 is in a module and the executable is loaded.
This is the lldb-server attach path that asserted in `RegisterContextWindows_x86_64` when Host::GetProcessInfo cannot not open the image.
>From 9f8cb3a80844e30b9d71200ab83a44831ee4f23c Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Tue, 6 Oct 2026 13:31:39 +0100
Subject: [PATCH] [lldb][test][Windows] Test attaching to a process past
MAX_PATH
---
.../functionalities/longpath/TestLongPath.py | 57 ++++++++++++++++---
lldb/test/API/functionalities/longpath/main.c | 13 +++++
2 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/lldb/test/API/functionalities/longpath/TestLongPath.py b/lldb/test/API/functionalities/longpath/TestLongPath.py
index 62e2b866fe49bb0..f3aafcf5628994c 100644
--- a/lldb/test/API/functionalities/longpath/TestLongPath.py
+++ b/lldb/test/API/functionalities/longpath/TestLongPath.py
@@ -5,6 +5,7 @@
import os
import shutil
+import subprocess
import lldb
from lldbsuite.test.decorators import *
@@ -47,9 +48,9 @@ def _find_module(self, target, long_exe):
return mod
return lldb.SBModule()
- def test_target_with_long_path(self):
- """CreateTarget, launch and break in an executable located past
- MAX_PATH, and verify the full path is preserved (not truncated)."""
+ def _copy_exe_to_long_dir(self):
+ """Build the test program, copy it into a directory whose path exceeds
+ MAX_PATH and return the path of the copy."""
self.build()
src_exe = self.getBuildArtifact("a.out")
@@ -57,16 +58,21 @@ def test_target_with_long_path(self):
if long_dir is None:
self.skipTest("OS cannot create paths longer than MAX_PATH")
- exe_basename = os.path.basename(src_exe)
- long_exe = os.path.join(long_dir, exe_basename)
+ long_exe = os.path.join(long_dir, os.path.basename(src_exe))
shutil.copyfile(src_exe, self._long_path(long_exe))
- long_exe_abs = os.path.abspath(long_exe)
self.assertGreater(
- len(long_exe_abs),
+ len(os.path.abspath(long_exe)),
MAX_PATH,
"the test executable path must exceed MAX_PATH to be meaningful",
)
+ return long_exe
+
+ def test_target_with_long_path(self):
+ """CreateTarget, launch and break in an executable located past
+ MAX_PATH, and verify the full path is preserved (not truncated)."""
+ long_exe = self._copy_exe_to_long_dir()
+ exe_basename = os.path.basename(long_exe)
# Creating the target has to open and parse the file at the long path.
target = self.dbg.CreateTarget(long_exe)
@@ -107,3 +113,40 @@ def test_target_with_long_path(self):
process.Continue()
self.assertState(process.GetState(), lldb.eStateExited)
self.assertEqual(process.GetExitStatus(), 0)
+
+ def test_attach_with_long_path(self):
+ """Attach by pid to a process whose executable is located past
+ MAX_PATH, and verify lldb determines its architecture and stops it."""
+ long_exe = self._copy_exe_to_long_dir()
+
+ token = self.getBuildArtifact("token")
+ # Pass the "\\?\" form so CreateProcessW accepts a path past MAX_PATH.
+ popen = subprocess.Popen(
+ [long_exe, token], executable=self._long_path(long_exe)
+ )
+ self.addTearDownHook(popen.kill)
+ lldbutil.wait_for_file_on_target(self, token)
+
+ # Start from an empty target so the architecture has to come from the
+ # process.
+ target = self.dbg.CreateTarget("")
+ error = lldb.SBError()
+ process = target.AttachToProcessWithID(self.dbg.GetListener(), popen.pid, error)
+ self.assertSuccess(error)
+ self.assertTrue(process.IsValid(), PROCESS_IS_VALID)
+ self.assertState(process.GetState(), lldb.eStateStopped)
+
+ triple = target.GetTriple()
+ self.assertTrue(triple, "target has a triple")
+ self.assertNotEqual(triple.split("-")[0], "unknown", "target arch is known")
+ # This reads the image file through Host::GetProcessInfo in lldb.
+ self.assertTrue(
+ process.GetProcessInfo().GetTriple(), "process info has a triple"
+ )
+
+ self.assertGreater(process.GetNumThreads(), 0, "process has threads")
+ frame = process.GetSelectedThread().GetFrameAtIndex(0)
+ self.assertTrue(frame.GetModule().IsValid(), "frame 0 is in a module")
+
+ exe_module = target.FindModule(lldb.SBFileSpec(os.path.basename(long_exe)))
+ self.assertTrue(exe_module.IsValid(), "the executable module is loaded")
diff --git a/lldb/test/API/functionalities/longpath/main.c b/lldb/test/API/functionalities/longpath/main.c
index 9ba28de2ae01cc0..c54a50c3221c12c 100644
--- a/lldb/test/API/functionalities/longpath/main.c
+++ b/lldb/test/API/functionalities/longpath/main.c
@@ -1,3 +1,16 @@
+#include <stdio.h>
+#include <windows.h>
+
int main(int argc, char **argv) {
+ if (argc > 1) {
+ // Create the synchronization token, then wait to be attached.
+ FILE *f = fopen(argv[1], "w");
+ if (!f)
+ return 1;
+ fputs("\n", f);
+ fclose(f);
+ while (1)
+ Sleep(1000);
+ }
return 0; // break here
}
More information about the lldb-commits
mailing list