Repository navigation
Handle InvalidOperationException from Console.ReadKey #3744
Description
Description of the new feature/enhancement
Under certain (unexpected) circumstances the Console.ReadKey and KeyAvailable APIs can throw an InvalidOperationException. See: dotnet/runtime#88697
(TL;DR: if a second process attached to the console is also waiting for input, and then is terminated, .NET gets back 0 records, and decides to throw.)
Ideally, that bug would be fixed in .NET. However, it is unclear when or if that will happen. I would like to propose that we update PSReadLine's use of these APIs to handle these situations instead of crashing.
For those who know what "razzle" is: the end goal here is to fix ctrl+c in PowerShell razzle.
(For those who don't know: "razzle" is an internal build environment, in which it is not too hard to hit the situation described in dotnet/runtime#88697.)
Proposed technical implementation details
The general idea is simple: wrap in a try/catch, and if it fails, just reissue the call.
One possible wrinkle: those APIs are expected to throw if the "application does not have a console or when console input has been redirected". I would not expect PSReadLine to come into play at all in such a case. Since a user script/module has no opportunity to catch the exception, such an exception should always crash the process. But it could be possible that someone is depending on this behavior (to crash in a console-input-redirected case)... in which case, we could try to detect this (not sure off the top of my head how) or adopt a heuristic, like "if the operation throws 5 times in a row, give up and let the exception fly". Let me know if you think going to such lengths is necessary.
Exhibit A: stack trace when the problem is hit:
An error has occurred that was not properly handled. Additional information is shown below. The PowerShell process will exit.
Unhandled exception. System.InvalidOperationException: Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read.
at System.ConsolePal.ReadKey(Boolean intercept)
at Microsoft.PowerShell.PSConsoleReadLine.ReadOneOrMoreKeys()
at Microsoft.PowerShell.PSConsoleReadLine.ReadKeyThreadProc()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
Activity
jazzdelightsme commentedon Jul 15, 2023
Note: this problem is the biggest obstacle preventing the ConsoleBouncer project from being reliable: https://github.com/jazzdelightsme/ConsoleBouncer#:~:text=May%20crash%20your%20shell
StevenBucher98 commentedon Jul 24, 2023
Dan Thompson (@jazzdelightsme) would you be willing to create a PR and see if that fixes your problems? We are also wanting to make sure it doesn't break any other scenarios with PSRL.
daxian-dbw commentedon Jul 24, 2023
Right, PSReadLine doesn't support the case where either
stdinorstdoutis redirected:PSReadLine/PSReadLine/ReadLine.cs
Lines 333 to 346 in c48f77d
So, this sounds like an acceptable change. Can you please submit a PR so we can take a closer look at the proposed changes?
Work around InvalidOperationExceptions from Console API
daxian-dbw commentedon Jul 27, 2023
Closed via #3755