Skip to content

Commit da8a9bd

Browse files
Fix Process.run with closed IO (#14698)
IOs passed to `Process.run` experience some indirection which blew up if an IO is closed. This patch ensures that closed IOs are handled correctly. * A closed IO that is not a `IO::FileDescriptor` is replaced with a closed file descriptor * A closed file descriptor won't be reopened in the new process
1 parent 7e33ecc commit da8a9bd

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

spec/std/process_spec.cr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ pending_interpreted describe: Process do
181181
$?.exit_code.should eq(0)
182182
end
183183

184+
it "forwards closed io" do
185+
closed_io = IO::Memory.new
186+
closed_io.close
187+
Process.run(*stdin_to_stdout_command, input: closed_io)
188+
Process.run(*stdin_to_stdout_command, output: closed_io)
189+
Process.run(*stdin_to_stdout_command, error: closed_io)
190+
end
191+
184192
it "sets working directory with string" do
185193
parent = File.dirname(Dir.current)
186194
command = {% if flag?(:win32) %}

src/crystal/system/unix/process.cr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ struct Crystal::System::Process
337337
end
338338

339339
private def self.reopen_io(src_io : IO::FileDescriptor, dst_io : IO::FileDescriptor)
340+
if src_io.closed?
341+
dst_io.close
342+
return
343+
end
344+
340345
src_io = to_real_fd(src_io)
341346

342347
dst_io.reopen(src_io)

src/process.cr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,14 @@ class Process
294294
when IO::FileDescriptor
295295
stdio
296296
when IO
297+
if stdio.closed?
298+
if dst_io == STDIN
299+
return File.open(File::NULL, "r").tap(&.close)
300+
else
301+
return File.open(File::NULL, "w").tap(&.close)
302+
end
303+
end
304+
297305
if dst_io == STDIN
298306
fork_io, process_io = IO.pipe(read_blocking: true)
299307

0 commit comments

Comments
 (0)