Fix unhandled exception in /getItem and /getTargetResult for items with illegal path characters
Fixes #11726
Context
/getItem and /getTargetResult throw an unhandled InvalidOperationException when serializing items whose item specs contain illegal path characters (e.g., compiler command line flags from ClangTidy's GetCompileCommands target).
The JSON output formatter iterates over all metadata names including built-in metadata like FullPath, Directory, etc. When GetMetadata() is called on these, it attempts path computation which fails for non-path item specs.
Changes Made
- Wrapped metadata retrieval in
JsonOutputFormatter.cswith try-catch forInvalidOperationException - Added
TryGetMetadataandTryGetMetadataValuehelper methods that return empty string on failure - Applied fix to all three affected methods:
AddTargetResultsInJsonFormat,AddItemInstancesInJsonFormat,AddItemsInJsonFormat
Testing
Added GetTargetResultWithIllegalPathCharacters test that verifies both /getTargetResult and /getItem succeed with items containing compiler flags as item specs.
Notes
On Linux, the test shows the path-like metadata is still computed (since / is valid in paths). On Windows, these would return empty strings. The key fix is preventing the unhandled exception crash.
[!WARNING]
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
rcxvsblobprodcus328.vsblob.vsassets.io
- Triggering command:
/home/REDACTED/work/msbuild/msbuild/artifacts/bin/bootstrap/core/dotnet dotnet test src/MSBuild.UnitTests/Microsoft.Build.CommandLine.UnitTests.csproj --filter FullyQualifiedName~GetTargetResultWithIllegalPathCharacters --no-build(dns block)If you need me to access, download, or install something from one of these locations, you can either:
- Configure Actions setup steps to set up my environment, which run before the firewall is enabled
- Add the appropriate URLs or hosts to the custom allowlist in this repository's Copilot coding agent settings (admins only)
Original prompt
This section details on the original issue you should resolve
<issue_title>[Unhandled Exception]: /getItem and /getTargetResult fail for target GetCompileCommands</issue_title> <issue_description>### Issue Description
There is an uncaught exception when trying to access certain information from the GetCompileCommands target (from ClangTidy), in particular /getTargetResult:GetCompileCommands and /getTargetResult:GetCompileCommands
Steps to Reproduce
Run either of the following commands (You could also run with target /t:ClangTidy for the same result)
msbuild tidytest.vcxproj /t:GetCompileCommands /getTargetResult:GetCompileCommands
msbuild tidytest.vcxproj /t:GetCompileCommands /getItem:CompileCommands
I expect to get a json formatted target result or item.
Actual Behavior
I get the following error when building
C:\Users\rp0656\source\repos\tidytest>msbuild tidytest.vcxproj /t:GetCompileCommands /getTargetResult:GetCompileCommands
MSBUILD : error MSB1025: An internal failure occurred while running MSBuild.
System.InvalidOperationException: The item metadata "%(FullPath)" cannot be applied to the path "/c /nologo /W3 /WX- /diagnostics:column /Od /D _DEBUG /D _CONSOLE /D _UNICODE /D UNICODE /EHsc /RTC1 /MDd /GS /fp:precise /permissive- /Fa"tidytest\x64\Debug\\" /Fo"tidytest\x64\Debug\\" /Gd --target=amd64-pc-windows-msvc /TP". Illegal characters in path.
at Microsoft.Build.Shared.ErrorUtilities.ThrowInvalidOperation(String resourceName, Object[] args)
at Microsoft.Build.Shared.FileUtilities.ItemSpecModifiers.GetItemSpecModifier(String currentDirectory, String itemSpec, String definingProjectEscaped, String modifier, String& fullPath)
at Microsoft.Build.Evaluation.BuiltInMetadata.GetMetadataValueEscaped(String currentDirectory, String evaluatedIncludeBeforeWildcardExpansionEscaped, String evaluatedIncludeEscaped, String definingProjectEscaped, String name, String& fullPath)
at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetBuiltInMetadataEscaped(String name)
at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadataEscaped(String metadataName)
at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadata(String metadataName)
at Microsoft.Build.CommandLine.JsonOutputFormatter.AddTargetResultsInJsonFormat(String[] targetNames, BuildResult result)
at Microsoft.Build.CommandLine.MSBuildApp.OutputBuildInformationInJson(BuildResult result, String[] getProperty, String[] getItem, String[] getTargetResult, ILogger[] loggers, ExitType exitType, TextWriter outputStream)
at Microsoft.Build.CommandLine.MSBuildApp.Execute(String commandLine)
Unhandled Exception: System.InvalidOperationException: The item metadata "%(FullPath)" cannot be applied to the path "/c /nologo /W3 /WX- /diagnostics:column /Od /D _DEBUG /D _CONSOLE /D _UNICODE /D UNICODE /EHsc /RTC1 /MDd /GS /fp:precise /permissive- /Fa"tidytest\x64\Debug\\" /Fo"tidytest\x64\Debug\\" /Gd --target=amd64-pc-windows-msvc /TP". Illegal characters in path.
at Microsoft.Build.Shared.ErrorUtilities.ThrowInvalidOperation(String resourceName, Object[] args)
at Microsoft.Build.Shared.FileUtilities.ItemSpecModifiers.GetItemSpecModifier(String currentDirectory, String itemSpec, String definingProjectEscaped, String modifier, String& fullPath)
at Microsoft.Build.Evaluation.BuiltInMetadata.GetMetadataValueEscaped(String currentDirectory, String evaluatedIncludeBeforeWildcardExpansionEscaped, String evaluatedIncludeEscaped, String definingProjectEscaped, String name, String& fullPath)
at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetBuiltInMetadataEscaped(String name)
at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadataEscaped(String metadataName)
at Microsoft.Build.Execution.ProjectItemInstance.TaskItem.GetMetadata(String metadataName)
at Microsoft.Build.CommandLine.JsonOutputFormatter.AddTargetResultsInJsonFormat(String[] targetNames, BuildResult result)
at Microsoft.Build.CommandLine.MSBuildApp.OutputBuildInformationInJson(BuildResult result, String[] getProperty, String[] getItem, String[] getTargetResult, ILogger[] loggers, ExitType exitType, TextWriter outputStream)
at Microsoft.Build.CommandLine.MSBuildApp.Execute(String commandLine)
at Microsoft.Build.CommandLine.MSBuildApp.Main()
Analysis
The error suggests that it is trying to interpret the flags of the compile commands as a path, which causes an error when it can't be resolved. The function %(FullPath) is used, though it is not clear to me exactly where, but my best guess is it used on a variable that is supposed to just be the path to cl, but has been extended with flags.
See the clang tidy targets file at something similar to C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.Cpp.ClangTidy.targets
Versions & Co...
- Fixes dotnet/msbuild#12589
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
PS C:\Users\janprovaznik\Downloads\tidytest> D:\msbuilds\msb9\artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe tidytest.vcxproj /t:GetCompileCommands /getItem:CompileCommands
{
"Items": {
"CompileCommands": [
{
"Identity": "/c /nologo /W3 /WX- /diagnostics:column /Od /Oy- /D WIN32 /D _DEBUG /D _CONSOLE /D _UNICODE /D UNICODE /EHsc /RTC1 /MDd /GS /fp:precise /permissive- /Fa\u0022tidytest\\Debug\\\\\u0022 /Fo\u0022tidytest\\Debug\\\\\u0022 /Gd --target=i686-pc-windows-msvc /TP",
"WorkingDirectory": "C:\\Users\\janprovaznik\\Downloads\\tidytest",
"Files": "C:\\Users\\janprovaznik\\Downloads\\tidytest\\main.cpp",
"ToolPath": "C:\\Windows\\system32\\CL.exe",
"FullPath": "",
"RootDir": "",
"Filename": "",
"Extension": "",
"RelativeDir": "",
"Directory": "",
"RecursiveDir": "",
"ModifiedTime": "",
"CreatedTime": "",
"AccessedTime": "",
"DefiningProjectFullPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Microsoft\\VC\\v170\\Microsoft.Cpp.ClangTidy.targets",
"DefiningProjectDirectory": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Microsoft\\VC\\v170\\",
"DefiningProjectName": "Microsoft.Cpp.ClangTidy",
"DefiningProjectExtension": ".targets"
}
]
}
}
PS C:\Users\janprovaznik\Downloads\tidytest> D:\msbuilds\msb9\artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe tidytest.vcxproj /t:GetCompileCommands /getTargetResult:GetCompileCommands
{
"TargetResults": {
"GetCompileCommands": {
"Result": "Success",
"Items": [
{
"Identity": "/c /nologo /W3 /WX- /diagnostics:column /Od /Oy- /D WIN32 /D _DEBUG /D _CONSOLE /D _UNICODE /D UNICODE /EHsc /RTC1 /MDd /GS /fp:precise /permissive- /Fa\u0022tidytest\\Debug\\\\\u0022 /Fo\u0022tidytest\\Debug\\\\\u0022 /Gd --target=i686-pc-windows-msvc /TP",
"WorkingDirectory": "C:\\Users\\janprovaznik\\Downloads\\tidytest",
"Files": "C:\\Users\\janprovaznik\\Downloads\\tidytest\\main.cpp",
"ToolPath": "C:\\Windows\\system32\\CL.exe",
"FullPath": "",
"RootDir": "",
"Filename": "",
"Extension": "",
"RelativeDir": "",
"Directory": "",
"RecursiveDir": "",
"ModifiedTime": "",
"CreatedTime": "",
"AccessedTime": "",
"DefiningProjectFullPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Microsoft\\VC\\v170\\Microsoft.Cpp.ClangTidy.targets",
"DefiningProjectDirectory": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\Msbuild\\Microsoft\\VC\\v170\\",
"DefiningProjectName": "Microsoft.Cpp.ClangTidy",
"DefiningProjectExtension": ".targets"
}
]
}
}
}
the command output from original issue makes sense