-
Notifications
You must be signed in to change notification settings - Fork 234
Fix PowerShell path escaping #765
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
Conversation
I should also include a test for unusual characters, in aid of PowerShell/vscode-powershell#1392 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! One major concern, the rest are nits or comments :)
Ok, I've added testing for international characters and for dot-sourcing files with unusual characters in them (and checked the latter fail if I don't quote). So I think this is ready now :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Love the addition of all those tests
|
||
namespace Microsoft.PowerShell.EditorServices.Test.Session | ||
{ | ||
public class PathEscapingTests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+100 !
@@ -105,7 +105,7 @@ public async Task DebuggerAcceptsScriptArgs(string[] args) | |||
// it should not escape already escaped chars. | |||
ScriptFile debugWithParamsFile = | |||
this.workspace.GetFile( | |||
@"..\..\..\..\PowerShellEditorServices.Test.Shared\Debugging\Debug` With Params `[Test].ps1"); | |||
@"..\..\..\..\PowerShellEditorServices.Test.Shared\Debugging\Debug` W&ith Params `[Test].ps1"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the deal with the & char? It isn't a wildcard char. Ah, wait a tic. I see. On WinPS it's a reserved char and on PS Core it is used to create a (background) job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's a "token separator", so it will break a bareword string
@@ -796,7 +797,7 @@ public async Task ExecuteScriptWithArgs(string script, string arguments = null, | |||
if (File.Exists(script) || File.Exists(scriptAbsPath)) | |||
{ | |||
// Dot-source the launched script path | |||
script = ". " + EscapePath(script, escapeSpaces: true); | |||
script = ". " + QuoteEscapeString(script); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this continue to work if someone has a debug launch config like this:
"script": "${workspaceFolder}/foo`[bar`].ps1"
I "think" if we single quote a path, we have to evaluate backticks as well and perhaps strip some out. For instance, with the above path the user tried to be helpful and escape the wildcard chars for us (even though unnecessary, this works today). If the backticks are left in, the path will fail with this change - I think. However take a file named foo
bar.ps1` and it requires the backtick as a literal char.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll give it a test. I don't think we can do both though. Even if it means a breaking change, personally my preference is to enable all paths to work rather than having some paths work two ways and others not work at all.
It feels like we should treat the config setting as a LiteralPath
-- it's possible to call a file foo`[bar`].ps1
on the filesystem (I experimented with that while making the fix). In fact on Windows it's not possible to make *.ps1
or ?.ps1
but on *nix it is, and have `?.ps1
right next to them in the directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth noting here too that Set-PSBreakpoint
does not have a -LiteralPath
parameter -- something which there is a desire to fix I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rkeithhill I just tested with two files in the same directory ([script].ps1
and `[script`].ps1
) and in 1.9.0, backticks or not both hit the first file.
Unfortunately the same happens in 1.9.1, so looks like I still need to do some work in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I think I'm hitting a powershell issue here. I'll look into a workaround and open an issue there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've found something interesting. PowerShell behaves strangely with backtick escaping: PowerShell/PowerShell#7999.
It looks like we've always been receiving the message in the first place with the backtick escaped (or maybe the [
escaped) but not other places:
2018-10-11 11:31:44.987 [DIAGNOSTIC] C:\Users\roholt\Documents\Dev\PowerShellEditorServices\src\PowerShellEditorServices.Protocol\MessageProtocol\MessageReader.cs: In method 'ReadMessage', line 114:
READ MESSAGE:
{
"command": "launch",
"arguments": {
"type": "PowerShell",
"request": "launch",
"name": "Launch Script",
"script": "C:\\Users\\roholt\\Documents\\Dev\\sandbox/``[script``].ps1",
"args": [],
"cwd": "C:\\Users\\roholt\\Documents\\Dev\\sandbox",
"createTemporaryIntegratedConsole": false,
"internalConsoleOptions": "neverOpen",
"__sessionId": "ecbc3316-e3f6-48ea-a3cf-dc6730758edc"
},
"type": "request",
"seq": 2
}
This miraculously worked because PowerShell escapes ``[
the same as it escapes `[
, which I think is a bug.
So I'm currently trying to track down why the message we get doubles the backticks.
/// <param name="path">The path to process.</param> | ||
/// <param name="escapeSpaces">Specify True to escape spaces in the path, otherwise False.</param> | ||
/// <returns>The path with [ and ] escaped.</returns> | ||
internal static string GlobEscapePath(string path, bool escapeSpaces = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit but does PowerShell really do globbing? Maybe this should be EscapeWildcardsInPath()
or something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good point. Discussing with @JamesWTruher we were calling it "globbing" but the help topic is about_Wildcards. I will rename.
Ok, I've finally worked out where the problem lay on our end. I'm going to do a bit more work to make this performant, but this is now working properly. |
Ok, thought I could jimmy some more Gonna ask for a second review here (@tylerl0706, @SeeminglyScience, @rkeithhill), since I've changed some things now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a small comment on the string concatenation
launchedScript = script + " " + arguments; | ||
command.AddScript(launchedScript, false); | ||
reportedScript += " " + arguments; | ||
escapedScriptPath += " " + arguments; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use a StringBuilder or string interpolation here instead?
Same for line 804, 801
73d7b6d
to
7fab6d8
Compare
So it turns out that PowerShell (back to v3 at least) has a But frankly it's broken:
And it's also subject to a PR or two currently. See PowerShell/PowerShell#7407. |
Fixes PowerShell/vscode-powershell#1400.
Fixes PowerShell/vscode-powershell#1526.
Replaces the strange regex logic we use with some glob-escaping string mangling.
Also single-quotes the place we dot-source a debug path.
Obsoletes some static public methods that have no business being public.
Adds a bunch of tests. Changes an existing one to check the ampersand case that we used to crash on.