Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix and specs for crash in Spawn#limit_io on MRI 1.9.3.

  • Loading branch information...
commit 01381280ac32f94378b8a37518065fadf2b388de 1 parent 8f3f2e5
@pwnall authored
View
13 lib/exec_sandbox/spawn.rb
@@ -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
View
15 spec/exec_sandbox/spawn_spec.rb
@@ -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
@@ -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
View
2  spec/fixtures/fork.rb
@@ -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]) }
View
3  spec/spec_helper.rb
@@ -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}
Please sign in to comment.
Something went wrong with that request. Please try again.