Skip to content

Commit f69c934

Browse files
legendecastargos
authored andcommitted
report: generates report on threads with no isolates
PR-URL: #38994 Backport-PR-URL: #39515 Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 99493b0 commit f69c934

File tree

4 files changed

+89
-49
lines changed

4 files changed

+89
-49
lines changed

src/node_errors.cc

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

426426
Isolate* isolate = Isolate::GetCurrent();
427-
// TODO(legendecas): investigate failures on triggering node-report with
428-
// nullptr isolates.
429-
if (isolate == nullptr) {
430-
fflush(stderr);
431-
ABORT();
427+
Environment* env = nullptr;
428+
if (isolate != nullptr) {
429+
env = Environment::GetCurrent(isolate);
432430
}
433-
Environment* env = Environment::GetCurrent(isolate);
434431
bool report_on_fatalerror;
435432
{
436433
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
@@ -267,20 +267,22 @@ static void WriteNodeReport(Isolate* isolate,
267267
PrintVersionInformation(&writer);
268268
writer.json_objectend();
269269

270-
writer.json_objectstart("javascriptStack");
271-
// Report summary JavaScript error stack backtrace
272-
PrintJavaScriptErrorStack(&writer, isolate, error, trigger);
270+
if (isolate != nullptr) {
271+
writer.json_objectstart("javascriptStack");
272+
// Report summary JavaScript error stack backtrace
273+
PrintJavaScriptErrorStack(&writer, isolate, error, trigger);
273274

274-
// Report summary JavaScript error properties backtrace
275-
PrintJavaScriptErrorProperties(&writer, isolate, error);
276-
writer.json_objectend(); // the end of 'javascriptStack'
275+
// Report summary JavaScript error properties backtrace
276+
PrintJavaScriptErrorProperties(&writer, isolate, error);
277+
writer.json_objectend(); // the end of 'javascriptStack'
278+
279+
// Report V8 Heap and Garbage Collector information
280+
PrintGCStatistics(&writer, isolate);
281+
}
277282

278283
// Report native stack backtrace
279284
PrintNativeStack(&writer);
280285

281-
// Report V8 Heap and Garbage Collector information
282-
PrintGCStatistics(&writer, isolate);
283-
284286
// Report OS and current thread resource usage
285287
PrintResourceUsage(&writer);
286288

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',
205+
'used', '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: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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,
25+
[ '--report-on-fatalerror', __filename, 'child' ],
26+
{ cwd: tmpdir.path });
27+
assert.ifError(p.error);
28+
assert.ok(p.stderr.toString().includes(
29+
'FATAL ERROR: work_thread foobar'));
30+
assert.ok(p.status === 134 || p.signal === 'SIGABRT');
31+
32+
const reports = helper.findReports(p.pid, tmpdir.path);
33+
assert.strictEqual(reports.length, 1);
34+
35+
const report = reports[0];
36+
helper.validate(report);

0 commit comments

Comments
 (0)