Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoyee Cheung <joyeec9h3@gmail.com>2019-03-22 19:07:46 +0300
committerJoyee Cheung <joyeec9h3@gmail.com>2019-03-30 07:38:55 +0300
commit61ef9df958f98bed5159d9d4553ea5b2f894272f (patch)
tree56870622ad9f6546a582fc53fd602fff37dbf373 /src/node_errors.cc
parent7aad63ba349d7b9b0eda4149d236ee66e5a26401 (diff)
inspector: display error when ToggleAsyncHook fails
This patch refactors `AppendExceptionLine` and `PrintSyncTrace` to reuse the error formatting logic and use them to print uncaught error in ``ToggleAsyncHook` PR-URL: https://github.com/nodejs/node/pull/26859 Refs: https://github.com/nodejs/node/issues/26798 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'src/node_errors.cc')
-rw-r--r--src/node_errors.cc154
1 files changed, 112 insertions, 42 deletions
diff --git a/src/node_errors.cc b/src/node_errors.cc
index 1923cb6a22f..3c041529743 100644
--- a/src/node_errors.cc
+++ b/src/node_errors.cc
@@ -21,10 +21,11 @@ using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::Message;
-using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::ScriptOrigin;
+using v8::StackFrame;
+using v8::StackTrace;
using v8::String;
using v8::Undefined;
using v8::Value;
@@ -44,30 +45,20 @@ namespace per_process {
static Mutex tty_mutex;
} // namespace per_process
-void AppendExceptionLine(Environment* env,
- Local<Value> er,
- Local<Message> message,
- enum ErrorHandlingMode mode) {
- if (message.IsEmpty()) return;
+static const int kMaxErrorSourceLength = 1024;
- HandleScope scope(env->isolate());
- Local<Object> err_obj;
- if (!er.IsEmpty() && er->IsObject()) {
- err_obj = er.As<Object>();
- }
+static std::string GetErrorSource(Isolate* isolate,
+ Local<Context> context,
+ Local<Message> message,
+ bool* added_exception_line) {
+ MaybeLocal<String> source_line_maybe = message->GetSourceLine(context);
+ node::Utf8Value encoded_source(isolate, source_line_maybe.ToLocalChecked());
+ std::string sourceline(*encoded_source, encoded_source.length());
- // Print (filename):(line number): (message).
- ScriptOrigin origin = message->GetScriptOrigin();
- node::Utf8Value filename(env->isolate(), message->GetScriptResourceName());
- const char* filename_string = *filename;
- int linenum = message->GetLineNumber(env->context()).FromJust();
- // Print line of source code.
- MaybeLocal<String> source_line_maybe = message->GetSourceLine(env->context());
- node::Utf8Value sourceline(env->isolate(),
- source_line_maybe.ToLocalChecked());
- const char* sourceline_string = *sourceline;
- if (strstr(sourceline_string, "node-do-not-add-exception-line") != nullptr)
- return;
+ if (sourceline.find("node-do-not-add-exception-line") != std::string::npos) {
+ *added_exception_line = false;
+ return sourceline;
+ }
// Because of how node modules work, all scripts are wrapped with a
// "function (module, exports, __filename, ...) {"
@@ -90,26 +81,32 @@ void AppendExceptionLine(Environment* env,
// sourceline to 78 characters, and we end up not providing very much
// useful debugging info to the user if we remove 62 characters.
+ // Print (filename):(line number): (message).
+ ScriptOrigin origin = message->GetScriptOrigin();
+ node::Utf8Value filename(isolate, message->GetScriptResourceName());
+ const char* filename_string = *filename;
+ int linenum = message->GetLineNumber(context).FromJust();
+
int script_start = (linenum - origin.ResourceLineOffset()->Value()) == 1
? origin.ResourceColumnOffset()->Value()
: 0;
- int start = message->GetStartColumn(env->context()).FromMaybe(0);
- int end = message->GetEndColumn(env->context()).FromMaybe(0);
+ int start = message->GetStartColumn(context).FromMaybe(0);
+ int end = message->GetEndColumn(context).FromMaybe(0);
if (start >= script_start) {
CHECK_GE(end, start);
start -= script_start;
end -= script_start;
}
- char arrow[1024];
- int max_off = sizeof(arrow) - 2;
+ int max_off = kMaxErrorSourceLength - 2;
- int off = snprintf(arrow,
- sizeof(arrow),
+ char buf[kMaxErrorSourceLength];
+ int off = snprintf(buf,
+ kMaxErrorSourceLength,
"%s:%i\n%s\n",
filename_string,
linenum,
- sourceline_string);
+ sourceline.c_str());
CHECK_GE(off, 0);
if (off > max_off) {
off = max_off;
@@ -117,26 +114,98 @@ void AppendExceptionLine(Environment* env,
// Print wavy underline (GetUnderline is deprecated).
for (int i = 0; i < start; i++) {
- if (sourceline_string[i] == '\0' || off >= max_off) {
+ if (sourceline[i] == '\0' || off >= max_off) {
break;
}
CHECK_LT(off, max_off);
- arrow[off++] = (sourceline_string[i] == '\t') ? '\t' : ' ';
+ buf[off++] = (sourceline[i] == '\t') ? '\t' : ' ';
}
for (int i = start; i < end; i++) {
- if (sourceline_string[i] == '\0' || off >= max_off) {
+ if (sourceline[i] == '\0' || off >= max_off) {
break;
}
CHECK_LT(off, max_off);
- arrow[off++] = '^';
+ buf[off++] = '^';
}
CHECK_LE(off, max_off);
- arrow[off] = '\n';
- arrow[off + 1] = '\0';
+ buf[off] = '\n';
+ buf[off + 1] = '\0';
+
+ *added_exception_line = true;
+ return std::string(buf);
+}
+
+void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) {
+ for (int i = 0; i < stack->GetFrameCount() - 1; i++) {
+ Local<StackFrame> stack_frame = stack->GetFrame(isolate, i);
+ node::Utf8Value fn_name_s(isolate, stack_frame->GetFunctionName());
+ node::Utf8Value script_name(isolate, stack_frame->GetScriptName());
+ const int line_number = stack_frame->GetLineNumber();
+ const int column = stack_frame->GetColumn();
+
+ if (stack_frame->IsEval()) {
+ if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
+ fprintf(stderr, " at [eval]:%i:%i\n", line_number, column);
+ } else {
+ fprintf(stderr,
+ " at [eval] (%s:%i:%i)\n",
+ *script_name,
+ line_number,
+ column);
+ }
+ break;
+ }
+
+ if (fn_name_s.length() == 0) {
+ fprintf(stderr, " at %s:%i:%i\n", *script_name, line_number, column);
+ } else {
+ fprintf(stderr,
+ " at %s (%s:%i:%i)\n",
+ *fn_name_s,
+ *script_name,
+ line_number,
+ column);
+ }
+ }
+ fflush(stderr);
+}
+
+void PrintCaughtException(Isolate* isolate,
+ Local<Context> context,
+ const v8::TryCatch& try_catch) {
+ CHECK(try_catch.HasCaught());
+ Local<Value> err = try_catch.Exception();
+ Local<Message> message = try_catch.Message();
+ Local<v8::StackTrace> stack = message->GetStackTrace();
+ node::Utf8Value reason(isolate,
+ err->ToDetailString(context).ToLocalChecked());
+ bool added_exception_line = false;
+ std::string source =
+ GetErrorSource(isolate, context, message, &added_exception_line);
+ fprintf(stderr, "%s\n", source.c_str());
+ fprintf(stderr, "%s\n", *reason);
+ PrintStackTrace(isolate, stack);
+}
+
+void AppendExceptionLine(Environment* env,
+ Local<Value> er,
+ Local<Message> message,
+ enum ErrorHandlingMode mode) {
+ if (message.IsEmpty()) return;
+
+ HandleScope scope(env->isolate());
+ Local<Object> err_obj;
+ if (!er.IsEmpty() && er->IsObject()) {
+ err_obj = er.As<Object>();
+ }
- Local<String> arrow_str =
- String::NewFromUtf8(env->isolate(), arrow, NewStringType::kNormal)
- .ToLocalChecked();
+ bool added_exception_line = false;
+ std::string source = GetErrorSource(
+ env->isolate(), env->context(), message, &added_exception_line);
+ if (!added_exception_line) {
+ return;
+ }
+ MaybeLocal<Value> arrow_str = ToV8Value(env->context(), source);
const bool can_set_arrow = !arrow_str.IsEmpty() && !err_obj.IsEmpty();
// If allocating arrow_str failed, print it out. There's not much else to do.
@@ -150,13 +219,14 @@ void AppendExceptionLine(Environment* env,
env->set_printed_error(true);
uv_tty_reset_mode();
- PrintErrorString("\n%s", arrow);
+ PrintErrorString("\n%s", source.c_str());
return;
}
CHECK(err_obj
- ->SetPrivate(
- env->context(), env->arrow_message_private_symbol(), arrow_str)
+ ->SetPrivate(env->context(),
+ env->arrow_message_private_symbol(),
+ arrow_str.ToLocalChecked())
.FromMaybe(false));
}