Work around MSB4216 NET task host drive-casing failure in CodeQL build#9371
Closed
AlesProkop wants to merge 1 commit into
Closed
Work around MSB4216 NET task host drive-casing failure in CodeQL build#9371AlesProkop wants to merge 1 commit into
AlesProkop wants to merge 1 commit into
Conversation
Temporary stopgap: rewrite the drive-letter casing of NetCoreSdkRoot to match the .NET task host child, learned via the SDK's dotnet host. Remove once the permanent fix (dotnet/arcade#17039, dotnet/msbuild#14027) flows in. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Member
Author
|
@microsoft-github-policy-service agree company="Microsoft" |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a temporary MSBuild-time workaround in eng/Versions.props to prevent intermittent MSB4216 failures in .NET Framework MSBuild task-host scenarios (notably CodeQL), by normalizing the drive-letter casing of $(NetCoreSdkRoot) to match what the child task host resolves.
Changes:
- Adds
InitialTargets="NormalizeNetCoreSdkRootCasing"so the normalization runs early in Full MSBuild runs. - Introduces an inline
RoslynCodeTaskFactorytask that probes the SDK’sdotnet.exeprocess path to learn the volume’s canonical drive casing and rewrites$(NetCoreSdkRoot)casing-only. - Adds opt-out / override properties (
DisableNetCoreSdkRootDriveCasingWorkaround,NetCoreSdkRootDriveCasingOverride).
Comment on lines
+199
to
+203
|
|
||
| string tasksDll = Path.Combine(sdkRoot, "Microsoft.Build.Tasks.Core.dll"); | ||
| string tempDir = Path.Combine(Path.GetTempPath(), "sdkdrvprobe_" + Guid.NewGuid().ToString("N")); | ||
| Directory.CreateDirectory(tempDir); | ||
| string proj = Path.Combine(tempDir, "probe.proj"); |
Comment on lines
+235
to
+256
| var psi = new ProcessStartInfo | ||
| { | ||
| FileName = dotnetExe, | ||
| Arguments = "msbuild \"" + proj + "\" -nologo -nodeReuse:false -v:m -t:P", | ||
| UseShellExecute = false, | ||
| RedirectStandardOutput = true, | ||
| RedirectStandardError = true, | ||
| CreateNoWindow = true, | ||
| WorkingDirectory = tempDir, | ||
| }; | ||
|
|
||
| using (var p = Process.Start(psi)) | ||
| { | ||
| string stdout = p.StandardOutput.ReadToEnd(); | ||
| string stderr = p.StandardError.ReadToEnd(); | ||
| if (!p.WaitForExit(120000)) | ||
| { | ||
| try { p.Kill(); } catch { } | ||
| Log.LogMessage(MessageImportance.Low, "NormalizeSdkRootDriveCasing: probe timed out launching '{0}'.", dotnetExe); | ||
| return '\0'; | ||
| } | ||
|
|
Member
|
Closing for now, I'll wait for the arcade fix to flow. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The CodeQL pipeline (and other .NET Framework MSBuild host scenarios on certain hosted CI agents) fails with MSB4216 when Arcade's
InstallDotNetCoretask launches the .NET task host:Root cause (see dotnet/msbuild#14026): the task host handshake salt is a case-sensitive hash of the SDK tools directory. The .NET Framework host derives it from
$(NetCoreSdkRoot)(drive-letter casing propagated verbatim from the environment, e.g. ADO'sD:\a\_work\1\s), while the .NET task host child resolves its own path viaEnvironment.ProcessPath, which on some agents reports the volume's canonical lowercase drive (d:). The salts then differ and the handshake fails. The failure is agent-specific, which is why it reproduces intermittently.Fix (temporary)
An
InitialTargetstarget ineng/Versions.propsrewrites only the drive-letter casing of$(NetCoreSdkRoot)to match the casing the child task host will use. It learns that casing by launching the SDK's owndotnethost (dotnet.exe— the runtime host, which always runs and lives on the same volume as the SDK) and readingGetModuleFileNameW(NULL), the exact API behind the child'sEnvironment.ProcessPath. The detected drive letter is adopted only when it is the same letter differing solely in case, so it can never change the actual drive — only its casing. Windows-only, cached, and a safe no-op on agents that already work.Knobs:
DisableNetCoreSdkRootDriveCasingWorkaround=true— skip entirely.NetCoreSdkRootDriveCasingOverride=lower|upper— force the casing without probing (emergency/testing).Validation
Reproduced and validated on the actual failing agent type via the
microsoft-testfxCodeQL pipeline: the probe resolvedd:, the target rewroteNetCoreSdkRootD:→d:, and MSB4216 was eliminated (two independent runs that both landed on a "bad" agent went green; anOverride=lowerrun also confirmed the salt reads the live, target-mutated property).Temporary / follow-up
This is a stopgap. The permanent fixes are:
Remove this once both are in.