From 8f72fc1c2d485a2217de8ab9e2836154b5ef737b Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 28 Aug 2026 09:57:50 -0700 Subject: [PATCH] Fix crossgen2 rejecting input files with uppercase .DLL/.EXE extensions (#132857) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `crossgen2` rejected input assemblies whose on-disk extension is uppercase (`.DLL`/`.EXE`), which occurs on filesystems/network shares that normalize casing (e.g. WinFsp/virtiofs). This is a regression from `Microsoft.NETCore.App.Crossgen2` 10.0.5 → 10.0.9, breaking `PublishReadyToRun` builds on affected volumes. ## Root Cause `RunSingleCompilation` in `src/coreclr/tools/aot/crossgen2/Program.cs` matched `Path.GetExtension(inFilePath)` against `.dll`/`.exe` using a case-sensitive switch expression, throwing `CommandLineException` for any other casing. ## Fix - Replaced the switch expression with cascading `if`/`else if` statements comparing the extension via `StringComparison.OrdinalIgnoreCase`, so `.dll`, `.DLL`, `.Dll`, `.exe`, `.EXE`, etc. are all accepted. - Fixes #132554 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jtschuster <36744439+jtschuster@users.noreply.github.com> --- src/coreclr/tools/aot/crossgen2/Program.cs | 35 ++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index 691add6dd78b2a..ebd233ed68ff83 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -309,8 +309,8 @@ public int Run() { foreach (var inputFile in inputFilePaths) { - var tmpOutFile = inputFile.Value.Replace(".dll", ".ni.dll.tmp"); - var outFile = inputFile.Value.Replace(".dll", ".ni.dll"); + var tmpOutFile = GetNearOutputFilePath(inputFile.Value, temporary: true); + var outFile = GetNearOutputFilePath(inputFile.Value, temporary: false); Console.WriteLine($@"Moving R2R PE file: {tmpOutFile} to {outFile}"); System.IO.File.Move(tmpOutFile, outFile); } @@ -324,6 +324,23 @@ public int Run() return 0; } + private static string GetNearOutputFilePath(string inFilePath, bool temporary) + { + string inputFileExtension = Path.GetExtension(inFilePath); + if (inputFileExtension.Equals(".dll", StringComparison.OrdinalIgnoreCase)) + { + return Path.ChangeExtension(inFilePath, temporary ? ".ni.dll.tmp" : ".ni.dll"); + } + else if (inputFileExtension.Equals(".exe", StringComparison.OrdinalIgnoreCase)) + { + return Path.ChangeExtension(inFilePath, temporary ? ".ni.exe.tmp" : ".ni.exe"); + } + else + { + throw new CommandLineException(string.Format(SR.UnsupportedInputFileExtension, inputFileExtension)); + } + } + private void RunSingleCompilation(Dictionary inFilePaths, InstructionSetSupport instructionSetSupport, string compositeRootPath, Dictionary unrootedInputFilePaths, HashSet versionBubbleModulesHash, ReadyToRunCompilerContext typeSystemContext, Logger logger) { // @@ -332,19 +349,7 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru var e = inFilePaths.GetEnumerator(); e.MoveNext(); string inFilePath = e.Current.Value; - string inputFileExtension = Path.GetExtension(inFilePath); - string nearOutFilePath = inputFileExtension switch - { - ".dll" => Path.ChangeExtension(inFilePath, - _singleFileCompilation&& _inputBubble - ? ".ni.dll.tmp" - : ".ni.dll"), - ".exe" => Path.ChangeExtension(inFilePath, - _singleFileCompilation && _inputBubble - ? ".ni.exe.tmp" - : ".ni.exe"), - _ => throw new CommandLineException(string.Format(SR.UnsupportedInputFileExtension, inputFileExtension)) - }; + string nearOutFilePath = GetNearOutputFilePath(inFilePath, temporary: _singleFileCompilation && _inputBubble); string outFile = _outNearInput ? nearOutFilePath : _outputFilePath; string dgmlLogFileName = Get(_command.DgmlLogFileName);