crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.26k stars 1.61k forks source link

Crystal runtime crashes on closed file descriptor for STDIN #14569

Closed straight-shoota closed 1 month ago

straight-shoota commented 2 months ago

As part of programm startup, the Crystal runtime initializes handles for the three standard streams. If such a stream is already closed, the runtime crashes.

This affects any Crystal program which uses STDIN somehow (i.e. the constant is initialized).

A minimal reproduction is crystal <&- (the shell redirection <&- instructs that stdin is to be closed). This results in the following error:

Unhandled exception: Unable to get info: Bad file descriptor (IO::Error)
  from /opt/homebrew/Cellar/crystal/1.12.1_1/bin/crystal in 'raise<IO::Error>:NoReturn'
  from /opt/homebrew/Cellar/crystal/1.12.1_1/bin/crystal in 'Crystal::System::FileDescriptor::system_info<Int32>:File::Info'
  from /opt/homebrew/Cellar/crystal/1.12.1_1/bin/crystal in 'IO::FileDescriptor::new<Int32>:IO::FileDescriptor'
  from /opt/homebrew/Cellar/crystal/1.12.1_1/bin/crystal in 'IO::FileDescriptor::from_stdio<Int32>:IO::FileDescriptor'
  from /opt/homebrew/Cellar/crystal/1.12.1_1/bin/crystal in '__crystal_main'
  from /opt/homebrew/Cellar/crystal/1.12.1_1/bin/crystal in 'main'

The same error does not appear when passing a closed output file descriptor (crystal >&-).

I'm not sure how to reproduce in pure Crystal yet. Passing a closed IO to Process.run errors on the invoking process (Closed stream from Process#copy_io). This needs to be fixed as well.

stdin = IO::Memory.new
stdin.close
Process.run("crystal", input: stdin, output: :inherit, error: :inherit)

This was originally reported in https://forum.crystal-lang.org/t/unable-to-get-info-bad-file-descriptor-io-error/6820

straight-shoota commented 2 months ago

Interestingly, Process::Redirect::Close does not actually close the file descriptor. It only passes the null device (i.e. it's equivalent to crystal < /dev/null). A closed file descriptor equivalent to the shell redirection apparently <&- has different semantics.

crysbot commented 2 months ago

This issue has been mentioned on Crystal Forum. There might be relevant details there:

https://forum.crystal-lang.org/t/unable-to-get-info-bad-file-descriptor-io-error/6820/4

crysbot commented 2 months ago

This issue has been mentioned on Crystal Forum. There might be relevant details there:

https://forum.crystal-lang.org/t/unable-to-get-info-bad-file-descriptor-io-error/6820/12