PowerShell / PowerShell

PowerShell for every system!
https://microsoft.com/PowerShell
MIT License
43.66k stars 7.08k forks source link

When tracing, Language.PositionUtilities.BriefMessage() passes an out-of-range index to StringBuilder.Insert() #16874

Open ghost opened 2 years ago

ghost commented 2 years ago

Prerequisites

Steps to reproduce

Using PowerShell 7.2.1 (I ran on Windows Server 2019 and on Debian 11.2 (4.4 kernel in Windows Subsystem for Linux)), enable tracing at level 1 or 2 and run this script (note that removing the Custom class's Method prevents the issue from occurring, but switching to New-Object does not):

class Custom {
  [void] Method() {}
}

[Custom]::new()

Expected behavior

PS C:\> Set-PSDebug -Trace 2; .\Test-TraceBug.ps1
DEBUG:    1+  >>>> Set-PSDebug -Trace 2; .\Test-TraceBug.ps1
DEBUG:     ! CALL function '<ScriptBlock>'
DEBUG:    1+ Set-PSDebug -Trace 2;  >>>> .\Test-TraceBug.ps1
DEBUG:    3+  >>>> [Custom]::new()

DEBUG:     ! CALL function '<ScriptBlock>'  (defined in file 'C:\Test-TraceBug.ps1')
Custom
PS C:\>

Actual behavior

PS C:\> Set-PSDebug -Trace 2; .\Test-TraceBug.ps1
DEBUG:    1+  >>>> Set-PSDebug -Trace 2; .\Test-TraceBug.ps1
DEBUG:     ! CALL function '<ScriptBlock>'
DEBUG:    1+ Set-PSDebug -Trace 2;  >>>> .\Test-TraceBug.ps1
DEBUG:    5+  >>>> [Custom]::new()

DEBUG:     ! CALL function '<ScriptBlock>'  (defined in file 'C:\Test-TraceBug.ps1')
DEBUG:    5+                                     function Get-ConciseViewPositionMessage  >>>> {

DEBUG:     ! CALL function 'Get-ConciseViewPositionMessage'
DEBUG:    7+                                          >>>> $resetColor = ''

DEBUG:     ! SET $resetColor = ''.
DEBUG:    8+                                         if ( >>>> $Host.UI.SupportsVirtualTerminal -and ([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {

DEBUG:    9+                                              >>>> $resetColor = [System.Management.Automation.VTUtility]::GetEscapeSequence(

DEBUG:     ! SET $resetColor = ''.
DEBUG:   46+                                          >>>> $errorColor = ''

DEBUG:     ! SET $errorColor = ''.
DEBUG:   47+                                          >>>> $accentColor = ''

DEBUG:     ! SET $accentColor = ''.
DEBUG:   49+                                         if ( >>>> $null -ne $Host.PrivateData) {

DEBUG:   50+                                              >>>> $errorColor = Get-VT100Color $Host.PrivateData.ErrorForegroundColor

DEBUG:   14+                                         function Get-VT100Color([ConsoleColor] $color)  >>>> {

DEBUG:     ! CALL function 'Get-VT100Color'
DEBUG:   15+                                             if ( >>>> !$Host.UI.SupportsVirtualTerminal -or !([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {

DEBUG:   19+                                             return  >>>> [System.Management.Automation.VTUtility]::GetEscapeSequence($color)

DEBUG:   20+                                          >>>> }

DEBUG:     ! SET $errorColor = ''.
DEBUG:   51+                                              >>>> $accentColor = Get-VT100Color ($Host.PrivateData.ErrorAccentColor ?? $errorColor)

DEBUG:   14+                                         function Get-VT100Color([ConsoleColor] $color)  >>>> {

DEBUG:     ! CALL function 'Get-VT100Color'
DEBUG:   15+                                             if ( >>>> !$Host.UI.SupportsVirtualTerminal -or !([string]::IsNullOrEmpty($env:__SuppressAnsiEscapeSequences))) {

DEBUG:   19+                                             return  >>>> [System.Management.Automation.VTUtility]::GetEscapeSequence($color)

DEBUG:   20+                                          >>>> }

DEBUG:     ! SET $accentColor = ''.
DEBUG:   54+                                          >>>> $posmsg = ''

DEBUG:     ! SET $posmsg = ''.
DEBUG:   55+                                          >>>> $headerWhitespace = ''

DEBUG:     ! SET $headerWhitespace = ''.
DEBUG:   56+                                          >>>> $offsetWhitespace = ''

DEBUG:     ! SET $offsetWhitespace = ''.
DEBUG:   57+                                          >>>> $message = ''

DEBUG:     ! SET $message = ''.
DEBUG:   58+                                          >>>> $prefix = ''

DEBUG:     ! SET $prefix = ''.
DEBUG:   61+                                         if ( >>>> ($myinv -and $myinv.ScriptName -or $myinv.ScriptLineNumber -gt 1 -or $err.CategoryInfo.Category -eq 'ParserError') -and !($myinv.ScriptName.EndsWith('.psm1', [System.StringComparison]::OrdinalIgnoreCase))) {

DEBUG:   62+                                              >>>> $useTargetObject = $false

DEBUG:     ! SET $useTargetObject = 'False'.
DEBUG:   65+                                             if ( >>>> $_.TargetObject.Line -and $_.TargetObject.LineText) {

DEBUG:   69+                                             elseif ( >>>> $myinv.ScriptName) {

DEBUG:   70+                                                 if ( >>>> $env:TERM_PROGRAM -eq 'vscode') {

DEBUG:   75+                                                      >>>> $posmsg = "${resetcolor}$($myinv.ScriptName):$($myinv.ScriptLineNumber)${newline}"

DEBUG:   75+                                                     $posmsg = "${resetcolor}$( >>>> $myinv.ScriptName):$($myinv.ScriptLineNumber)${newline}"

DEBUG:   75+                                                     $posmsg = "${resetcolor}$($myinv.ScriptName):$( >>>> $myinv.ScriptLineNumber)${newline}"

DEBUG:     ! SET $posmsg = 'C:\Test-TraceBug.ps1:5
'.
DEBUG:   82+                                             if ( >>>> $useTargetObject) {

DEBUG:   87+                                                  >>>> $scriptLineNumber = $myinv.ScriptLineNumber

DEBUG:     ! SET $scriptLineNumber = '5'.
DEBUG:   88+                                                  >>>> $scriptLineNumberLength = $myinv.ScriptLineNumber.ToString().Length

DEBUG:     ! SET $scriptLineNumberLength = '1'.
DEBUG:   91+                                             if ( >>>> $scriptLineNumberLength -gt 4) {

DEBUG:   95+                                              >>>> $lineWhitespace = ''

DEBUG:     ! SET $lineWhitespace = ''.
DEBUG:   96+                                             if ( >>>> $scriptLineNumberLength -lt 4) {

DEBUG:   97+                                                  >>>> $lineWhitespace = ' ' * (4 - $scriptLineNumberLength)

DEBUG:     ! SET $lineWhitespace = '   '.
DEBUG:  100+                                              >>>> $verticalBar = '|'

DEBUG:     ! SET $verticalBar = '|'.
DEBUG:  101+                                              >>>> $posmsg += "${accentColor}${headerWhitespace}Line ${verticalBar}${newline}"

DEBUG:     ! SET $posmsg = 'C:\Test-TraceBug.ps1:5
Line |
'.
DEBUG:  103+                                              >>>> $highlightLine = ''

DEBUG:     ! SET $highlightLine = ''.
DEBUG:  104+                                             if ( >>>> $useTargetObject) {

DEBUG:  110+                                                  >>>> $positionMessage = $myinv.PositionMessage.Split($newline)

DEBUG:     ! SET $positionMessage = 'At C:\Test-TraceBug.ps1:5 char:1 + [Custom]::…'.
DEBUG:  111+                                                  >>>> $line = $positionMessage[1].Substring(1) # skip the '+' at the start

DEBUG:     ! SET $line = ' [Custom]::new()'.
DEBUG:  112+                                                  >>>> $highlightLine = $positionMessage[$positionMessage.Count - 1].Substring(1)

DEBUG:     ! SET $highlightLine = ' ~~~~~~~~~~~~~~~'.
DEBUG:  113+                                                  >>>> $offsetLength = $highlightLine.Trim().Length

DEBUG:     ! SET $offsetLength = '15'.
DEBUG:  114+                                                  >>>> $offsetInLine = $highlightLine.IndexOf('~')

DEBUG:     ! SET $offsetInLine = '1'.
DEBUG:  117+                                             if ( >>>> -not $line.EndsWith($newline)) {

DEBUG:  118+                                                  >>>> $line += $newline

DEBUG:     ! SET $line = ' [Custom]::new()
'.
DEBUG:  122+                                             if ( >>>> $offsetLength -lt $line.Length - 1) {

DEBUG:  123+                                                  >>>> $line = $line.Insert($offsetInLine + $offsetLength, $resetColor).Insert($offsetInLine, $accentColor)

DEBUG:     ! SET $line = ' [Custom]::new()
'.
DEBUG:  126+                                              >>>> $posmsg += "${accentColor}${lineWhitespace}${ScriptLineNumber} ${verticalBar} ${resetcolor}${line}"

DEBUG:     ! SET $posmsg = 'C:\Test-TraceBug.ps1:5
Line |
   5 | '.
DEBUG:  127+                                              >>>> $offsetWhitespace = ' ' * $offsetInLine

DEBUG:     ! SET $offsetWhitespace = ' '.
DEBUG:  128+                                              >>>> $prefix = "${accentColor}${headerWhitespace}     ${verticalBar} ${errorColor}"

DEBUG:     ! SET $prefix = '     | '.
DEBUG:  129+                                             if ( >>>> $highlightLine -ne '') {

DEBUG:  130+                                                  >>>> $posMsg += "${prefix}${highlightLine}${newline}"

DEBUG:     ! SET $posMsg = 'C:\Test-TraceBug.ps1:5
Line |
   5 | '.
DEBUG:  132+                                              >>>> $message = "${prefix}"

DEBUG:     ! SET $message = '     | '.
DEBUG:  135+                                         if ( >>>> ! $err.ErrorDetails -or ! $err.ErrorDetails.Message) {

DEBUG:  136+                                             if ( >>>> $err.CategoryInfo.Category -eq 'ParserError' -and $err.Exception.Message.Contains("~$newline")) {

DEBUG:  140+                                             elseif ( >>>> $err.Exception) {

DEBUG:  141+                                                  >>>> $message += $err.Exception.Message

DEBUG:     ! SET $message = '     | Index was out of range. Must be non-…'.
DEBUG:  155+                                         if ( >>>> $myinv -and $myinv.ScriptName -or $err.CategoryInfo.Category -eq 'ParserError') {

DEBUG:  156+                                              >>>> $prefixLength = Get-RawStringLength -string $prefix

DEBUG:   23+                                         function Get-RawStringLength($string)  >>>> {

DEBUG:     ! CALL function 'Get-RawStringLength'
DEBUG:   24+                                              >>>> $vtCodes = "`e[0m", "`e[2;30m", "`e[2;31m", "`e[2;32m", "`e[2;33m", "`e[2;34m",

DEBUG:     ! SET $vtCodes = '       …'.
DEBUG:   28+                                              >>>> $newString = $string

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ($vtCode in  >>>> $vtCodes) {

DEBUG:     ! SET $foreach = 'IEnumerator'.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $vtCode = ''.
DEBUG:   30+                                                  >>>> $newString = $newString.Replace($vtCode, '')

DEBUG:     ! SET $newString = '     | '.
DEBUG:   29+                                             foreach ( >>>> $vtCode in $vtCodes) {

DEBUG:     ! SET $foreach = ''.
DEBUG:   33+                                             return  >>>> $newString.Length

DEBUG:   34+                                          >>>> }

DEBUG:     ! SET $prefixLength = '17'.
DEBUG:  157+                                              >>>> $prefixVtLength = $prefix.Length - $prefixLength

DEBUG:     ! SET $prefixVtLength = '0'.
DEBUG:  160+                                              >>>> $message = $message.Replace($newline, ' ').Replace("`n", ' ').Replace("`t", ' ')

DEBUG:     ! SET $message = '     | Index was out of range. Must be non-…'.
DEBUG:  162+                                              >>>> $windowWidth = 120

DEBUG:     ! SET $windowWidth = '120'.
DEBUG:  163+                                             if ( >>>> $Host.UI.RawUI -ne $null) {

DEBUG:  164+                                                  >>>> $windowWidth = $Host.UI.RawUI.WindowSize.Width

DEBUG:     ! SET $windowWidth = '120'.
DEBUG:  167+                                             if ( >>>> $windowWidth -gt 0 -and ($message.Length - $prefixVTLength) -gt $windowWidth) {

DEBUG:  168+                                                  >>>> $sb = [Text.StringBuilder]::new()

DEBUG:     ! SET $sb = ''.
DEBUG:  169+                                                  >>>> $substring = Get-TruncatedString -string $message -length ($windowWidth + $prefixVTLength)

DEBUG:   37+                                         function Get-TruncatedString($string, [int]$length)  >>>> {

DEBUG:     ! CALL function 'Get-TruncatedString'
DEBUG:   39+                                             if ( >>>> $string.Length -le $length) {

DEBUG:   43+                                             return  >>>> ($string.Substring(0,$length) -split '\s',-2)[0]

DEBUG:   44+                                          >>>> }

DEBUG:     ! SET $substring = '     | Index was out of range. Must be no…'.
DEBUG:  170+                                                  >>>> $null = $sb.Append($substring)

DEBUG:  171+                                                  >>>> $remainingMessage = $message.Substring($substring.Length).Trim()

DEBUG:     ! SET $remainingMessage = ''index')'.
DEBUG:  172+                                                  >>>> $null = $sb.Append($newline)

DEBUG:  173+                                                 while ( >>>> ($remainingMessage.Length + $prefixLength) -gt $windowWidth) {

DEBUG:  188+                                                  >>>> $null = $sb.Append($prefix + $remainingMessage.Trim())

DEBUG:  189+                                                  >>>> $message = $sb.ToString()

DEBUG:     ! SET $message = '     | Index was out of range. Must be non-…'.
DEBUG:  192+                                              >>>> $message += $newline

DEBUG:     ! SET $message = '     | Index was out of range. Must be non-…'.
DEBUG:  195+                                          >>>> $posmsg += "${errorColor}" + $message

DEBUG:     ! SET $posmsg = 'C:\Test-TraceBug.ps1:5
Line |
   5 | '.
DEBUG:  197+                                          >>>> $reason = 'Error'

DEBUG:     ! SET $reason = 'Error'.
DEBUG:  198+                                         if ( >>>> $err.Exception -and $err.Exception.WasThrownFromThrowStatement) {

DEBUG:  202+                                         elseif ( >>>> $myinv.MyCommand -and $myinv.MyCommand.Name -and (Get-Command -Name $myinv.MyCommand -ErrorAction Ignore))

DEBUG:  207+                                         elseif ( >>>> $_.CategoryInfo.Activity) {

DEBUG:  210+                                         elseif ( >>>> $myinv.MyCommand) {

DEBUG:  213+                                         elseif ( >>>> $myinv.InvocationName) {

DEBUG:  216+                                         elseif ( >>>> $err.CategoryInfo.Category) {

DEBUG:  217+                                              >>>> $reason = $err.CategoryInfo.Category

DEBUG:     ! SET $reason = 'OperationStopped'.
DEBUG:  223+                                          >>>> $errorMsg = 'Error'

DEBUG:     ! SET $errorMsg = 'Error'.
DEBUG:  225+                                          >>>> "${errorColor}${reason}: ${posmsg}${resetcolor}"

DEBUG:  226+                                      >>>> }

DEBUG:    1+ &  >>>> { Set-StrictMode -Version 1; $this.Exception.InnerException.PSMessageDetails }
DEBUG:     ! CALL function '<ScriptBlock>'
DEBUG:    1+ & {  >>>> Set-StrictMode -Version 1; $this.Exception.InnerException.PSMessageDetails }
DEBUG:    1+ & { Set-StrictMode -Version 1;  >>>> $this.Exception.InnerException.PSMessageDetails }
DEBUG:    1+ & { Set-StrictMode -Version 1; $this.Exception.InnerException.PSMessageDetails  >>>> }
OperationStopped: C:\Test-TraceBug.ps1:5
Line |
   5 |  [Custom]::new()
     |  ~~~~~~~~~~~~~~~
     | Index was out of range. Must be non-negative and less than the size of the collection. (Parameter
     | 'index')

PS C:\>

Error details

PS C:\> Get-Error

Exception             :
    Type       : System.ArgumentOutOfRangeException
    Message    : Index was out of range. Must be non-negative and less than the size of the collection. (Parameter
'index')
    ParamName  : index
    TargetSite :
        Name          : Insert
        DeclaringType : System.Text.StringBuilder
        MemberType    : Method
        Module        : System.Private.CoreLib.dll
    Data       : System.Collections.ListDictionaryInternal
    Source     : System.Private.CoreLib
    HResult    : -2146233086
    StackTrace :
   at System.Text.StringBuilder.Insert(Int32 index, String value)
   at System.Management.Automation.Language.PositionUtilities.BriefMessage(IScriptPosition position)
   at System.Management.Automation.ScriptDebugger.TraceLine(IScriptExtent extent)
   at System.Management.Automation.ScriptDebugger.OnSequencePointHit(FunctionContext functionContext)
   at System.Management.Automation.ScriptDebugger.EnterScriptFunction(FunctionContext functionContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
   at System.Management.Automation.ScriptBlock.InvokeWithPipeImpl(ScriptBlockClauseToInvoke clauseToInvoke, Boolean
createLocalScope, Dictionary`2 functionsToDefine, List`1 variablesToDefine, ErrorHandlingBehavior
errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo
invocationInfo, Object[] args)
   at System.Management.Automation.ScriptBlock.InvokeWithPipe(Boolean useLocalScope, ErrorHandlingBehavior
errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo
invocationInfo, Boolean propagateAllExceptionsToTop, List`1 variablesToDefine, Dictionary`2 functionsToDefine,
Object[] args)
   at System.Management.Automation.ScriptBlock.InvokeAsMemberFunction(Object instance, Object[] args)
   at System.Management.Automation.Internal.ScriptBlockMemberMethodWrapper.InvokeHelper(Object instance, Object
sessionStateInternal, Object[] args)
   at CallSite.Target(Closure , CallSite , Type )
   at System.Management.Automation.Interpreter.DynamicInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
CategoryInfo          : OperationStopped: (:) [], ArgumentOutOfRangeException
FullyQualifiedErrorId : System.ArgumentOutOfRangeException
InvocationInfo        :
    ScriptLineNumber : 5
    OffsetInLine     : 1
    HistoryId        : -1
    ScriptName       : C:\Test-TraceBug.ps1
    Line             : [Custom]::new()

    PositionMessage  : At C:\Test-TraceBug.ps1:5 char:1
                       + [Custom]::new()
                       + ~~~~~~~~~~~~~~~
    PSScriptRoot     : C:\
    PSCommandPath    : C:\Test-TraceBug.ps1
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, C:\Test-TraceBug.ps1: line 5
                        at <ScriptBlock>, <No file>: line 1

PS C:\>

Environment data

PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.2.1
PSEdition                      Core
GitCommitId                    7.2.1
OS                             Microsoft Windows 10.0.17763
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Winver:

Microsoft Windows Server
Version 1809 (OS Build 17763.2565)

OR

PS /> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.2.1
PSEdition                      Core
GitCommitId                    7.2.1
OS                             Linux 4.4.0-19041-Microsoft #1237-Microsoft Sat Sep 11 14:32:00 PST 2021
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

PS /> Get-Content /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
PS /> Get-Content /etc/debian_version
11.2

Visuals

No response

iSazonov commented 2 years ago

Debug show the trace throws on empty script block.

kasini3000 commented 2 years ago

I can reproduced the problem on both 【ps 5.1】 and 【ps 6.2.7】

daxian-dbw commented 2 years ago

The Engine Working Group reviewed this issue and agree it's a bug that needs to be fixed.

ghost commented 1 year ago

I'm now encountering a case where custom classes with no explicit constructor trigger this issue as well. The classes are derived from a parent that also has no explicit constructor; I don't know if that's part of why. I am able to work around it by adding explicit 0-argument constructors with the body {return}:

CustomBase {
  [object] AbstractMethod() {
    throw "Abstract method not implemented."
  }
  CustomBase() {return}
}

Custom : CustomBase {
  [object] AbstractMethod() {
    # Some implementation.
  }
  Custom() {return}
}

This seems to support that the issue has something to do with empty blocks; I assume the default implicit constructor is {}.

iSazonov commented 1 year ago

@daxian-dbw I could refactor internal static string BriefMessage(IScriptPosition position) method if you don't see more depth problem.

daxian-dbw commented 1 year ago

@iSazonov I haven't yet got a chance to understand the root cause. Will try taking a look next week.

ghost commented 1 year ago

Line 278 of Position.cs is the obvious starting point for the blame game, seeing as it's the only Insert() call in BriefMessage(). I assume that, for an empty block, the trace position is at column 0, so -1 is passed as the insert offset. Special-casing column 0 (and... negative columns??) is one fix, but maybe that should never happen; I'm obviously not familiar with how tracing is supposed to work internally. It also might be that position 0 is invalid in an empty string builder, in which case the line being empty needs handling or should be prevented from happening...

Amendment: Checked, position 0 is legal in empty string builders and does what you'd expect.

microsoft-github-policy-service[bot] commented 6 months ago

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

microsoft-github-policy-service[bot] commented 6 months ago

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

fflaten commented 2 weeks ago

Please reopen. Still an issue