Skip to content

Commit 832ce4f

Browse files
committed
report: generates report on threads with no isolates
1 parent 65a7fd3 commit 832ce4f

File tree

4 files changed

+87
-49
lines changed

4 files changed

+87
-49
lines changed

src/node_errors.cc

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -425,13 +425,10 @@ void OnFatalError(const char* location, const char* message) {
425425
}
426426

427427
Isolate* isolate = Isolate::GetCurrent();
428-
// TODO(legendecas): investigate failures on triggering node-report with
429-
// nullptr isolates.
430-
if (isolate == nullptr) {
431-
fflush(stderr);
432-
ABORT();
428+
Environment* env = nullptr;
429+
if (isolate != nullptr) {
430+
env = Environment::GetCurrent(isolate);
433431
}
434-
Environment* env = Environment::GetCurrent(isolate);
435432
bool report_on_fatalerror;
436433
{
437434
Mutex::ScopedLock lock(node::per_process::cli_options_mutex);

src/node_report.cc

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,20 +272,22 @@ static void WriteNodeReport(Isolate* isolate,
272272
PrintVersionInformation(&writer);
273273
writer.json_objectend();
274274

275-
writer.json_objectstart("javascriptStack");
276-
// Report summary JavaScript error stack backtrace
277-
PrintJavaScriptErrorStack(&writer, isolate, error, trigger);
275+
if (isolate != nullptr) {
276+
writer.json_objectstart("javascriptStack");
277+
// Report summary JavaScript error stack backtrace
278+
PrintJavaScriptErrorStack(&writer, isolate, error, trigger);
278279

279-
// Report summary JavaScript error properties backtrace
280-
PrintJavaScriptErrorProperties(&writer, isolate, error);
281-
writer.json_objectend(); // the end of 'javascriptStack'
280+
// Report summary JavaScript error properties backtrace
281+
PrintJavaScriptErrorProperties(&writer, isolate, error);
282+
writer.json_objectend(); // the end of 'javascriptStack'
283+
284+
// Report V8 Heap and Garbage Collector information
285+
PrintGCStatistics(&writer, isolate);
286+
}
282287

283288
// Report native stack backtrace
284289
PrintNativeStack(&writer);
285290

286-
// Report V8 Heap and Garbage Collector information
287-
PrintGCStatistics(&writer, isolate);
288-
289291
// Report OS and current thread resource usage
290292
PrintResourceUsage(&writer);
291293

test/common/report.js

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,20 @@ function validateContent(report, fields = []) {
5454

5555
function _validateContent(report, fields = []) {
5656
const isWindows = process.platform === 'win32';
57+
const isJavaScriptThreadReport = report.javascriptStack != null;
5758

5859
// Verify that all sections are present as own properties of the report.
59-
const sections = ['header', 'javascriptStack', 'nativeStack',
60-
'javascriptHeap', 'libuv', 'environmentVariables',
60+
const sections = ['header', 'nativeStack', 'libuv', 'environmentVariables',
6161
'sharedObjects', 'resourceUsage', 'workers'];
6262
if (!isWindows)
6363
sections.push('userLimits');
6464

6565
if (report.uvthreadResourceUsage)
6666
sections.push('uvthreadResourceUsage');
6767

68+
if (isJavaScriptThreadReport)
69+
sections.push('javascriptStack', 'javascriptHeap');
70+
6871
checkForUnknownFields(report, sections);
6972
sections.forEach((section) => {
7073
assert(report.hasOwnProperty(section));
@@ -163,19 +166,6 @@ function _validateContent(report, fields = []) {
163166
});
164167
assert.strictEqual(header.host, os.hostname());
165168

166-
// Verify the format of the javascriptStack section.
167-
checkForUnknownFields(report.javascriptStack,
168-
['message', 'stack', 'errorProperties']);
169-
assert.strictEqual(typeof report.javascriptStack.errorProperties,
170-
'object');
171-
assert.strictEqual(typeof report.javascriptStack.message, 'string');
172-
if (report.javascriptStack.stack !== undefined) {
173-
assert(Array.isArray(report.javascriptStack.stack));
174-
report.javascriptStack.stack.forEach((frame) => {
175-
assert.strictEqual(typeof frame, 'string');
176-
});
177-
}
178-
179169
// Verify the format of the nativeStack section.
180170
assert(Array.isArray(report.nativeStack));
181171
report.nativeStack.forEach((frame) => {
@@ -186,26 +176,41 @@ function _validateContent(report, fields = []) {
186176
assert.strictEqual(typeof frame.symbol, 'string');
187177
});
188178

189-
// Verify the format of the javascriptHeap section.
190-
const heap = report.javascriptHeap;
191-
const jsHeapFields = ['totalMemory', 'totalCommittedMemory', 'usedMemory',
192-
'availableMemory', 'memoryLimit', 'heapSpaces'];
193-
checkForUnknownFields(heap, jsHeapFields);
194-
assert(Number.isSafeInteger(heap.totalMemory));
195-
assert(Number.isSafeInteger(heap.totalCommittedMemory));
196-
assert(Number.isSafeInteger(heap.usedMemory));
197-
assert(Number.isSafeInteger(heap.availableMemory));
198-
assert(Number.isSafeInteger(heap.memoryLimit));
199-
assert(typeof heap.heapSpaces === 'object' && heap.heapSpaces !== null);
200-
const heapSpaceFields = ['memorySize', 'committedMemory', 'capacity', 'used',
201-
'available'];
202-
Object.keys(heap.heapSpaces).forEach((spaceName) => {
203-
const space = heap.heapSpaces[spaceName];
204-
checkForUnknownFields(space, heapSpaceFields);
205-
heapSpaceFields.forEach((field) => {
206-
assert(Number.isSafeInteger(space[field]));
179+
if (isJavaScriptThreadReport) {
180+
// Verify the format of the javascriptStack section.
181+
checkForUnknownFields(report.javascriptStack,
182+
['message', 'stack', 'errorProperties']);
183+
assert.strictEqual(typeof report.javascriptStack.errorProperties,
184+
'object');
185+
assert.strictEqual(typeof report.javascriptStack.message, 'string');
186+
if (report.javascriptStack.stack !== undefined) {
187+
assert(Array.isArray(report.javascriptStack.stack));
188+
report.javascriptStack.stack.forEach((frame) => {
189+
assert.strictEqual(typeof frame, 'string');
190+
});
191+
}
192+
193+
// Verify the format of the javascriptHeap section.
194+
const heap = report.javascriptHeap;
195+
const jsHeapFields = ['totalMemory', 'totalCommittedMemory', 'usedMemory',
196+
'availableMemory', 'memoryLimit', 'heapSpaces'];
197+
checkForUnknownFields(heap, jsHeapFields);
198+
assert(Number.isSafeInteger(heap.totalMemory));
199+
assert(Number.isSafeInteger(heap.totalCommittedMemory));
200+
assert(Number.isSafeInteger(heap.usedMemory));
201+
assert(Number.isSafeInteger(heap.availableMemory));
202+
assert(Number.isSafeInteger(heap.memoryLimit));
203+
assert(typeof heap.heapSpaces === 'object' && heap.heapSpaces !== null);
204+
const heapSpaceFields = ['memorySize', 'committedMemory', 'capacity', 'used',
205+
'available'];
206+
Object.keys(heap.heapSpaces).forEach((spaceName) => {
207+
const space = heap.heapSpaces[spaceName];
208+
checkForUnknownFields(space, heapSpaceFields);
209+
heapSpaceFields.forEach((field) => {
210+
assert(Number.isSafeInteger(space[field]));
211+
});
207212
});
208-
});
213+
}
209214

210215
// Verify the format of the resourceUsage section.
211216
const usage = report.resourceUsage;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
const common = require('../../common');
3+
const helper = require('../../common/report.js');
4+
const tmpdir = require('../../common/tmpdir');
5+
6+
const assert = require('assert');
7+
const child_process = require('child_process');
8+
const test_fatal = require(`./build/${common.buildType}/test_fatal`);
9+
10+
if (common.buildType === 'Debug')
11+
common.skip('as this will currently fail with a Debug check ' +
12+
'in v8::Isolate::GetCurrent()');
13+
14+
// Test in a child process because the test code will trigger a fatal error
15+
// that crashes the process.
16+
if (process.argv[2] === 'child') {
17+
test_fatal.TestThread();
18+
// Busy loop to allow the work thread to abort.
19+
while (true) {}
20+
}
21+
22+
tmpdir.refresh();
23+
const p = child_process.spawnSync(
24+
process.execPath, [ '--report-on-fatalerror', __filename, 'child' ], { cwd: tmpdir.path });
25+
assert.ifError(p.error);
26+
assert.ok(p.stderr.toString().includes(
27+
'FATAL ERROR: work_thread foobar'));
28+
assert.ok(p.status === 134 || p.signal === 'SIGABRT');
29+
30+
const reports = helper.findReports(p.pid, tmpdir.path);
31+
assert.strictEqual(reports.length, 1);
32+
33+
const report = reports[0];
34+
helper.validate(report);

0 commit comments

Comments
 (0)