fix(windows): use extended paths in Python bootstraps - #4071
Conversation
Implicit long-path support is not universal across the Win32 API. The documented set of APIs covered by the long-path opt-in does not include DLL loading functions, e.g., LoadLibraryExW: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation#functions-without-max_path-restrictions Always use extended-length paths in Windows bootstrap code and correctly convert UNC paths to the \\?\UNC\ form.
…otstrap path order Extended-length path prefixes (\\?\ and \\?\UNC\) added by bootstrap templates caused Runfiles.CurrentRepository() to fail with a mount mismatch ValueError when computing relative paths against standard drive roots. Additionally, forward-slash paths could be corrupted when checking the prefix before converting to an absolute path. - Normalize \\?\ and \\?\UNC\ prefixes and path separators in Runfiles._normalize_windows_path() and use ntpath on Windows. - Call abspath() before checking extended path prefixes across all bootstrap templates. - Fix inverted Windows logic in zip_main_template.py create_runfiles_root(). - Add unit tests for Windows path normalization in tests/runfiles/runfiles_test.py. - Add news fragment news/4071.fixed.md.
Unconditionally prepending \\?\ to short Windows paths broke cmd.exe batch wrapper execution, relative path resolution (..) in importlib.metadata, and zipapp runfiles discovery. Restrict extended path prefixing in bootstrap templates to paths that exceed MAX_PATH (260 characters).
…nfiles Unconditionally apply extended-length path prefixing on Windows without arbitrary MAX_PATH length checks. Normalize relative path separators in find_runfiles_root across bootstrap templates so os.path.exists checks succeed under \\?\ paths. Ensure zipapp symlink extraction resolves relative targets to absolute paths on Windows, and normalize RECORD paths in importlib metadata tests.
|
CI flagged a variety of edge cases: https://buildkite.com/bazel/rules-python-python/builds/17072/list Would you be able to create a repro for this case? i.e. one that triggers LoadLibraryExW with a long path. There's now a py_extension rule that can create windows DLLs, so it should possible to create a small no-op python c module at a long path location to verify it can be loaded I'm gonna throw my ai at this and see if it can hash out the failures, too. |
Add a test exercising Python C extension dynamic loading at a path longer than 260 characters (MAX_PATH). On Windows, this exercises the extended-length path prefix (\\?\) in sys.path and runfiles required by LoadLibraryExW.
LoadLibraryExW is a Windows-specific API and long path names are restricted to Windows target compatibility to avoid POSIX path length limits on other operating systems.
…ap_impls Move the extended-length path test from tests/cc/py_extension to tests/bootstrap_impls/long_path to better reflect that it validates bootstrap path handling and LoadLibraryExW runtime behavior.
…ompatibility Shorten the intermediate directory segments so that the compile-time cl.exe params file path remains under MAX_PATH (213 characters), while the full runtime path in Bazel runfiles on Windows exceeds MAX_PATH (388 characters), exercising LoadLibraryExW with extended path prefixing.
…able tests Normalize sys.executable paths when comparing across processes, and read metadata files with relative '..' components via resolved paths to prevent Win32 invalid argument errors under extended-length prefixes.
|
Sorry, I expected to get emails about replies here, but I didn't for some reason (or they were filtered out, etc.), so I missed this. (fixed notifications, they were marked Spam for some reason...) |
Implicit long-path support is not universal across the Win32 API. The documented set of APIs covered by the long-path opt-in does not include DLL loading functions, e.g., LoadLibraryExW:
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation#functions-without-max_path-restrictions
Always use extended-length paths in Windows bootstrap code and correctly convert UNC paths to the \?\UNC\ form.
Experienced this breakage in JAX after the project being switched over to Bzlmod, which made some paths too long:
https://github.com/jax-ml/jax/actions/runs/31674295160/job/94365413380
Already used as a patch in jax-ml/jax#39961