7131f4d
From fbff7054a47551387a99244e2cf0631f30406798 Mon Sep 17 00:00:00 2001
7131f4d
From: Trevor Norris <trev.norris@gmail.com>
7131f4d
Date: Tue, 18 Nov 2014 16:37:54 -0800
7131f4d
Subject: [PATCH] v8: add api for aborting on uncaught exception
7131f4d
7131f4d
Add v8::Isolate::SetAbortOnUncaughtException() so the user can be
7131f4d
notified when an uncaught exception has bubbled.
7131f4d
7131f4d
PR-URL: https://github.com/joyent/node/pull/8666
7131f4d
Reviewed-by: Trevor Norris <trev.norris@gmail.com>
7131f4d
---
7131f4d
 include/v8.h   | 11 +++++++++++
7131f4d
 src/api.cc     |  5 +++++
7131f4d
 src/isolate.cc | 33 +++++++++++++++++++++++----------
7131f4d
 src/isolate.h  |  5 +++++
7131f4d
 4 files changed, 44 insertions(+), 10 deletions(-)
7131f4d
7131f4d
diff --git a/include/v8.h b/include/v8.h
7131f4d
index 71a0d01..e229ed9 100644
7131f4d
--- a/include/v8.h
7131f4d
+++ b/include/v8.h
7131f4d
@@ -2842,6 +2842,17 @@ class V8EXPORT Isolate {
7131f4d
   static Isolate* GetCurrent();
7131f4d
 
7131f4d
   /**
7131f4d
+   * Custom callback used by embedders to help V8 determine if it should abort
7131f4d
+   * when it throws and no internal handler can catch the exception.
7131f4d
+   * If FLAG_abort_on_uncaught_exception is true, then V8 will abort if either:
7131f4d
+   * - no custom callback is set.
7131f4d
+   * - the custom callback set returns true.
7131f4d
+   * Otherwise it won't abort.
7131f4d
+   */
7131f4d
+  typedef bool (*abort_on_uncaught_exception_t)();
7131f4d
+  void SetAbortOnUncaughtException(abort_on_uncaught_exception_t callback);
7131f4d
+
7131f4d
+  /**
7131f4d
    * Methods below this point require holding a lock (using Locker) in
7131f4d
    * a multi-threaded environment.
7131f4d
    */
7131f4d
diff --git a/src/api.cc b/src/api.cc
7131f4d
index 96d564f..4b1aa67 100644
7131f4d
--- a/src/api.cc
7131f4d
+++ b/src/api.cc
7131f4d
@@ -5550,6 +5550,11 @@ void Isolate::Enter() {
7131f4d
   isolate->Enter();
7131f4d
 }
7131f4d
 
7131f4d
+void Isolate::SetAbortOnUncaughtException(
7131f4d
+      abort_on_uncaught_exception_t callback) {
7131f4d
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
7131f4d
+  isolate->SetAbortOnUncaughtException(callback);
7131f4d
+}
7131f4d
 
7131f4d
 void Isolate::Exit() {
7131f4d
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
7131f4d
diff --git a/src/isolate.cc b/src/isolate.cc
7131f4d
index 5a5293e..0b38616 100644
7131f4d
--- a/src/isolate.cc
7131f4d
+++ b/src/isolate.cc
7131f4d
@@ -1152,18 +1152,26 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) {
7131f4d
         thread_local_top()->pending_message_end_pos_ = location->end_pos();
7131f4d
       }
7131f4d
 
7131f4d
-      // If the abort-on-uncaught-exception flag is specified, abort on any
7131f4d
-      // exception not caught by JavaScript, even when an external handler is
7131f4d
-      // present.  This flag is intended for use by JavaScript developers, so
7131f4d
-      // print a user-friendly stack trace (not an internal one).
7131f4d
+      // If the abort-on-uncaught-exception flag is specified, and if the
7131f4d
+      // exception is not caught by JavaScript (even when an external handler is
7131f4d
+      // present).
7131f4d
       if (fatal_exception_depth == 0 &&
7131f4d
           FLAG_abort_on_uncaught_exception &&
7131f4d
           (report_exception || can_be_caught_externally)) {
7131f4d
-        fatal_exception_depth++;
7131f4d
-        fprintf(stderr, "%s\n\nFROM\n",
7131f4d
-          *MessageHandler::GetLocalizedMessage(message_obj));
7131f4d
-        PrintCurrentStackTrace(stderr);
7131f4d
-        OS::Abort();
7131f4d
+        // If the embedder didn't specify a custom uncaught exception callback,
7131f4d
+        // or if the custom callback determined that V8 should abort, then
7131f4d
+        // abort
7131f4d
+        bool should_abort = !abort_on_uncaught_exception_callback_ ||
7131f4d
+                             abort_on_uncaught_exception_callback_();
7131f4d
+        if (should_abort) {
7131f4d
+          fatal_exception_depth++;
7131f4d
+          // This flag is intended for use by JavaScript developers, so
7131f4d
+          // print a user-friendly stack trace (not an internal one).
7131f4d
+          fprintf(stderr, "%s\n\nFROM\n",
7131f4d
+            *MessageHandler::GetLocalizedMessage(message_obj));
7131f4d
+          PrintCurrentStackTrace(stderr);
7131f4d
+          OS::Abort();
7131f4d
+        }
7131f4d
       }
7131f4d
     } else if (location != NULL && !location->script().is_null()) {
7131f4d
       // We are bootstrapping and caught an error where the location is set
7131f4d
@@ -1339,6 +1347,10 @@ void Isolate::SetCaptureStackTraceForUncaughtExceptions(
7131f4d
   stack_trace_for_uncaught_exceptions_options_ = options;
7131f4d
 }
7131f4d
 
7131f4d
+void Isolate::SetAbortOnUncaughtException(
7131f4d
+      v8::Isolate::abort_on_uncaught_exception_t callback) {
7131f4d
+  abort_on_uncaught_exception_callback_ = callback;
7131f4d
+}
7131f4d
 
7131f4d
 bool Isolate::is_out_of_memory() {
7131f4d
   if (has_pending_exception()) {
7131f4d
@@ -1534,7 +1546,8 @@ Isolate::Isolate()
7131f4d
       date_cache_(NULL),
7131f4d
       context_exit_happened_(false),
7131f4d
       deferred_handles_head_(NULL),
7131f4d
-      optimizing_compiler_thread_(this) {
7131f4d
+      optimizing_compiler_thread_(this),
7131f4d
+      abort_on_uncaught_exception_callback_(NULL) {
7131f4d
   TRACE_ISOLATE(constructor);
7131f4d
 
7131f4d
   memset(isolate_addresses_, 0,
7131f4d
diff --git a/src/isolate.h b/src/isolate.h
7131f4d
index 2769ca7..8719aa1 100644
7131f4d
--- a/src/isolate.h
7131f4d
+++ b/src/isolate.h
7131f4d
@@ -692,6 +692,9 @@ class Isolate {
7131f4d
       int frame_limit,
7131f4d
       StackTrace::StackTraceOptions options);
7131f4d
 
7131f4d
+  typedef bool (*abort_on_uncaught_exception_t)();
7131f4d
+  void SetAbortOnUncaughtException(abort_on_uncaught_exception_t callback);
7131f4d
+
7131f4d
   // Tells whether the current context has experienced an out of memory
7131f4d
   // exception.
7131f4d
   bool is_out_of_memory();
7131f4d
@@ -1292,6 +1295,8 @@ class Isolate {
7131f4d
   DeferredHandles* deferred_handles_head_;
7131f4d
   OptimizingCompilerThread optimizing_compiler_thread_;
7131f4d
 
7131f4d
+  abort_on_uncaught_exception_t abort_on_uncaught_exception_callback_;
7131f4d
+
7131f4d
   friend class ExecutionAccess;
7131f4d
   friend class HandleScopeImplementer;
7131f4d
   friend class IsolateInitializer;