bool CanContinue() const;
/**
+ * Throws the exception caught by this TryCatch in a way that avoids
+ * it being caught again by this same TryCatch. As with ThrowException
+ * it is illegal to execute any JavaScript operations after calling
+ * ReThrow; the caller must return immediately to where the exception
+ * is caught.
+ */
+ Handle<Value> ReThrow();
+
+ /**
* Returns the exception caught by this try/catch block. If no exception has
* been caught an empty handle is returned.
*
TryCatch* next_;
void* exception_;
void* message_;
- bool is_verbose_;
- bool can_continue_;
- bool capture_message_;
+ bool is_verbose_ : 1;
+ bool can_continue_ : 1;
+ bool capture_message_ : 1;
+ bool rethrow_ : 1;
void* js_handler_;
};
is_verbose_(false),
can_continue_(true),
capture_message_(true),
+ rethrow_(false),
js_handler_(NULL) {
i::Top::RegisterTryCatchHandler(this);
}
v8::TryCatch::~TryCatch() {
- i::Top::UnregisterTryCatchHandler(this);
+ if (rethrow_) {
+ v8::HandleScope scope;
+ v8::Local<v8::Value> exc = v8::Local<v8::Value>::New(Exception());
+ i::Top::UnregisterTryCatchHandler(this);
+ v8::ThrowException(exc);
+ } else {
+ i::Top::UnregisterTryCatchHandler(this);
+ }
}
}
+v8::Handle<v8::Value> v8::TryCatch::ReThrow() {
+ if (!HasCaught()) return v8::Local<v8::Value>();
+ rethrow_ = true;
+ return v8::Undefined();
+}
+
+
v8::Local<Value> v8::TryCatch::Exception() const {
if (HasCaught()) {
// Check for out of memory exception.
}
}
}
+
+
+static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
+ v8::HandleScope scope;
+ v8::TryCatch tc;
+ v8::Handle<v8::String> str = args[0]->ToString();
+ if (tc.HasCaught())
+ return tc.ReThrow();
+ return v8::Undefined();
+}
+
+
+// Test that a stack overflow can be propagated down through a spaghetti
+// stack using ReThrow.
+THREADED_TEST(SpaghettiStackOverflow) {
+ v8::HandleScope scope;
+ LocalContext context;
+ context->Global()->Set(
+ v8::String::New("s"),
+ v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
+ v8::TryCatch try_catch;
+ CompileRun("var o = {toString: function () {return s(o);}}; s(o);");
+ CHECK(try_catch.HasCaught());
+ v8::String::Utf8Value value(try_catch.Exception());
+ CHECK_NE(0, strstr(*value, "RangeError"));
+}