Powershell: String in Sub-Expression incorrectly parsed

Created on 10 Aug 2017  路  6Comments  路  Source: PowerShell/PowerShell

Hello everyone,
got a possible interpreter bug explained in detail first in the following forum
https://social.technet.microsoft.com/Forums/windowsserver/en-US/aeff1790-7e9a-4dfa-b35c-212a7f4b78b0/subexpression-with-additional-parentheses-string-inside-a-string-with-quotation-marks?forum=winserverpowershell

Steps to reproduce

Enter the following code in the console or in a script:

"$(')')" or "$('(')" or "$(")")" and so on.

Expected behavior

Should output a single closing parenthesis ) in the console

)

Actual behavior

Complains about missing parenthesis, although the parenthesis is enclosed in single quotation marks.
If you add an additional parenthesis so that the parethesis are balanced it's OK but this is not expected.

"$('()')"

Environment data

Could be reproduced in all Powershell-Versions up to the latest available.

Regards
colinardo

Issue-Bug WG-Engine

Most helpful comment

This is related to #3039 in a way, but I think this issue could be fixed whereas I think #3039 probably can't.

First, there is a workaround - put an opening paren in a comment like this:

"$(<#(#>')')"

Yes it's ugly. There are better alternatives, like using a format string, but I had to mention this for completeness.

A fix for this issue might be as simple as keeping a stack of expected delimiters, and only counting the opening/closing paren when the top of this stack is a paren.

The delimiters pairs that must be handled include <# #>, ' ', " ", @" "@, @' '@ and of course ( ). I think it's safe to ignore [ ] and { } here.

It is important to ignore escape characters though, e.g. the following examples are/should be valid with and without matched delimiters:

echo a`'`(b
echo a`'`(`'b
"$(echo a`'`(b)'
"$(echo a`'`(`'b)"

All 6 comments

Good find; it seems that any unbalanced ( or ) instances inside a _quoted string_ inside $(...) cause the problem.

The following commands all break unexpectedly:

"$(')')"  # your example
"$('(')"  # opening parenthesis too
"$("(")"  # ditto with double quotes

Conversely, the following does _not_ break, even though it should:

"$("`")"  # !! Unexpectedly doesn't break, even though "`" is not a well-formed string.

This looks related to #3039, and to this question on SO.

This is related to #3039 in a way, but I think this issue could be fixed whereas I think #3039 probably can't.

First, there is a workaround - put an opening paren in a comment like this:

"$(<#(#>')')"

Yes it's ugly. There are better alternatives, like using a format string, but I had to mention this for completeness.

A fix for this issue might be as simple as keeping a stack of expected delimiters, and only counting the opening/closing paren when the top of this stack is a paren.

The delimiters pairs that must be handled include <# #>, ' ', " ", @" "@, @' '@ and of course ( ). I think it's safe to ignore [ ] and { } here.

It is important to ignore escape characters though, e.g. the following examples are/should be valid with and without matched delimiters:

echo a`'`(b
echo a`'`(`'b
"$(echo a`'`(b)'
"$(echo a`'`(`'b)"

Really great info provided here, thanks @lzybkr .

See also
https://github.com/PowerShell/vscode-powershell/issues/1401

A comment nested inside a subexpression can expose issues with parenthesis as well.

I ran in to this, unmatched parenthesis because of a regular expression, was able to do this:

from https://gist.github.com/msftrncs/bff8c6c5e28ff92a19efb8a5556a4238, both lines are enclosed in the same string subexpression, and line 37 also possesses its own string subexpression as well.

Line 25

                if ($_ -match '^(?:[@#<>]|[1-6]>)|[\s`|&;,''"\u2018-\u201E{}()]|\$[{(\w:$^?]') { #)

Line 37


                "$QuotedWith$($_ -replace '["\u201C-\u201E`]', '$0$0' -replace '\$(?=[{(\w:$^?])'<#)#>, '`$0')$QuotedWith"
Was this page helpful?
0 / 5 - 0 ratings