Skip to content

Commit

Permalink
Fix and specs for crash in Spawn#limit_io on MRI 1.9.3.
Browse files Browse the repository at this point in the history
  • Loading branch information
pwnall committed Feb 9, 2012
1 parent 8f3f2e5 commit 0138128
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 2 deletions.
13 changes: 12 additions & 1 deletion lib/exec_sandbox/spawn.rb
Expand Up @@ -65,7 +65,18 @@ def self.limit_io(io)
redirected_fds = Set.new redirects.map(&:first)
max_fd = LibC.getdtablesize
0.upto(max_fd) do |fd|
LibC.close fd unless redirected_fds.include?(fd)
next if redirected_fds.include?(fd)

# TODO(pwnall): this is slow; consider detecting the Ruby version and
# only running it on buggy MRIs
begin
# This fails if rb_reserved_fd_p returns 0.
# In that case, we shouldn't close the FD, otherwise the VM will crash.
IO.new(fd)
rescue ArgumentError, Errno::EBADF
next
end
LibC.close fd
end
end

Expand Down
15 changes: 14 additions & 1 deletion spec/exec_sandbox/spawn_spec.rb
Expand Up @@ -13,8 +13,20 @@
@temp_in.close
@temp_out = Tempfile.new 'exec_sandbox_rspec'
@temp_out.close

# Force-creating a 2nd thread to make MRI 1.9.3 crash without our fix.
@lock = Mutex.new
@lock.lock
Thread.new do
loop do
sleep 0.1
break if @lock.try_lock
end
@lock.unlock
end
end
after do
@lock.unlock
@temp_in.unlink
@temp_out.unlink
end
Expand All @@ -37,7 +49,8 @@
describe 'with paths' do
before do
pid = ExecSandbox::Spawn.spawn bin_fixture(:duplicate),
{:in => @temp_in.path, :out => @temp_out.path}
{:in => @temp_in.path, :out => @temp_out.path,
:err => @temp_out.path}
@status = ExecSandbox::Wait4.wait4 pid
end

Expand Down
2 changes: 2 additions & 0 deletions spec/fixtures/fork.rb
Expand Up @@ -11,7 +11,9 @@
0.upto(proc_count - 1) do |i|
pids[i] = fork do
f.write '+'
f.close
sleep 1
exit
end
end
0.upto(proc_count - 1) { |i| Process.waitpid(pids[i]) }
Expand Down
3 changes: 3 additions & 0 deletions spec/spec_helper.rb
Expand Up @@ -3,6 +3,9 @@
require 'rspec'
require 'exec_sandbox'

# Spawn tests use threads to test against an MRI 1.9.3 crash.
require 'thread'

# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
Expand Down

0 comments on commit 0138128

Please sign in to comment.