From 0af4c9ea7434e4f505dbe071357e4bc3b4ab2a8a Mon Sep 17 00:00:00 2001 From: Chris Dickinson Date: Sun, 22 Feb 2015 14:54:25 -0800 Subject: src: fix domains + --abort-on-uncaught-exception If run with --abort-on-uncaught-exception, V8 will abort the process whenever it does not see a JS-installed CatchClause in the stack. C++ TryCatch clauses are ignored. Domains work by setting a FatalException handler which is ignored when running in abort mode. This patch modifies MakeCallback to call its target function through a JS function that installs a CatchClause and manually calls _fatalException on error, if the process is both using domains and is in abort mode. Semver: patch PR-URL: https://github.com/iojs/io.js/pull/922 Fixes: https://github.com/iojs/io.js/issues/836 Reviewed-By: Ben Noordhuis --- src/async-wrap.cc | 19 ++++++++++++++++++- src/env-inl.h | 9 +++++++++ src/env.h | 5 +++++ src/node.cc | 6 +++++- src/node.js | 8 ++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 7887caf4f5b..5710c431460 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -7,6 +7,7 @@ #include "v8.h" +using v8::Array; using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; @@ -81,6 +82,7 @@ Handle AsyncWrap::MakeCallback(const Handle cb, Local process = env()->process_object(); Local domain; bool has_domain = false; + bool has_abort_on_uncaught_and_domains = false; if (env()->using_domains()) { Local domain_v = context->Get(env()->domain_string()); @@ -89,6 +91,7 @@ Handle AsyncWrap::MakeCallback(const Handle cb, domain = domain_v.As(); if (domain->Get(env()->disposed_string())->IsTrue()) return Undefined(env()->isolate()); + has_abort_on_uncaught_and_domains = env()->using_abort_on_uncaught_exc(); } } @@ -112,7 +115,21 @@ Handle AsyncWrap::MakeCallback(const Handle cb, try_catch.SetVerbose(true); } - Local ret = cb->Call(context, argc, argv); + Local ret; + + if (has_abort_on_uncaught_and_domains) { + Local fn = process->Get(env()->domain_abort_uncaught_exc_string()); + if (fn->IsFunction()) { + Local special_context = Array::New(env()->isolate(), 2); + special_context->Set(0, context); + special_context->Set(1, cb); + ret = fn.As()->Call(special_context, argc, argv); + } else { + ret = cb->Call(context, argc, argv); + } + } else { + ret = cb->Call(context, argc, argv); + } if (try_catch.HasCaught()) { return Undefined(env()->isolate()); diff --git a/src/env-inl.h b/src/env-inl.h index abe2a5a5260..d3a723a0c24 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -165,6 +165,7 @@ inline Environment::Environment(v8::Local context, isolate_data_(IsolateData::GetOrCreate(context->GetIsolate(), loop)), using_smalloc_alloc_cb_(false), using_domains_(false), + using_abort_on_uncaught_exc_(false), using_asyncwrap_(false), printed_error_(false), debugger_agent_(this), @@ -283,6 +284,14 @@ inline void Environment::set_using_smalloc_alloc_cb(bool value) { using_smalloc_alloc_cb_ = value; } +inline bool Environment::using_abort_on_uncaught_exc() const { + return using_abort_on_uncaught_exc_; +} + +inline void Environment::set_using_abort_on_uncaught_exc(bool value) { + using_abort_on_uncaught_exc_ = value; +} + inline bool Environment::using_domains() const { return using_domains_; } diff --git a/src/env.h b/src/env.h index 74544e43d51..73940ad0d48 100644 --- a/src/env.h +++ b/src/env.h @@ -67,6 +67,7 @@ namespace node { V(dev_string, "dev") \ V(disposed_string, "_disposed") \ V(domain_string, "domain") \ + V(domain_abort_uncaught_exc_string, "_makeCallbackAbortOnUncaught") \ V(exchange_string, "exchange") \ V(idle_string, "idle") \ V(irq_string, "irq") \ @@ -402,6 +403,9 @@ class Environment { inline bool using_smalloc_alloc_cb() const; inline void set_using_smalloc_alloc_cb(bool value); + inline bool using_abort_on_uncaught_exc() const; + inline void set_using_abort_on_uncaught_exc(bool value); + inline bool using_domains() const; inline void set_using_domains(bool value); @@ -496,6 +500,7 @@ class Environment { ares_task_list cares_task_list_; bool using_smalloc_alloc_cb_; bool using_domains_; + bool using_abort_on_uncaught_exc_; bool using_asyncwrap_; bool printed_error_; debugger::Agent debugger_agent_; diff --git a/src/node.cc b/src/node.cc index 507e5dc7d61..d75f0d039f4 100644 --- a/src/node.cc +++ b/src/node.cc @@ -112,6 +112,7 @@ static bool print_eval = false; static bool force_repl = false; static bool trace_deprecation = false; static bool throw_deprecation = false; +static bool abort_on_uncaught_exception = false; static const char* eval_string = nullptr; static bool use_debug_agent = false; static bool debug_wait_connect = false; @@ -3109,6 +3110,9 @@ static void ParseArgs(int* argc, trace_deprecation = true; } else if (strcmp(arg, "--throw-deprecation") == 0) { throw_deprecation = true; + } else if (strcmp(arg, "--abort-on-uncaught-exception") == 0 || + strcmp(arg, "--abort_on_uncaught_exception") == 0) { + abort_on_uncaught_exception = true; } else if (strcmp(arg, "--v8-options") == 0) { new_v8_argv[new_v8_argc] = "--help"; new_v8_argc += 1; @@ -3789,7 +3793,7 @@ int Start(int argc, char** argv) { exec_argc, exec_argv); Context::Scope context_scope(context); - + env->set_using_abort_on_uncaught_exc(abort_on_uncaught_exception); // Start debug agent when argv has --debug if (use_debug_agent) StartDebug(env, debug_wait_connect); diff --git a/src/node.js b/src/node.js index e14592c0080..a5a26e96eae 100644 --- a/src/node.js +++ b/src/node.js @@ -209,6 +209,14 @@ }; startup.processFatal = function() { + process._makeCallbackAbortOnUncaught = function() { + try { + return this[1].apply(this[0], arguments); + } catch (err) { + process._fatalException(err); + } + }; + process._fatalException = function(er) { var caught; -- cgit v1.2.3