Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Powershell 7 crashes when exiting from elixir's iex #11215

Open
SchrodingerZhu opened this issue Nov 29, 2019 · 23 comments
Open

Powershell 7 crashes when exiting from elixir's iex #11215

SchrodingerZhu opened this issue Nov 29, 2019 · 23 comments
Labels
WG-Engine core PowerShell engine, interpreter, and runtime
Projects
Milestone

Comments

@SchrodingerZhu
Copy link

Step:
enter iex by zsh -c 'iex', doube enter Ctrl-C to quit iex.
Behavior:

❯ zsh -c 'iex'
Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]

warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
^CProcess terminated. The process cannot access the file because it is being used by another process.
   at System.Environment.FailFast(System.String, System.Exception)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(System.String, System.String[], Int32)
   at Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])
System.IO.IOException: The process cannot access the file because it is being used by another process.
   at System.ConsolePal.TryGetCursorPosition(Int32& left, Int32& top, Boolean reinitializeForRead)
   at System.Console.get_CursorLeft()
   at Microsoft.PowerShell.ConsoleHostRawUserInterface.get_CursorPosition()
   at Microsoft.PowerShell.ConsoleHost.InputLoop.Run(Boolean inputLoopIsNested)
   at Microsoft.PowerShell.ConsoleHost.InputLoop.RunNewInputLoop(ConsoleHost parent, Boolean isNested)
   at Microsoft.PowerShell.ConsoleHost.EnterNestedPrompt()
   at Microsoft.PowerShell.ConsoleHost.DoRunspaceLoop(String initialCommand, Boolean skipProfiles, Collection`1 initialCommandArgs, Boolean staMode, String configurationName)
   at Microsoft.PowerShell.ConsoleHost.Run(CommandLineParameterParser cpp, Boolean isPrestartWarned)
   at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.ConsoleShell.Start(InitialSessionState initialSessionState, String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.ConsoleShell.Start(String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(String consoleFilePath, String[] args, Int32 argc)

Warning: Program '/usr/bin/pwsh-preview' crashed.

Os info:

Linux ****** 5.3.12-arch1-1 #1 SMP PREEMPT Wed, 20 Nov 2019 19:45:16 +0000 x86_64 GNU/Linux
@SchrodingerZhu SchrodingerZhu added the Issue-Question ideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a label Nov 29, 2019
@iSazonov
Copy link
Collaborator

the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8.

What is locale in your session?

@SchrodingerZhu
Copy link
Author

@iSazonov

❯ locale
LANG=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=
schrodinger@Monad  ~                                                                                                                                                  [11:05]
❯ env LC_ALL=en_US.utf-8 iex
Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]

Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
^CProcess terminated. The process cannot access the file because it is being used by another process.
   at System.Environment.FailFast(System.String, System.Exception)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(System.String, System.String[], Int32)
   at Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])
System.IO.IOException: The process cannot access the file because it is being used by another process.
   at System.ConsolePal.TryGetCursorPosition(Int32& left, Int32& top, Boolean reinitializeForRead)
   at System.Console.get_CursorLeft()
   at Microsoft.PowerShell.ConsoleHostRawUserInterface.get_CursorPosition()
   at Microsoft.PowerShell.ConsoleHost.InputLoop.Run(Boolean inputLoopIsNested)
   at Microsoft.PowerShell.ConsoleHost.InputLoop.RunNewInputLoop(ConsoleHost parent, Boolean isNested)
   at Microsoft.PowerShell.ConsoleHost.EnterNestedPrompt()
   at Microsoft.PowerShell.ConsoleHost.DoRunspaceLoop(String initialCommand, Boolean skipProfiles, Collection`1 initialCommandArgs, Boolean staMode, String configurationName)
   at Microsoft.PowerShell.ConsoleHost.Run(CommandLineParameterParser cpp, Boolean isPrestartWarned)
   at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.ConsoleShell.Start(InitialSessionState initialSessionState, String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.ConsoleShell.Start(String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(String consoleFilePath, String[] args, Int32 argc)

@iSazonov
Copy link
Collaborator

iSazonov commented Dec 2, 2019

@SchrodingerZhu Thanks! Please remove PSReadline (Remove-Module PSReadline) and try again. Also what is a terminal you use?

@SchrodingerZhu
Copy link
Author

SchrodingerZhu commented Dec 2, 2019

still

^CProcess terminated. The process cannot access the file because it is being used by another process.
   at System.Environment.FailFast(System.String, System.Exception)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(System.String, System.String[], Int32)
   at Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])
System.IO.IOException: The process cannot access the file because it is being used by another process.
   at System.ConsolePal.TryGetCursorPosition(Int32& left, Int32& top, Boolean reinitializeForRead)
   at System.Console.get_CursorLeft()
   at Microsoft.PowerShell.ConsoleHostRawUserInterface.get_CursorPosition()
   at Microsoft.PowerShell.ConsoleHost.InputLoop.Run(Boolean inputLoopIsNested)
   at Microsoft.PowerShell.ConsoleHost.InputLoop.RunNewInputLoop(ConsoleHost parent, Boolean isNested)
   at Microsoft.PowerShell.ConsoleHost.EnterNestedPrompt()
   at Microsoft.PowerShell.ConsoleHost.DoRunspaceLoop(String initialCommand, Boolean skipProfiles, Collection`1 initialCommandArgs, Boolean staMode, String configurationName)
   at Microsoft.PowerShell.ConsoleHost.Run(CommandLineParameterParser cpp, Boolean isPrestartWarned)
   at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.ConsoleShell.Start(InitialSessionState initialSessionState, String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.ConsoleShell.Start(String bannerText, String helpText, String[] args)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(String consoleFilePath, String[] args, Int32 argc)

the terminal is konsole

@SchrodingerZhu
Copy link
Author

same error with terminal alacritty.

@iSazonov
Copy link
Collaborator

iSazonov commented Dec 2, 2019

at System.ConsolePal.TryGetCursorPosition(Int32& left, Int32& top, Boolean reinitializeForRead)
at System.Console.get_CursorLeft()

I guess it is .Net Core issue with alacritty.
@rjmholt Thoughts?

@rjmholt
Copy link
Collaborator

rjmholt commented Dec 2, 2019

Looks like an issue with console ownership where PowerShell expects to own the console but does not.

Looks like the place we do this in PowerShell is here. The underlying implementation of that property in *nix is here.

It feels to me like PowerShell is trying to be too clever in this particular instance.

My simplified mental model for how our interactive shell should host another interactive program/shell is that we synchronously cede the console to the subprocess, and then when that subprocess finishes we take it back. I'm imagining that's the intended implementation, so this might be an issue where the ConHost is not waiting for that properly.

It is notable that we don't have this issue generally; just with iex. @SchrodingerZhu what happens if you execute iex directly, without zsh?

/cc @daxian-dbw and @SteveL-MSFT since they are better versed in our console interaction logic

@SteveL-MSFT SteveL-MSFT self-assigned this Dec 2, 2019
@SteveL-MSFT
Copy link
Member

SteveL-MSFT commented Dec 2, 2019

It looks like the problem is that pwsh is sent a SIGTTIN signal (meaning pwsh doesn't have the console, so stop trying to read it), but it's not being handled. I couldn't find how to handle this in .NET Core. Opened dotnet/runtime#452

@SteveL-MSFT SteveL-MSFT removed their assignment Dec 2, 2019
@SteveL-MSFT SteveL-MSFT added this to To do in Shell via automation Dec 2, 2019
@SteveL-MSFT SteveL-MSFT added this to the vNext-Consider milestone Dec 2, 2019
@SteveL-MSFT SteveL-MSFT added Waiting - DotNetCore waiting on a fix/change in .NET and removed Issue-Question ideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a labels Dec 2, 2019
@rjmholt
Copy link
Collaborator

rjmholt commented Dec 3, 2019

@SteveL-MSFT
Copy link
Member

Looks like the recommend solution is to use a Mono library to handle this

@iSazonov
Copy link
Collaborator

iSazonov commented Dec 4, 2019

Why not if it is small library.

@rjmholt
Copy link
Collaborator

rjmholt commented Dec 4, 2019

Why not if it is small library.

While I'd usually propose caution on bringing a new dependency in (both for size and dependency matching reasons), this one seems especially useful to have as a shell, so agree with the proposal.

@daxian-dbw
Copy link
Member

PSReadLine is affected by this too. The call to Console.ReadKey will result in an IOException in this case.

I read a bit more about SIGTTIN and it looks to me the default action for this signal is what we want unless the reading process is ignoring or blocking this signal:

From Access to the Controlling Terminal
When a process in a background job tries to read from its controlling terminal, the process group is usually sent a SIGTTIN signal. This normally causes all of the processes in that group to stop (unless they handle the signal and don’t stop themselves). However, if the reading process is ignoring or blocking this signal, then read fails with an EIO error instead.

And I found this PR: Investigate which signals really need to be blocked on Unix, and this comment indicates SIGTTIN is handled by its default handler, which is Stop (suspend).

According to the description here, SIGTTIN is sent to a background process when it tries to read from the terminal and SIGCONT is sent when the background process is resumed. So I tried the following in bash on Linux:

## run start-sleep first so it's guaranteed that '[Console]::CursorLeft' executes after the pwsh process becomes a background process.
pwsh-preview -c "start-sleep -s 2; Set-Content ~/bb.txt -value value; Add-Content ~/bb.txt -Value ([Console]::CursorLeft)" &

And here is the result

bash:39> pwsh-preview -c "start-sleep -s 2; Set-Content ~/bb.txt -value value; Add-Content ~/bb.txt -Value ([Console]::CursorLeft)" &
[1] 12962
bash:40> cat ~/bb.txt 
value

[1]+  Stopped                 pwsh-preview -c "start-sleep -s 2; Set-Content ~/bb.txt -value value; Add-Content ~/bb.txt -Value ([Console]::CursorLeft)"
bash:41> cat ~/bb.txt 
value
bash:42> fg
pwsh-preview -c "start-sleep -s 2; Set-Content ~/bb.txt -value value; Add-Content ~/bb.txt -Value ([Console]::CursorLeft)"
bash:43> cat ~/bb.txt 
value
0

It looks to me SIGTTIN is handled properly -- pwsh was suspended when reaching [Console]::CursorLeft and resumed after fg brings it to foreground.
So maybe this is not caused by the handling of SIGTTIN? (it seems the default action should just be desired anyways)

@daxian-dbw
Copy link
Member

daxian-dbw commented Dec 19, 2019

Also want to add, this issue has a different repro on WSL (works fine on Ubuntu 16.04), which doesn't involve SIGTTIN signal sending to pwsh:

image

Here, iex runs from bash, then type Ctrl+C twice to exit from it, then start pwsh-preview, and pwsh crashes with the same exception stack.

@SteveL-MSFT
Copy link
Member

Related #8975

@SteveL-MSFT SteveL-MSFT added this to the 7.2-Consider milestone Dec 14, 2020
@SteveL-MSFT SteveL-MSFT added WG-Engine core PowerShell engine, interpreter, and runtime and removed Waiting - DotNetCore waiting on a fix/change in .NET labels Mar 4, 2021
@SteveL-MSFT
Copy link
Member

.NET team is not going to directly support this. @JamesWTruher has a prototype to catch signals and convert to .NET event we can use.

@JamesWTruher
Copy link
Member

Since current dotnet preview now contains code for handling signals, i created a private which handles SIGTTIN and SIGTTOU. Sadly, those signals are not getting delivered in this scenario (no surprise, these are really signals for job control environments which PS is not). On the plus side, i have been able to replicate the behavior in a powershell-free environment. I've opened dotnet/runtime#59059 to see if the dotnet folks can provide some guidance.

@radrow
Copy link

radrow commented Jun 27, 2022

The issue persists for me. However, I managed to workaround it by wraping erl or iex with rlwrap. You may loose some autocompletion, but it is still better than shell crash...

@darthwalsh
Copy link

I ran into this issue by running a build script somebody had written that started with shebang #!/bin/sh -eil If the script fails, my entire terminal tab just disappears! (I guess the "close terminal on shell exit is a setting I can configure, but it's very confusing and disruptive.)

A minimal repro on my mac is running bash -i something will kills the current pwsh instance with a similar, but different IOException: Input/output error (leaving this breadcrumb here in case somebody else google finds this).

$ bash -i something
bash: something: No such file or directory
^[[7;1RProcess terminated. Input/output error
   at System.Environment.FailFast(System.String, System.Exception)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(System.String[], Int32)
   at Microsoft.PowerShell.ManagedPSEntry.Main(System.String[])
System.IO.IOException: Input/output error
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at System.ConsolePal.TryGetCursorPosition(Int32& left, Int32& top, Boolean reinitializeForRead)
   at System.ConsolePal.GetCursorPosition()
   at System.Console.get_CursorLeft()
   at Microsoft.PowerShell.ConsoleHostRawUserInterface.get_CursorPosition()
   at Microsoft.PowerShell.ConsoleHost.InputLoop.Run(Boolean inputLoopIsNested)
   at Microsoft.PowerShell.ConsoleHost.InputLoop.RunNewInputLoop(ConsoleHost parent, Boolean isNested)
   at Microsoft.PowerShell.ConsoleHost.EnterNestedPrompt()
   at Microsoft.PowerShell.ConsoleHost.DoRunspaceLoop(String initialCommand, Boolean skipProfiles, Collection`1 initialCommandArgs, Boolean staMode, String configurationName, String configurationFilePath)
   at Microsoft.PowerShell.ConsoleHost.Run(CommandLineParameterParser cpp, Boolean isPrestartWarned)
   at Microsoft.PowerShell.ConsoleHost.Start(String bannerText, String helpText, Boolean issProvidedExternally)
   at Microsoft.PowerShell.UnmanagedPSEntry.Start(String[] args, Int32 argc)
[Process completed]

Since I'm not expecting this to be fixed anytime soon, is there some ugly workaround I can put into my powershell profile to prevent my shell process from dying? I tried "I'll start a second pwsh, so the outer pwsh process doesn't die," but both pwsh processes crash D: I googled around and hoped to find something with the terms "pwsh PosixSignal" but didn't find anything good.

@SteveL-MSFT
Copy link
Member

Unfortunately we likely need .NET to make a change here to handle signals. As for a workaround, I can't think of one if you need to explicitly have the nested shell interactive. If you can not request it to be interactive, that would not expose the issue.

@JamesWTruher
Copy link
Member

i believe that this is actually a dotnet issue, and I've opened: dotnet/runtime#59059 to track

@radrow
Copy link

radrow commented Nov 8, 2023

Shouldn't this be closed in that case?

@microsoft-github-policy-service microsoft-github-policy-service bot added the Resolution-No Activity Issue has had no activity for 6 months or more label May 7, 2024
@darthwalsh
Copy link

Having your shell process just crash feels pretty bad.

The issue seems to still be blocked on dotnet/runtime#59059 (which was prioritized to top of backlog last release, but maybe needs another bump.)

@microsoft-github-policy-service microsoft-github-policy-service bot removed the Resolution-No Activity Issue has had no activity for 6 months or more label May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WG-Engine core PowerShell engine, interpreter, and runtime
Projects
Shell
  
To do
Development

No branches or pull requests

9 participants