From a60b74d974360092008648c58a7fc125fccad3c3 Mon Sep 17 00:00:00 2001 From: Marc Horowitz Date: Thu, 16 Jun 2016 14:28:28 -0700 Subject: [PATCH] When executing JS throws an exception, capture the js stack in the C++ exception thrown Reviewed By: davidaurelio Differential Revision: D3428921 fbshipit-source-id: 0e8be84a2be92558ea3de0d32d1d4a53308d8270 --- ReactCommon/cxxreact/JSCHelpers.cpp | 13 +++++++++++-- ReactCommon/cxxreact/JSCHelpers.h | 27 +++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/ReactCommon/cxxreact/JSCHelpers.cpp b/ReactCommon/cxxreact/JSCHelpers.cpp index f30d9dbfb..d0aa0a0ed 100644 --- a/ReactCommon/cxxreact/JSCHelpers.cpp +++ b/ReactCommon/cxxreact/JSCHelpers.cpp @@ -52,7 +52,8 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef // file/resource, or was a constructed statement. The location // info will include that source, if any. std::string locationInfo = source != nullptr ? String::ref(source).str() : ""; - auto line = exception.asObject().getProperty("line"); + Object exObject = exception.asObject(); + auto line = exObject.getProperty("line"); if (line != nullptr && line.isNumber()) { if (locationInfo.empty() && line.asInteger() != 1) { // If there is a non-trivial line number, but there was no @@ -71,7 +72,15 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef } LOG(ERROR) << "Got JS Exception: " << exceptionText; - throwJSExecutionException("%s", exceptionText.c_str()); + + Value jsStack = exObject.getProperty("stack"); + if (jsStack.isNull() || !jsStack.isString()) { + throwJSExecutionException("%s", exceptionText.c_str()); + } else { + LOG(ERROR) << "Got JS Stack: " << jsStack.toString().str(); + throwJSExecutionExceptionWithStack( + exceptionText.c_str(), jsStack.toString().str().c_str()); + } } return result; } diff --git a/ReactCommon/cxxreact/JSCHelpers.h b/ReactCommon/cxxreact/JSCHelpers.h index 57b03e31e..eb29058ef 100644 --- a/ReactCommon/cxxreact/JSCHelpers.h +++ b/ReactCommon/cxxreact/JSCHelpers.h @@ -17,12 +17,26 @@ namespace facebook { namespace react { -struct JsException : std::runtime_error { - using std::runtime_error::runtime_error; +class JSException : public std::runtime_error { +public: + explicit JSException(const char* msg) + : std::runtime_error(msg) + , stack_("") {} + + JSException(const char* msg, const char* stack) + : std::runtime_error(msg) + , stack_(stack) {} + + const std::string& getStack() const { + return stack_; + } + +private: + std::string stack_; }; inline void throwJSExecutionException(const char* msg) { - throw JsException(msg); + throw JSException(msg); } template @@ -31,7 +45,12 @@ inline void throwJSExecutionException(const char* fmt, Args... args) { msgSize = std::min(512, msgSize + 1); char *msg = (char*) alloca(msgSize); snprintf(msg, msgSize, fmt, args...); - throw JsException(msg); + throw JSException(msg); +} + +template +inline void throwJSExecutionExceptionWithStack(const char* msg, const char* stack) { + throw JSException(msg, stack); } void installGlobalFunction(