Prerequisites
Steps to reproduce
The problem occurs in the update-notification formatting path when the UI culture is zh-Hans.
I originally encountered the crash with PowerShell 7.7.0-preview.4 when a newer preview release became eligible for notification.
The relevant code is in:
src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.cs
inside UpdatesNotification.ShowUpdateNotification():
// The first line is longest, if the message changes, this needs to be updated
int line1Length = notificationMsgTemplate.IndexOf('\n');
int line2Length = notificationMsgTemplate.IndexOf('\n', line1Length + 1);
int line3Length = notificationMsgTemplate.IndexOf('\n', line2Length + 1);
line3Length -= line2Length + 1;
line2Length -= line1Length + 1;
line2Padding = line2Padding.PadRight(
line1Length - line2Length + releaseTag.Length
);
// 3 represents the extra placeholder in the template
line3Padding = line3Padding.PadRight(
line1Length - line3Length + 3
);
The code assumes that the first line of the localized notification is the longest.
However, the Simplified Chinese resource in:
src/Microsoft.PowerShell.ConsoleHost/resources/zh-Hans/ManagedEntranceStrings.zh-Hans.resx
contains the following PreviewUpdateNotificationMessage:
{1} 有新的 PowerShell 预览版本可用: v{0} {2}
{1} 立即升级,或访问发布页:{3}{2}
{1} https://aka.ms/PowerShell-Release?tag=v{0} {4}{2}
The issue can be reproduced independently from the notification state with:
$lines = @(
' {1} 有新的 PowerShell 预览版本可用: v{0} {2}'
' {1} 立即升级,或访问发布页:{3}{2}'
' {1} https://aka.ms/PowerShell-Release?tag=v{0} {4}{2}'
)
$lines | ForEach-Object { $_.Length }
# 37
# 24
# 57
$paddingWidth = $lines[0].Length - $lines[2].Length + 3
$paddingWidth
# -17
''.PadRight($paddingWidth)
This produces the same invalid padding width seen in the startup crash:
The exact calculation performed by ShowUpdateNotification() is:
line1Length - line3Length + 3
= 37 - 57 + 3
= -17
Therefore it eventually attempts the equivalent of:
string.Empty.PadRight(-17)
which throws ArgumentOutOfRangeException.
The same formatting logic and the same zh-Hans resource text are still present in the latest preview release, v7.7.0-preview.5.
When an eligible update notification is actually shown, the startup failure is:
Process terminated.
totalWidth ('-17') must be a non-negative value. (Parameter 'totalWidth')
Actual value was -17.
at System.Environment.FailFast(System.Runtime.CompilerServices.StackCrawlMarkHandle, System.String, System.Runtime.CompilerServices.ObjectHandleOnStack, System.String)
at System.Environment.FailFast(System.Threading.StackCrawlMark ByRef, System.String, System.Exception, System.String)
at System.Environment.FailFast(System.String, System.Exception)
at Microsoft.PowerShell.UnmanagedPSEntry.Start(System.String[], Int32)
at Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])
System.ArgumentOutOfRangeException: totalWidth ('-17') must be a non-negative value. (Parameter 'totalWidth')
Actual value was -17.
at System.ArgumentOutOfRangeException.ThrowNegative[T](T value, String paramName)
at System.String.PadRight(Int32 totalWidth, Char paddingChar)
at Microsoft.PowerShell.UpdatesNotification.ShowUpdateNotification(PSHostUserInterface hostUI)
at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, Boolean issProvidedExternally)
at Microsoft.PowerShell.UnmanagedPSEntry.Start(String[] args, Int32 argc)
Setting:
setx POWERSHELL_UPDATECHECK Off
avoids the crash by preventing the update-notification path from running.
Expected behavior
PowerShell should start normally and display the localized update notification.
Notification formatting should work regardless of the relative lengths of localized message lines.
Actual behavior
When the zh-Hans update notification is displayed, ShowUpdateNotification() calculates a negative padding width because the third line is longer than the first line.
For the preview notification resource:
line 1 length = 37
line 3 length = 57
so:
This value is passed to String.PadRight(), which throws ArgumentOutOfRangeException.
Because this happens during console-host startup, the PowerShell process terminates instead of opening an interactive session.
The underlying assumption appears to be this comment in UpdatesNotification.cs:
// The first line is longest, if the message changes, this needs to be updated
That assumption is not valid for all localized resources.
Error details
`Get-Error` cannot be collected from the affected process because the exception occurs during PowerShell console-host startup and the process terminates through `Environment.FailFast()` before an interactive session is available.
The verbatim startup output is:
Process terminated.
totalWidth ('-17') must be a non-negative value. (Parameter 'totalWidth')
Actual value was -17.
at System.Environment.FailFast(System.Runtime.CompilerServices.StackCrawlMarkHandle, System.String, System.Runtime.CompilerServices.ObjectHandleOnStack, System.String)
at System.Environment.FailFast(System.Threading.StackCrawlMark ByRef, System.String, System.Exception, System.String)
at System.Environment.FailFast(System.String, System.Exception)
at Microsoft.PowerShell.UnmanagedPSEntry.Start(System.String[], Int32)
at Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])
System.ArgumentOutOfRangeException: totalWidth ('-17') must be a non-negative value. (Parameter 'totalWidth')
Actual value was -17.
at System.ArgumentOutOfRangeException.ThrowNegative[T](T value, String paramName)
at System.String.PadRight(Int32 totalWidth, Char paddingChar)
at Microsoft.PowerShell.UpdatesNotification.ShowUpdateNotification(PSHostUserInterface hostUI)
at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, Boolean issProvidedExternally)
at Microsoft.PowerShell.UnmanagedPSEntry.Start(String[] args, Int32 argc)
Environment data
PASTE THE VERBATIM OUTPUT OF:
$PSVersionTable
The original startup crash was observed with:
PowerShell 7.7.0-preview.4
The relevant implementation and zh-Hans resource remain unchanged in v7.7.0-preview.5.
Visuals
Not required. The failure occurs during console-host startup and is fully represented by the stack trace above.
Prerequisites
Steps to reproduce
The problem occurs in the update-notification formatting path when the UI culture is
zh-Hans.I originally encountered the crash with PowerShell
7.7.0-preview.4when a newer preview release became eligible for notification.The relevant code is in:
src/Microsoft.PowerShell.ConsoleHost/host/msh/UpdatesNotification.csinside
UpdatesNotification.ShowUpdateNotification():The code assumes that the first line of the localized notification is the longest.
However, the Simplified Chinese resource in:
src/Microsoft.PowerShell.ConsoleHost/resources/zh-Hans/ManagedEntranceStrings.zh-Hans.resxcontains the following
PreviewUpdateNotificationMessage:The issue can be reproduced independently from the notification state with:
This produces the same invalid padding width seen in the startup crash:
The exact calculation performed by
ShowUpdateNotification()is:Therefore it eventually attempts the equivalent of:
which throws
ArgumentOutOfRangeException.The same formatting logic and the same
zh-Hansresource text are still present in the latest preview release,v7.7.0-preview.5.When an eligible update notification is actually shown, the startup failure is:
Setting:
setx POWERSHELL_UPDATECHECK Offavoids the crash by preventing the update-notification path from running.
Expected behavior
PowerShell should start normally and display the localized update notification.
Notification formatting should work regardless of the relative lengths of localized message lines.
Actual behavior
When the
zh-Hansupdate notification is displayed,ShowUpdateNotification()calculates a negative padding width because the third line is longer than the first line.For the preview notification resource:
so:
This value is passed to
String.PadRight(), which throwsArgumentOutOfRangeException.Because this happens during console-host startup, the PowerShell process terminates instead of opening an interactive session.
The underlying assumption appears to be this comment in
UpdatesNotification.cs:// The first line is longest, if the message changes, this needs to be updatedThat assumption is not valid for all localized resources.
Error details
Environment data
PASTE THE VERBATIM OUTPUT OF: $PSVersionTableThe original startup crash was observed with:
The relevant implementation and
zh-Hansresource remain unchanged inv7.7.0-preview.5.Visuals
Not required. The failure occurs during console-host startup and is fully represented by the stack trace above.