From ab09bfdf102db3e8229a9cba1cd402c8925d3394 Mon Sep 17 00:00:00 2001 From: Randy Stauner Date: Tue, 12 May 2026 11:43:52 -0700 Subject: [PATCH] Close stdin immediately when using popen2e It's good hygiene to close the stdin pipe as soon as you are done writing to it. This can happen for example if "ruby extconf.rb" spawns another process (for example "cargo build", which may spawn arbitrary commands to fetch credentials) and any of those subprocesses attempt to read STDIN until it is closed. We can close it as soon as it's created since we aren't writing to it at all. --- lib/rubygems/ext/builder.rb | 3 ++- test/rubygems/test_gem_ext_builder.rb | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 62d36bcf48d3..e00cf159da3e 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -102,7 +102,8 @@ def self.run(command, results, command_name = nil, dir = Dir.pwd, env = {}) # Set $SOURCE_DATE_EPOCH for the subprocess. build_env = { "SOURCE_DATE_EPOCH" => Gem.source_date_epoch_string }.merge(env) output, status = begin - Open3.popen2e(build_env, *command, chdir: dir) do |_stdin, stdouterr, wait_thread| + Open3.popen2e(build_env, *command, chdir: dir) do |stdin, stdouterr, wait_thread| + stdin.close output = String.new while line = stdouterr.gets output << line diff --git a/test/rubygems/test_gem_ext_builder.rb b/test/rubygems/test_gem_ext_builder.rb index 5fcbc3e2acfd..37204f3c472a 100644 --- a/test/rubygems/test_gem_ext_builder.rb +++ b/test/rubygems/test_gem_ext_builder.rb @@ -106,6 +106,22 @@ def test_custom_make_with_options assert_match(/install: OK/, results) end + def test_class_run_closes_stdin + results = [] + check_stdin_script = <<~'RUBY' + if IO.select([STDIN], nil, nil, 1) + puts "STDIN: #{STDIN.read.inspect}" + else + puts "NOT_READY" + end + RUBY + + Gem::Ext::Builder.run([Gem.ruby, "-e", check_stdin_script], results) + + command_output = results.last + assert_equal "STDIN: \"\"\n", command_output + end + def test_build_extensions pend "terminates on mswin" if vc_windows? && ruby_repo?