Commit 6cb90020 authored by yurys@chromium.org's avatar yurys@chromium.org

V8 can clear exception pending message, when should not do this.

The case:
v8::TryCatch try_catch;
CompileRun(try { CEvaluate('throw 1;'); } finally {});
CHECK(try_catch.HasCaught());
CHECK(!try_catch.Message().IsEmpty());

CEvaluate is native call. Last check is not passed without patch. Patch contains test TryCatchFinallyStoresMessageUsingTryCatchHandler with more details.

R=yangguo@chromium.org, mstarzinger@chromium.org, vsevik@chromium.org

Review URL: https://codereview.chromium.org/321763002

Patch from Alexey Kozyatinskiy <kozyatinskiy@google.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21755 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6ca63336
...@@ -1166,20 +1166,15 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) { ...@@ -1166,20 +1166,15 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) {
} }
bool Isolate::IsExternallyCaught() { bool Isolate::HasExternalTryCatch() {
ASSERT(has_pending_exception()); ASSERT(has_pending_exception());
if ((thread_local_top()->catcher_ == NULL) || return (thread_local_top()->catcher_ != NULL) &&
(try_catch_handler() != thread_local_top()->catcher_)) { (try_catch_handler() == thread_local_top()->catcher_);
// When throwing the exception, we found no v8::TryCatch }
// which should care about this exception.
return false;
}
if (!is_catchable_by_javascript(pending_exception())) {
return true;
}
bool Isolate::IsFinallyOnTop() {
// Get the address of the external handler so we can compare the address to // Get the address of the external handler so we can compare the address to
// determine which one is closer to the top of the stack. // determine which one is closer to the top of the stack.
Address external_handler_address = Address external_handler_address =
...@@ -1199,18 +1194,18 @@ bool Isolate::IsExternallyCaught() { ...@@ -1199,18 +1194,18 @@ bool Isolate::IsExternallyCaught() {
StackHandler::FromAddress(Isolate::handler(thread_local_top())); StackHandler::FromAddress(Isolate::handler(thread_local_top()));
while (handler != NULL && handler->address() < external_handler_address) { while (handler != NULL && handler->address() < external_handler_address) {
ASSERT(!handler->is_catch()); ASSERT(!handler->is_catch());
if (handler->is_finally()) return false; if (handler->is_finally()) return true;
handler = handler->next(); handler = handler->next();
} }
return true; return false;
} }
void Isolate::ReportPendingMessages() { void Isolate::ReportPendingMessages() {
ASSERT(has_pending_exception()); ASSERT(has_pending_exception());
PropagatePendingExceptionToExternalTryCatch(); bool can_clear_message = PropagatePendingExceptionToExternalTryCatch();
HandleScope scope(this); HandleScope scope(this);
if (thread_local_top_.pending_exception_ == if (thread_local_top_.pending_exception_ ==
...@@ -1237,7 +1232,7 @@ void Isolate::ReportPendingMessages() { ...@@ -1237,7 +1232,7 @@ void Isolate::ReportPendingMessages() {
} }
} }
} }
clear_pending_message(); if (can_clear_message) clear_pending_message();
} }
...@@ -1742,14 +1737,22 @@ void Isolate::InitializeThreadLocal() { ...@@ -1742,14 +1737,22 @@ void Isolate::InitializeThreadLocal() {
} }
void Isolate::PropagatePendingExceptionToExternalTryCatch() { bool Isolate::PropagatePendingExceptionToExternalTryCatch() {
ASSERT(has_pending_exception()); ASSERT(has_pending_exception());
bool external_caught = IsExternallyCaught(); bool has_external_try_catch = HasExternalTryCatch();
thread_local_top_.external_caught_exception_ = external_caught; if (!has_external_try_catch) {
thread_local_top_.external_caught_exception_ = false;
return true;
}
if (!external_caught) return; bool catchable_by_js = is_catchable_by_javascript(pending_exception());
if (catchable_by_js && IsFinallyOnTop()) {
thread_local_top_.external_caught_exception_ = false;
return false;
}
thread_local_top_.external_caught_exception_ = true;
if (thread_local_top_.pending_exception_ == if (thread_local_top_.pending_exception_ ==
heap()->termination_exception()) { heap()->termination_exception()) {
try_catch_handler()->can_continue_ = false; try_catch_handler()->can_continue_ = false;
...@@ -1765,13 +1768,14 @@ void Isolate::PropagatePendingExceptionToExternalTryCatch() { ...@@ -1765,13 +1768,14 @@ void Isolate::PropagatePendingExceptionToExternalTryCatch() {
handler->has_terminated_ = false; handler->has_terminated_ = false;
handler->exception_ = pending_exception(); handler->exception_ = pending_exception();
// Propagate to the external try-catch only if we got an actual message. // Propagate to the external try-catch only if we got an actual message.
if (thread_local_top_.pending_message_obj_->IsTheHole()) return; if (thread_local_top_.pending_message_obj_->IsTheHole()) return true;
handler->message_obj_ = thread_local_top_.pending_message_obj_; handler->message_obj_ = thread_local_top_.pending_message_obj_;
handler->message_script_ = thread_local_top_.pending_message_script_; handler->message_script_ = thread_local_top_.pending_message_script_;
handler->message_start_pos_ = thread_local_top_.pending_message_start_pos_; handler->message_start_pos_ = thread_local_top_.pending_message_start_pos_;
handler->message_end_pos_ = thread_local_top_.pending_message_end_pos_; handler->message_end_pos_ = thread_local_top_.pending_message_end_pos_;
} }
return true;
} }
......
...@@ -604,7 +604,8 @@ class Isolate { ...@@ -604,7 +604,8 @@ class Isolate {
thread_local_top_.scheduled_exception_ = heap_.the_hole_value(); thread_local_top_.scheduled_exception_ = heap_.the_hole_value();
} }
bool IsExternallyCaught(); bool HasExternalTryCatch();
bool IsFinallyOnTop();
bool is_catchable_by_javascript(Object* exception) { bool is_catchable_by_javascript(Object* exception) {
return exception != heap()->termination_exception(); return exception != heap()->termination_exception();
...@@ -1179,7 +1180,10 @@ class Isolate { ...@@ -1179,7 +1180,10 @@ class Isolate {
void FillCache(); void FillCache();
void PropagatePendingExceptionToExternalTryCatch(); // Propagate pending exception message to the v8::TryCatch.
// If there is no external try-catch or message was successfully propagated,
// then return true.
bool PropagatePendingExceptionToExternalTryCatch();
// Traverse prototype chain to find out whether the object is derived from // Traverse prototype chain to find out whether the object is derived from
// the Error object. // the Error object.
......
...@@ -8362,6 +8362,41 @@ TEST(TryCatchFinallyUsingTryCatchHandler) { ...@@ -8362,6 +8362,41 @@ TEST(TryCatchFinallyUsingTryCatchHandler) {
} }
void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::HandleScope scope(args.GetIsolate());
CompileRun(args[0]->ToString());
}
TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
templ->Set(v8_str("CEvaluate"),
v8::FunctionTemplate::New(isolate, CEvaluate));
LocalContext context(0, templ);
v8::TryCatch try_catch;
CompileRun("try {"
" CEvaluate('throw 1;');"
"} finally {"
"}");
CHECK(try_catch.HasCaught());
CHECK(!try_catch.Message().IsEmpty());
String::Utf8Value exception_value(try_catch.Exception());
CHECK_EQ(*exception_value, "1");
try_catch.Reset();
CompileRun("try {"
" CEvaluate('throw 1;');"
"} finally {"
" throw 2;"
"}");
CHECK(try_catch.HasCaught());
CHECK(!try_catch.Message().IsEmpty());
String::Utf8Value finally_exception_value(try_catch.Exception());
CHECK_EQ(*finally_exception_value, "2");
}
// For use within the TestSecurityHandler() test. // For use within the TestSecurityHandler() test.
static bool g_security_callback_result = false; static bool g_security_callback_result = false;
static bool NamedSecurityTestCallback(Local<v8::Object> global, static bool NamedSecurityTestCallback(Local<v8::Object> global,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment