Skip to content

Commit 8292057

Browse files
committed
src: print arbitrary javascript exception value in node report
1 parent 3dee233 commit 8292057

File tree

5 files changed

+98
-30
lines changed

5 files changed

+98
-30
lines changed

src/node_report.cc

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,16 @@ static void WriteNodeReport(Isolate* isolate,
5858
const char* trigger,
5959
const std::string& filename,
6060
std::ostream& out,
61-
Local<Object> error,
61+
Local<Value> error,
6262
bool compact);
6363
static void PrintVersionInformation(JSONWriter* writer);
6464
static void PrintJavaScriptErrorStack(JSONWriter* writer,
6565
Isolate* isolate,
66-
Local<Object> error,
66+
Local<Value> error,
6767
const char* trigger);
6868
static void PrintJavaScriptErrorProperties(JSONWriter* writer,
6969
Isolate* isolate,
70-
Local<Object> error);
70+
Local<Value> error);
7171
static void PrintNativeStack(JSONWriter* writer);
7272
static void PrintResourceUsage(JSONWriter* writer);
7373
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
@@ -84,7 +84,7 @@ std::string TriggerNodeReport(Isolate* isolate,
8484
const char* message,
8585
const char* trigger,
8686
const std::string& name,
87-
Local<Object> error) {
87+
Local<Value> error) {
8888
std::string filename;
8989

9090
// Determine the required report filename. In order of priority:
@@ -169,7 +169,7 @@ void GetNodeReport(Isolate* isolate,
169169
Environment* env,
170170
const char* message,
171171
const char* trigger,
172-
Local<Object> error,
172+
Local<Value> error,
173173
std::ostream& out) {
174174
WriteNodeReport(isolate, env, message, trigger, "", out, error, false);
175175
}
@@ -182,7 +182,7 @@ static void WriteNodeReport(Isolate* isolate,
182182
const char* trigger,
183183
const std::string& filename,
184184
std::ostream& out,
185-
Local<Object> error,
185+
Local<Value> error,
186186
bool compact) {
187187
// Obtain the current time and the pid.
188188
TIME_TYPE tm_struct;
@@ -474,13 +474,14 @@ static void PrintNetworkInterfaceInfo(JSONWriter* writer) {
474474

475475
static void PrintJavaScriptErrorProperties(JSONWriter* writer,
476476
Isolate* isolate,
477-
Local<Object> error) {
477+
Local<Value> error) {
478478
writer->json_objectstart("errorProperties");
479-
if (!error.IsEmpty()) {
479+
if (!error.IsEmpty() && error->IsObject()) {
480480
TryCatch try_catch(isolate);
481-
Local<Context> context = error->GetIsolate()->GetCurrentContext();
481+
Local<Object> error_obj = error.As<Object>();
482+
Local<Context> context = error_obj->GetIsolate()->GetCurrentContext();
482483
Local<Array> keys;
483-
if (!error->GetOwnPropertyNames(context).ToLocal(&keys)) {
484+
if (!error_obj->GetOwnPropertyNames(context).ToLocal(&keys)) {
484485
return writer->json_objectend(); // the end of 'errorProperties'
485486
}
486487
uint32_t keys_length = keys->Length();
@@ -491,7 +492,7 @@ static void PrintJavaScriptErrorProperties(JSONWriter* writer,
491492
}
492493
Local<Value> value;
493494
Local<String> value_string;
494-
if (!error->Get(context, key).ToLocal(&value) ||
495+
if (!error_obj->Get(context, key).ToLocal(&value) ||
495496
!value->ToString(context).ToLocal(&value_string)) {
496497
continue;
497498
}
@@ -505,26 +506,45 @@ static void PrintJavaScriptErrorProperties(JSONWriter* writer,
505506
writer->json_objectend(); // the end of 'errorProperties'
506507
}
507508

509+
static void ErrorToString(Isolate* isolate,
510+
Local<Context> context,
511+
Local<Value> error,
512+
std::string* ss) {
513+
if (error.IsEmpty()) {
514+
return;
515+
}
516+
517+
Local<Value> js_str;
518+
// `ToString` is not available to Symbols.
519+
if (error->IsSymbol() &&
520+
error.As<v8::Symbol>()->ToDetailString(context).ToLocal(&js_str)) {
521+
String::Utf8Value sv(isolate, js_str);
522+
*ss = std::string(*sv, sv.length());
523+
} else if (!error->IsObject() && error->ToString(context).ToLocal(&js_str)) {
524+
String::Utf8Value sv(isolate, js_str);
525+
*ss = std::string(*sv, sv.length());
526+
} else if (error->IsObject() &&
527+
error.As<Object>()
528+
->Get(context, node::FIXED_ONE_BYTE_STRING(isolate, "stack"))
529+
.ToLocal(&js_str)) {
530+
String::Utf8Value sv(isolate, js_str);
531+
*ss = std::string(*sv, sv.length());
532+
}
533+
}
534+
508535
// Report the JavaScript stack.
509536
static void PrintJavaScriptErrorStack(JSONWriter* writer,
510-
Isolate* isolate,
511-
Local<Object> error,
512-
const char* trigger) {
513-
Local<Value> stackstr;
514-
std::string ss = "";
537+
Isolate* isolate,
538+
Local<Value> error,
539+
const char* trigger) {
515540
TryCatch try_catch(isolate);
541+
Local<Context> context = isolate->GetCurrentContext();
542+
std::string ss = "";
516543
if ((!strcmp(trigger, "FatalError")) ||
517544
(!strcmp(trigger, "Signal"))) {
518545
ss = "No stack.\nUnavailable.\n";
519-
} else if (!error.IsEmpty() &&
520-
error
521-
->Get(isolate->GetCurrentContext(),
522-
node::FIXED_ONE_BYTE_STRING(isolate,
523-
"stack"))
524-
.ToLocal(&stackstr)) {
525-
String::Utf8Value sv(isolate, stackstr);
526-
ss = std::string(*sv, sv.length());
527546
}
547+
ErrorToString(isolate, context, error, &ss);
528548
int line = ss.find('\n');
529549
if (line == -1) {
530550
writer->json_keyvalue("message", ss);

src/node_report.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ std::string TriggerNodeReport(v8::Isolate* isolate,
2020
const char* message,
2121
const char* trigger,
2222
const std::string& name,
23-
v8::Local<v8::Object> error);
23+
v8::Local<v8::Value> error);
2424
void GetNodeReport(v8::Isolate* isolate,
2525
node::Environment* env,
2626
const char* message,
2727
const char* trigger,
28-
v8::Local<v8::Object> error,
28+
v8::Local<v8::Value> error,
2929
std::ostream& out);
3030

3131
// Function declarations - utility functions in src/node_report_utils.cc

src/node_report_module.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@ void WriteReport(const FunctionCallbackInfo<Value>& info) {
3232
Isolate* isolate = env->isolate();
3333
HandleScope scope(isolate);
3434
std::string filename;
35-
Local<Object> error;
35+
Local<Value> error;
3636

3737
CHECK_EQ(info.Length(), 4);
3838
String::Utf8Value message(isolate, info[0].As<String>());
3939
String::Utf8Value trigger(isolate, info[1].As<String>());
4040

4141
if (info[2]->IsString())
4242
filename = *String::Utf8Value(isolate, info[2]);
43-
if (!info[3].IsEmpty() && info[3]->IsObject())
44-
error = info[3].As<Object>();
43+
if (!info[3].IsEmpty())
44+
error = info[3];
4545
else
46-
error = Local<Object>();
46+
error = Local<Value>();
4747

4848
filename = TriggerNodeReport(
4949
isolate, env, *message, *trigger, filename, error);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Flags: --report-uncaught-exception
2+
'use strict';
3+
// Test producing a report on uncaught exception.
4+
const common = require('../common');
5+
const assert = require('assert');
6+
const helper = require('../common/report');
7+
const tmpdir = require('../common/tmpdir');
8+
9+
const exception = 1;
10+
11+
tmpdir.refresh();
12+
process.report.directory = tmpdir.path;
13+
14+
process.on('uncaughtException', common.mustCall((err) => {
15+
assert.strictEqual(err, exception);
16+
const reports = helper.findReports(process.pid, tmpdir.path);
17+
assert.strictEqual(reports.length, 1);
18+
console.log(reports[0]);
19+
helper.validate(reports[0], [
20+
['javascriptStack.message', `${exception}`],
21+
]);
22+
}));
23+
24+
throw exception;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Flags: --report-uncaught-exception
2+
'use strict';
3+
// Test producing a report on uncaught exception.
4+
const common = require('../common');
5+
const assert = require('assert');
6+
const helper = require('../common/report');
7+
const tmpdir = require('../common/tmpdir');
8+
9+
const exception = Symbol('foobar');
10+
11+
tmpdir.refresh();
12+
process.report.directory = tmpdir.path;
13+
14+
process.on('uncaughtException', common.mustCall((err) => {
15+
assert.strictEqual(err, exception);
16+
const reports = helper.findReports(process.pid, tmpdir.path);
17+
assert.strictEqual(reports.length, 1);
18+
console.log(reports[0]);
19+
helper.validate(reports[0], [
20+
['javascriptStack.message', "Symbol('foobar')"],
21+
]);
22+
}));
23+
24+
throw exception;

0 commit comments

Comments
 (0)