Powershell: Finally clause can be canceled with CTRL + C

Created on 28 Aug 2019  路  5Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

try { } finally {
    Write-Host Press ctrl c now
    Start-Sleep 5
    Write-Host You`'ll never see this one
}

Evaluate the above script and press CTRL + C after the message is displayed.

Expected behavior

The entire finally block to complete.

Actual behavior

The finally block is cancelled when CTRL + C is pressed.

Environment data

Name                           Value
----                           -----
PSVersion                      7.0.0-preview.3
PSEdition                      Core
GitCommitId                    7.0.0-preview.3
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

This also occurs on Windows PowerShell 5.1

Notes

If CTRL + C is pressed in the try block, additional key presses in the finally block will be correctly ignored. e.g.

try {
    Write-Host Press ctrl c now
    Start-Sleep 5
} finally {
    Write-Host Try pressing it a bunch, won`'t do anything
    Start-Sleep 5
    Write-Host You`'ll actually see this one
}
Issue-Discussion WG-Engine

Most helpful comment

From a user perspective, that might make sense.

From a module author's perspective, that stance could be really dangerous. Sure, it might be what the user wants, but usually the things you put in a finally block are pretty important. Cancelling a finally block can lead to corrupted data, memory leaks (objects can't be disposed properly), among a host of other problems.

This should be fixed.

All 5 comments

@SteveL-MSFT @daxian-dbw this is... fairly serious, no? Being able to cancel a finally block seems _super_ not a good thing. 馃槮

Looks like there's no real system to handle "delaying" stops.

The example in the notes works mostly by accident. In ConsoleHost, ^c spins up a thread that handles stops the current pipeline and waits for it to finish. In that handler, if that thread already exists it just returns early. So the notes example only works because ConsoleHost thinks it's a duplicate stop request.

A possible way to fix this would be to:

  1. Add a new field to LocalPipeline called _areStopsDisabled
  2. Add another field to LocalPipeline called _wasStopReceivedWhileDisabled with a better name
  3. Change LocalPipeline.CoreStop to check if _areStopsDisabled and to instead set _wasStopReceivedWhileDisabled if true
  4. Change the expression generated by the compiler for a finally block to set LocalPipeline._areStopsDisabled before the body, and to throw PipelineStoppedException after the body if _wasStopReceivedWhileDisabled is true
  5. Figure out how to do all that while accounting for nested try/finally blocks

I guess it is not issue for background scripts like task scheduled.
For interactive session it could not big issue too - users press Ctrl-C most often when the script freezes and it can freezes in finally block too.

I pretty much agree with @iSazonov - I don't think it's really a big issue. Once you hit ctrl-C, your shell is in an inconsistent state. Because that's how interactive shells work. If you're running a batch script/task or whatever, no one is hitting ctrl-C because - well - it's not interactive. The ctrl-C implementation in PowerShell is a pretty controlled compared to the first implementation (which simply terminated the thread.)

But if one was to change anything, there is a single value that represents the fact that the shell is stopping. Just save that value away in the finally clause then restore once finally is done. But wait - what if the user hit's stop again!?! That usually means that they really want it to stop. So the finalizer is interrupted. Well - that's what the user wanted. I don't have a problem with that.

From a user perspective, that might make sense.

From a module author's perspective, that stance could be really dangerous. Sure, it might be what the user wants, but usually the things you put in a finally block are pretty important. Cancelling a finally block can lead to corrupted data, memory leaks (objects can't be disposed properly), among a host of other problems.

This should be fixed.

Was this page helpful?
0 / 5 - 0 ratings