Permalink
Browse files

Ensure VM doesn't improperly unwind into a process exit.

  • Loading branch information...
Brian Ford
Brian Ford committed Mar 3, 2011
1 parent 495e015 commit 2a2bbf1d70d5bcd49648b7d967166061256f4a84
@@ -105,4 +105,9 @@ def self.agent_io
Ruby.primitive :vm_agent_io
raise PrimitiveFailure, "Rubinius.agent_io failed"
end
+
+ def self.thread_state
+ Ruby.primitive :vm_thread_state
+ raise PrimitiveFailure, "Rubinius.thread_state failed"
+ end
end
@@ -2,6 +2,7 @@ module Rubinius
class VariableScope
attr_reader :parent
attr_reader :block
+ attr_reader :module
# CompiledMethod this scope is for.
#
View
@@ -636,6 +636,31 @@ def epilogue
# Exit.
def done
+ # check that this is a valid exit rather than failing to process
+ # unwinding properly.
+ #
+ # TODO: this code is pretty gross, nice object inspectors, please.
+ thread_state = Rubinius.thread_state
+ reason = thread_state[0]
+ unless reason == :none
+ STDERR.puts "\nERROR: the VM is exiting improperly"
+ STDERR.puts "intended operation: #{reason.inspect}"
+ STDERR.puts "associated value: #{thread_state[1].inspect}"
+ destination = thread_state[2]
+ method = destination.method
+ STDERR.puts "destination scope:"
+ STDERR.puts " method: #{method.name} at #{method.file}:#{method.first_line}"
+ STDERR.puts " module: #{destination.module.name}"
+ STDERR.puts " block: #{destination.block}" if destination.block
+ if reason == :catch_throw
+ STDERR.puts "throw destination: #{thread_state[4].inspect}"
+ end
+ if exception = thread_state[3]
+ exception.render
+ end
+ @exit_code = 1
+ end
+
Process.exit! @exit_code
end
@@ -714,10 +739,10 @@ def self.main
begin
new.main
rescue Object => exc
- puts "\n====================================="
- puts "Exception occurred during top-level exception output! (THIS IS BAD)"
- puts
- puts "Exception: #{exc.inspect} (#{exc.class})"
+ STDERR.puts "\n====================================="
+ STDERR.puts "Exception occurred during top-level exception output! (THIS IS BAD)"
+ STDERR.puts
+ STDERR.puts "Exception: #{exc.inspect} (#{exc.class})"
end
end
end
@@ -3,11 +3,12 @@
describe "Rubinius::Loader.main" do
before :each do
- @stdout, $stdout = $stdout, IOStub.new
+ @stderr = STDERR
+ Object.const_set :STDERR, IOStub.new
end
after :each do
- $stdout = @stdout
+ Object.const_set :STDERR, @stderr
end
it "catches any uncaught exceptions raised while running" do
@@ -17,7 +18,7 @@
Rubinius::Loader.main
- $stdout.should == <<-EOM
+ STDERR.should == <<-EOM
=====================================
Exception occurred during top-level exception output! (THIS IS BAD)
View
@@ -1081,4 +1081,41 @@ namespace rubinius {
return String::create(state, buf, 40);
}
+
+ Tuple* System::vm_thread_state(STATE) {
+ ThreadState* ts = state->thread_state();
+ Tuple* tuple = Tuple::create(state, 5);
+
+ Symbol* reason = 0;
+ switch(ts->raise_reason()) {
+ case cNone:
+ reason = state->symbol("none");
+ break;
+ case cException:
+ reason = state->symbol("exception");
+ break;
+ case cReturn:
+ reason = state->symbol("return");
+ break;
+ case cBreak:
+ reason = state->symbol("break");
+ break;
+ case cExit:
+ reason = state->symbol("exit");
+ break;
+ case cCatchThrow:
+ reason = state->symbol("catch_throw");
+ break;
+ default:
+ reason = state->symbol("unknown");
+ }
+
+ tuple->put(state, 0, reason);
+ tuple->put(state, 1, ts->raise_value());
+ tuple->put(state, 2, ts->destination_scope());
+ tuple->put(state, 3, ts->current_exception());
+ tuple->put(state, 4, ts->throw_dest());
+
+ return tuple;
+ }
}
View
@@ -277,6 +277,9 @@ namespace rubinius {
// Ruby.primitive :sha1_hash
static String* sha1_hash(STATE, String* str);
+ // Ruby.primitive :vm_thread_state
+ static Tuple* vm_thread_state(STATE);
+
public: /* Type info */
class Info : public TypeInfo {

0 comments on commit 2a2bbf1

Please sign in to comment.