Browse Source

inspector: add support for uncaught exception

To output exception in DevTools console method exceptionThrown should
be called on uncaught exception on V8Inspector object. Additionally
we need to wait disconnect to provide user way to inspect exception.

PR-URL: https://github.com/nodejs/node/pull/8043
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: jasnell - James M Snell <jasnell@gmail.com>
Reviewed-By: ofrobots - Ali Ijaz Sheikh <ofrobots@google.com>
v7.x
Aleksei Koziatinskii 8 years ago
committed by Ali Ijaz Sheikh
parent
commit
26cd48fb9b
  1. 54
      src/inspector_agent.cc
  2. 7
      src/inspector_agent.h
  3. 40
      src/node.cc

54
src/inspector_agent.cc

@ -13,6 +13,7 @@
#include "platform/v8_inspector/public/V8Inspector.h"
#include "platform/v8_inspector/public/V8InspectorClient.h"
#include "platform/v8_inspector/public/V8InspectorSession.h"
#include "platform/v8_inspector/public/V8StackTrace.h"
#include "platform/inspector_protocol/FrontendChannel.h"
#include "platform/inspector_protocol/String16.h"
#include "platform/inspector_protocol/Values.h"
@ -175,6 +176,9 @@ class AgentImpl {
bool IsConnected() { return state_ == State::kConnected; }
void WaitForDisconnect();
void FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message);
private:
using MessageQueue = std::vector<std::pair<int, String16>>;
enum class State { kNew, kAccepting, kConnected, kDone, kError };
@ -334,6 +338,10 @@ class V8NodeInspector : public blink::V8InspectorClient {
session_->dispatchProtocolMessage(message);
}
blink::V8Inspector* inspector() {
return inspector_.get();
}
private:
AgentImpl* agent_;
v8::Isolate* isolate_;
@ -495,6 +503,46 @@ void AgentImpl::InstallInspectorOnProcess() {
env->SetMethod(inspector, "wrapConsoleCall", InspectorWrapConsoleCall);
}
String16 ToProtocolString(v8::Local<v8::Value> value) {
if (value.IsEmpty() || value->IsNull() || value->IsUndefined() ||
!value->IsString()) {
return String16();
}
v8::Local<v8::String> string_value = v8::Local<v8::String>::Cast(value);
wstring buffer(string_value->Length(), '\0');
string_value->Write(&buffer[0], 0, string_value->Length());
return String16(buffer);
}
void AgentImpl::FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message) {
if (!IsStarted())
return;
auto env = parent_env_;
v8::Local<v8::Context> context = env->context();
int script_id = message->GetScriptOrigin().ScriptID()->Value();
std::unique_ptr<blink::V8StackTrace> stack_trace =
inspector_->inspector()->createStackTrace(message->GetStackTrace());
if (stack_trace && !stack_trace->isEmpty() &&
String16::fromInteger(script_id) == stack_trace->topScriptId()) {
script_id = 0;
}
inspector_->inspector()->exceptionThrown(
context,
"Uncaught",
error,
ToProtocolString(message->Get()),
ToProtocolString(message->GetScriptResourceName()),
message->GetLineNumber(context).FromMaybe(0),
message->GetStartColumn(context).FromMaybe(0),
std::move(stack_trace),
script_id);
WaitForDisconnect();
}
// static
void AgentImpl::ThreadCbIO(void* agent) {
static_cast<AgentImpl*>(agent)->WorkerRunIO();
@ -714,5 +762,11 @@ void Agent::WaitForDisconnect() {
impl->WaitForDisconnect();
}
void Agent::FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message) {
impl->FatalException(error, message);
}
} // namespace inspector
} // namespace node

7
src/inspector_agent.h

@ -12,6 +12,10 @@ class Environment;
namespace v8 {
class Platform;
template<typename T>
class Local;
class Value;
class Message;
} // namespace v8
namespace node {
@ -32,6 +36,9 @@ class Agent {
bool IsStarted();
bool IsConnected();
void WaitForDisconnect();
void FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message);
private:
AgentImpl* impl;
};

40
src/node.cc

@ -2464,31 +2464,43 @@ void FatalException(Isolate* isolate,
Local<Function> fatal_exception_function =
process_object->Get(fatal_exception_string).As<Function>();
int exit_code = 0;
if (!fatal_exception_function->IsFunction()) {
// failed before the process._fatalException function was added!
// this is probably pretty bad. Nothing to do but report and exit.
ReportException(env, error, message);
exit(6);
exit_code = 6;
}
TryCatch fatal_try_catch(isolate);
if (exit_code == 0) {
TryCatch fatal_try_catch(isolate);
// Do not call FatalException when _fatalException handler throws
fatal_try_catch.SetVerbose(false);
// Do not call FatalException when _fatalException handler throws
fatal_try_catch.SetVerbose(false);
// this will return true if the JS layer handled it, false otherwise
Local<Value> caught =
fatal_exception_function->Call(process_object, 1, &error);
// this will return true if the JS layer handled it, false otherwise
Local<Value> caught =
fatal_exception_function->Call(process_object, 1, &error);
if (fatal_try_catch.HasCaught()) {
// the fatal exception function threw, so we must exit
ReportException(env, fatal_try_catch);
exit(7);
if (fatal_try_catch.HasCaught()) {
// the fatal exception function threw, so we must exit
ReportException(env, fatal_try_catch);
exit_code = 7;
}
if (exit_code == 0 && false == caught->BooleanValue()) {
ReportException(env, error, message);
exit_code = 1;
}
}
if (false == caught->BooleanValue()) {
ReportException(env, error, message);
exit(1);
if (exit_code) {
#if HAVE_INSPECTOR
if (use_inspector) {
env->inspector_agent()->FatalException(error, message);
}
#endif
exit(exit_code);
}
}

Loading…
Cancel
Save