Skip to content

Commit c0e3840

Browse files
committed
src: no call to SetIdle() when terminating
Calling SetIdle() when terminating is not harmless. When node terminates due to an unhandled exception, v8 preseves the vm state, which is JS and notifies node through PerIsolateMessageListener(). If node calls SetIdle() later, v8 complains because it requires the vm state to either be EXTERNEL or IDLE when embedder calling SetIdle().
1 parent e1ac4e9 commit c0e3840

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

src/api/callback.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,11 @@ void InternalCallbackScope::Close() {
9797
if (closed_) return;
9898
closed_ = true;
9999

100+
if (!env_->can_call_into_js()) return;
101+
100102
Isolate* isolate = env_->isolate();
101103
auto idle = OnScopeLeave([&]() { isolate->SetIdle(true); });
102104

103-
if (!env_->can_call_into_js()) return;
104105
auto perform_stopping_check = [&]() {
105106
if (env_->is_stopping()) {
106107
MarkAsFailed();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
require('../common');
3+
4+
// Check that node will not call v8::Isolate::SetIdle() when exiting
5+
// due to an unhandled exception, otherwise the assertion(enabled in
6+
// debug build only) in the SetIdle() will fail.
7+
//
8+
// The root cause of this issue is that before PerIsolateMessageListener()
9+
// is invoked by v8, v8 preserves the vm state, which is JS. However,
10+
// SetIdle() requires the vm state is either EXTERNEL or IDLE when embedder
11+
// calling it.
12+
13+
if (process.argv[2] === 'child') {
14+
const { Worker } = require('worker_threads');
15+
new Worker('', { eval: true });
16+
throw new Error('xxx');
17+
} else {
18+
const assert = require('assert');
19+
const { spawnSync } = require('child_process');
20+
const result = spawnSync(process.execPath, [__filename, 'child']);
21+
22+
const stderr = result.stderr.toString().trim();
23+
// Expect error message to be preserved
24+
assert.match(stderr, /xxx/);
25+
// Expect no crash message
26+
assert.doesNotMatch(stderr, /node::DumpBacktrace/);
27+
}

0 commit comments

Comments
 (0)