Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unescape Intrinsic Property Function Does Double-Unescaping #4086

Open
hypersw opened this issue Jan 20, 2019 · 0 comments
Open

Unescape Intrinsic Property Function Does Double-Unescaping #4086

hypersw opened this issue Jan 20, 2019 · 0 comments
Labels

Comments

@hypersw
Copy link

hypersw commented Jan 20, 2019

By calling the Unescape intrinsic property function (as in $([MSBuild]::Unescape(...))), I expect it to do one level of unescaping.

But I'm getting double unescaping instead. So turns out I have to do Escape twice on the data I'm feeding into the function to get the raw string back. This is not intuitive.

I guess this happens because one level of unescaping is done in Microsoft.Build.Evaluation.Expander`2+Function`1::Execute when preparing the argument (args[n] = EscapingUtilities.UnescapeAll(argumentValue);), and the second level of unescaping happens when the Unescape intrinsic function itself gets actually executed. Seems like it should have been a no-op function.

Steps to reproduce

Suppose we're trying to load a task from a DLL in the folder named $(The%20Folder) (literally, with these $ and % characters on disk, why not). You do not need the task DLL, just consider the path and match to the error messages when the task DLL is not found -- we need to get the desired path in the error message.

I've chosen UsingTask for this example because it skips unescaping on its path argument and thus avoids an extra level of possible unescaping.

Run the project file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<UsingTask TaskName="Unimportant" AssemblyFile="$([MSBuild]::Unescape('C:\%24(The%2520Folder)\Task.dll'))" />
	<UsingTask TaskName="Unimportant" AssemblyFile="$([MSBuild]::Unescape('C:\%2524(The%252520Folder)\Task.dll'))" />
	<Target Name="Target">
		<Unimportant />
	</Target>
</Project>

Expected behavior

... task could not be loaded from the assembly C:\$(The%20Folder)\Task.dll … if the first UsingTask unescapes only one level of escaping.

Actual behavior

... task could not be loaded from the assembly C:\$(The Folder)\Task.dll …, as two levels of escaping have been lifted.

If the first UsingTask element is commented out to let the second one work (that's doubly-escaped), we see the expected result.

Environment data

msbuild /version output:

Microsoft (R) Build Engine version 15.8.169+g1ccb72aefa for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

15.8.169.51996

OS info: Microsoft Windows [Version 10.0.17134.523]

If applicable, version of the tool that invokes MSBuild (Visual Studio, dotnet CLI, etc):

PS What would be the proper workaround, safest around different MSBuild versions out there starting with v4.0, to emit a project file which would pass the task path correctly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants