Skip to content

Fix launching executables whose path can't be shortened on Windows#29921

Closed
rdesgroppes wants to merge 2 commits into
bazelbuild:masterfrom
rdesgroppes:fix-19710-long-exe-path
Closed

Fix launching executables whose path can't be shortened on Windows#29921
rdesgroppes wants to merge 2 commits into
bazelbuild:masterfrom
rdesgroppes:fix-19710-long-exe-path

Conversation

@rdesgroppes

@rdesgroppes rdesgroppes commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Description

AsExecutablePathForCreateProcess shortens an executable's path with GetShortPathNameW so it fits CreateProcessW's MAX_PATH-bound command line, and currently fails outright when shortening can't bring it under MAX_PATH.
This change adds a fallback: it launches the executable through CreateProcessW's lpApplicationName, which is not subject to the MAX_PATH limit, in extended-length (\\?\) form.
Supplying lpApplicationName also lifts the MAX_PATH limit from the executable part of lpCommandLine, so the original path is kept there as argv[0].

Shortening is still attempted first, so the change is a pure superset of the current behavior: paths that shorten today are launched unchanged, and only the currently-failing ones take the fallback.
The fallback is limited to absolute, normalized paths to plain executables:

  • a batch file is not a valid lpApplicationName as it must be run through a command interpreter,
  • neither is a non-normalized path because its ./.. components would survive unresolved in the extended-length path.

The fix relies on \\?\ bypassing MAX_PATH at the path-parsing layer, independently of the LongPathsEnabled registry value and the longPathAware manifest.

Motivation

Fixes #19710.

Avoid errors like:

==================== Test output for //some/configuration/issues/invalidconfig:invalidconfig_test:
ERROR(tools/test/windows/tw.cc:1307) ERROR: src/main/native/windows/process.cc(82): WaitableProcess::Create(C:\user\execroot\_main\bazel-out\x64_windows-fastbuild-ST-000000000001\bin\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe.runfiles\_main\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe): ERROR: src/main/native/windows/util.cc(292): AsExecutablePathForCreateProcess(C:\user\execroot\_main\bazel-out\x64_windows-fastbuild-ST-000000000001\bin\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe.runfiles\_main\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe): ERROR: src/main/native/windows/util.cc(262): GetShortPathNameW(\\?\C:\user\execroot\_main\bazel-out\x64_windows-fastbuild-ST-000000000001\bin\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe.runfiles\_main\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe): cannot shorten the path enough
ERROR(tools/test/windows/tw.cc:1517) Failed to start test process (arg: C:\user\execroot\_main\bazel-out\x64_windows-fastbuild-ST-000000000001\bin\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe.runfiles\_main\some\configuration\issues\invalidconfig\invalidconfig_test_\invalidconfig_test.exe)
================================================================================

Shortening fails in two situations, both handled here:

Prior art: Rust's std::process::Command passes a verbatim \\?\ path as lpApplicationName for a >MAX_PATH executable and special-cases batch files the same way:

Build API Changes

No

Checklist

  • I have added tests for the new use cases (if any).
  • I have updated the documentation (if applicable).

Release Notes

RELNOTES: Fixed Bazel being unable to run a Windows executable whose path is too long to shorten under MAX_PATH, e.g. when 8dot3 short names are disabled (microsoft/Windows-Containers#507).

@rdesgroppes rdesgroppes marked this pull request as ready for review June 21, 2026 17:42
@github-actions github-actions Bot added area-Windows Windows-specific issues and feature requests awaiting-review PR is awaiting review from an assigned reviewer labels Jun 21, 2026
rdesgroppes added a commit to DataDog/datadog-agent-buildimages that referenced this pull request Jun 22, 2026
### What does this PR do?
Enable NTFS 8.3 short-name creation on the container scratch volume at
startup, via `fsutil 8dot3name set C: 0` in the entrypoint.

The registry key from #1212 is dropped because it is now superseded and
provably inert for the scratch volume.

### Motivation
#1212 set `NtfsDisable8dot3NameCreation` to 0 in the image, betting the
SYSTEM-hive value would travel with the layers.
It **does** travel, but a container's fresh scratch volume surprisingly
still comes up disabled at runtime:
```
The volume state is: 1 (8dot3 name creation is DISABLED)
The registry state is: 0 (8dot3 name creation is ENABLED on all volumes)
Based on the above settings, 8dot3 name creation is ENABLED on "C:"
```
`fsutil` **mistakenly** reports ENABLED after the registry override, yet
freshly created files still get no 8.3 alias, so `GetShortPathNameW`
stays a no-op and Bazel still cannot shorten long paths
(bazelbuild/bazel#19710), root cause of
[#incident-56436](https://dd.enterprise.slack.com/archives/C0BBPAV0J20).

#1212 also anticipated that a build-time `fsutil 8dot3name set` would
not persist, which a test image confirmed: the build volume flips to
state 0, but a container started from that image is back to state 1.

Per microsoft/Windows-Containers#507 and Microsoft Q&A[^1], the
per-volume flag only takes hold across an unmount/remount and is not
carried by image layers, so it must be (re)applied at runtime.
The entrypoint is the earliest such point, ahead of any build.

### Possible Drawbacks / Trade-offs
`fsutil 8dot3name set` runs on every container start, but it is a cheap
per-volume metadata write.
As in #1212, it only affects files created afterwards, which covers the
runtime-created output base.

### Additional Notes
Validated by DataDog/datadog-agent#52500 against this image:
`bazel:test:windows-amd64` is green with the runtime override removed.

There's work in progress we'll monitor to remove the workaround:
- bazelbuild/bazel#29921.

[^1]: of which:
- https://learn.microsoft.com/en-us/answers/questions/1406321/enable-8dot3-name-creation-for-volume-c-in-windows
- https://learn.microsoft.com/en-us/answers/questions/2455648/8-3-filename-support
- etc.
rdesgroppes added a commit to DataDog/datadog-agent-buildimages that referenced this pull request Jun 22, 2026
### What does this PR do?
Enable NTFS 8.3 short-name creation on the container scratch volume at
startup, via `fsutil 8dot3name set C: 0` in the entrypoint.

The registry key from #1212 is dropped because it is now superseded and
provably inert for the scratch volume.

### Motivation
#1212 set `NtfsDisable8dot3NameCreation` to 0 in the image, betting the
SYSTEM-hive value would travel with the layers.
It **does travel**, but a container's fresh scratch volume surprisingly
still comes up disabled at runtime despite `fsutil` output:
```
The volume state is: 1 (8dot3 name creation is DISABLED)
The registry state is: 0 (8dot3 name creation is ENABLED on all volumes)
Based on the above settings, 8dot3 name creation is ENABLED on "C:"
```
`fsutil` **mistakenly** reports ENABLED after the registry override, yet
freshly created files **still get no 8.3 alias**, so `GetShortPathNameW`
stays a no-op and Bazel still cannot shorten long paths
(bazelbuild/bazel#19710), root cause of
[#incident-56436](https://dd.enterprise.slack.com/archives/C0BBPAV0J20).

#1212 also anticipated that a build-time `fsutil 8dot3name set` would
not persist, which a test image confirmed: the build volume flips to
state 0, but a container started from that image is back to state 1.

Per microsoft/Windows-Containers#507 and Microsoft Q&A[^1], the
per-volume flag only takes hold across an unmount/remount and is not
carried by image layers, so it must be (re)applied at runtime.

=> The entrypoint is the earliest such point, ahead of any build.

### Possible Drawbacks / Trade-offs
`fsutil 8dot3name set` runs on every container start, but it is a cheap
per-volume metadata write.
As in #1212, it only affects files created afterwards, which covers the
runtime-created output base.

### Additional Notes
Validated by DataDog/datadog-agent#52500 against this image:
`bazel:test:windows-amd64` is green with the runtime override removed.

There's work in progress we'll monitor to remove the workaround:
- bazelbuild/bazel#29921.

[^1]: of which:
- https://learn.microsoft.com/en-us/answers/questions/1406321/enable-8dot3-name-creation-for-volume-c-in-windows
- https://learn.microsoft.com/en-us/answers/questions/2455648/8-3-filename-support
- etc.
rdesgroppes added a commit to DataDog/datadog-agent-buildimages that referenced this pull request Jun 22, 2026
### What does this PR do?
Enable NTFS 8.3 short-name creation on the container scratch volume at
startup, via `fsutil 8dot3name set C: 0` in the entrypoint.

The registry key from #1212 is dropped because it is now superseded and
provably inert for the scratch volume.

### Motivation
#1212 set `NtfsDisable8dot3NameCreation` to 0 in the image, betting the
SYSTEM-hive value would travel with the layers.
It **does travel**, but a container's fresh scratch volume surprisingly
still comes up disabled at runtime despite `fsutil` output:
```
The volume state is: 1 (8dot3 name creation is DISABLED)
The registry state is: 0 (8dot3 name creation is ENABLED on all volumes)
Based on the above settings, 8dot3 name creation is ENABLED on "C:"
```
`fsutil` **mistakenly** reports ENABLED after the registry override, yet
freshly created files **still get no 8.3 alias**, so `GetShortPathNameW`
stays a no-op and Bazel still cannot shorten long paths
(bazelbuild/bazel#19710), root cause of
[#incident-56436](https://dd.enterprise.slack.com/archives/C0BBPAV0J20).

#1212 also anticipated that a build-time `fsutil 8dot3name set` would
not persist, which a test image confirmed: the build volume flips to
state 0, but a container started from that image is back to state 1.

Per microsoft/Windows-Containers#507 and Microsoft Q&A[^1], the
per-volume flag only takes hold across an unmount/remount and is not
carried by image layers, so it must be (re)applied at runtime.

=> The entrypoint is the earliest such point, ahead of any build.

### Possible Drawbacks / Trade-offs
`fsutil 8dot3name set` runs on every container start, but it is a cheap
per-volume metadata write.
As in #1212, it only affects files created afterwards, which covers the
runtime-created output base.

### Additional Notes
Validated by DataDog/datadog-agent#52500 against this image:
`bazel:test:windows-amd64` is green with the runtime override removed.

There's work in progress we'll monitor to remove the workaround:
- bazelbuild/bazel#29921.

[^1]: of which:
- https://learn.microsoft.com/en-us/answers/questions/1406321/enable-8dot3-name-creation-for-volume-c-in-windows
- https://learn.microsoft.com/en-us/answers/questions/2455648/8-3-filename-support
- etc.

@fmeum fmeum left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix, this looks pretty simple and doesn't require any manifest patching.

Comment thread src/main/native/windows/util.cc
@fmeum

fmeum commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

FYI @meteorcloudy for when you are back
@fweikert Could you review this in the meantime?

### Description

`AsExecutablePathForCreateProcess` shortens an executable's path with
`GetShortPathNameW` so it fits `CreateProcessW`'s `MAX_PATH`-bound
command line, and currently fails outright when shortening can't bring
it under `MAX_PATH`.
This change adds a fallback: it launches the executable through
`CreateProcessW`'s _lpApplicationName_, which is not subject to the
`MAX_PATH` limit, in extended-length (`\\?\`) form.
Supplying _lpApplicationName_ also lifts the `MAX_PATH` limit from the
executable part of _lpCommandLine_, so the original path is kept there
as `argv[0]`.

Shortening is still attempted first, so the change is a pure superset of
the current behavior: paths that shorten today are launched unchanged,
and only the currently-failing ones take the fallback.
The fallback is limited to absolute, normalized paths to plain
executables:
- a batch file is not a valid _lpApplicationName_ as it must be run
  through a command interpreter,
- neither is a non-normalized path because its `.`/`..` components would
  survive unresolved in the extended-length path.

The fix relies on `\\?\` bypassing `MAX_PATH` at the path-parsing layer,
independently of the _LongPathsEnabled_ registry value and the
_longPathAware_ manifest.

### Motivation
Fixes bazelbuild#19710.

Shortening fails in two situations, both handled here:
- 8dot3 short-name creation is disabled on the volume (common in
  containers, microsoft/Windows-Containers#507), so `GetShortPathNameW`
  is a no-op and a long runfiles executable path stays over `MAX_PATH`,
- the path is nested so deeply that even fully 8dot3-shortened it still
  overflows `MAX_PATH`.

Prior art: Rust's `std::process::Command` passes a verbatim `\\?\` path
as _lpApplicationName_ for a >`MAX_PATH` executable and special-cases
batch files the same way (rust-lang/rust#87704, rust-lang/rust#92519).

### Build API Changes

No

### Checklist

- [x] I have added tests for the new use cases (if any).
- [ ] I have updated the documentation (if applicable).

### Release Notes

RELNOTES: Fixed Bazel being unable to run a Windows executable whose
path is too long to shorten under `MAX_PATH`, e.g. when 8dot3 short
names are disabled (microsoft/Windows-Containers#507).
@github-actions github-actions Bot added the community-reviewed Reviewed by a trusted community contributor label Jun 22, 2026
@rdesgroppes rdesgroppes force-pushed the fix-19710-long-exe-path branch from cbb4d49 to 812a275 Compare June 22, 2026 13:07
gh-worker-dd-mergequeue-cf854d Bot pushed a commit to DataDog/datadog-agent that referenced this pull request Jun 23, 2026
…2500)

### What does this PR do?
Add a preflight check that creates a temp file whose name exceeds 8.3 limits and compare its long name (`%%~nxi`) against its short name (`%%~snxi`).

When they are equal, `GetShortPathNameW` is a no-op, meaning 8.3 short names are disabled and the hook exits with actionable instructions.

### Motivation
`GetShortPathNameW` is a no-op when 8.3 short names are disabled, causing Bazel to fail with an internal path-length error (bazelbuild/bazel#19710), even with the 260-character OS limit lifted.

GitLab runners had the volume state enabled, but Docker containers did not, root cause of [#incident-56436](https://dd.enterprise.slack.com/archives/C0BBPAV0J20).
The latter is now fixed by the combo:
- DataDog/datadog-agent-buildimages#1215
- #52561.

The present change makes it fail fast with actionable instructions rather than a cryptic Bazel error.

### Describe how you validated your changes
Before #52561 was merged: https://gitlab.ddbuild.io/DataDog/datadog-agent/-/jobs/1788332180#L48

### Additional Notes
To be reverted once following upstream fix (or equivalent) is available:
- bazelbuild/bazel#29921.

Co-authored-by: regis.desgroppes <regis.desgroppes@datadoghq.com>
@Wyverald Wyverald added team-OSS Issues for the Bazel OSS team: installation, release processBazel packaging, website awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally and removed awaiting-review PR is awaiting review from an assigned reviewer labels Jun 23, 2026
@github-actions github-actions Bot removed the awaiting-PR-merge PR has been approved by a reviewer and is ready to be merge internally label Jun 24, 2026
@rdesgroppes rdesgroppes deleted the fix-19710-long-exe-path branch June 24, 2026 17:50
@fmeum

fmeum commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

@bazel-io fork 9.2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Windows Windows-specific issues and feature requests community-reviewed Reviewed by a trusted community contributor team-OSS Issues for the Bazel OSS team: installation, release processBazel packaging, website

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: cannot shorten the path enough

3 participants