Skip to content

Commit f9c4eb9

Browse files
committed
src: avoid draining tasks at FreeEnvironment
At the point of `FreeEnvironment` and onwards, no JavaScript execution associated with the Environment should be triggered. Avoid draining platform tasks that can trigger JavaScript execution in `FreeEnvironment`. The holder of `node::Environment` should immediately call `node::MultiIsolatePlatform::UnregisterIsolate` and `v8::Isolate::Dispose` to cancel pending foreground tasks and join concurrent tasks after the environment was freed. `NodePlatform` can properly handle the case in `RunForegroundTask` when an Isolate out-lives its associated `node::Environment`.
1 parent 89ddc98 commit f9c4eb9

File tree

4 files changed

+30
-7
lines changed

4 files changed

+30
-7
lines changed

src/api/environment.cc

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -512,13 +512,6 @@ void FreeEnvironment(Environment* env) {
512512
RunAtExit(env);
513513
}
514514

515-
// This call needs to be made while the `Environment` is still alive
516-
// because we assume that it is available for async tracking in the
517-
// NodePlatform implementation.
518-
MultiIsolatePlatform* platform = env->isolate_data()->platform();
519-
if (platform != nullptr)
520-
platform->DrainTasks(isolate);
521-
522515
delete env;
523516
}
524517

src/node_main_instance.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ NodeMainInstance::~NodeMainInstance() {
6565
if (isolate_params_ == nullptr) {
6666
return;
6767
}
68+
69+
#ifdef DEBUG
70+
// node::Environment has been disposed and no JavaScript Execution is allowed
71+
// at this point.
72+
Isolate::DisallowJavascriptExecutionScope disallow_js(
73+
isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
74+
#endif
6875
// This should only be done on a main instance that owns its isolate.
6976
// IsolateData must be freed before UnregisterIsolate() is called.
7077
isolate_data_.reset();

src/node_platform.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ void PerIsolatePlatformData::RunForegroundTask(std::unique_ptr<Task> task) {
424424
InternalCallbackScope::kNoFlags);
425425
task->Run();
426426
} else {
427+
// When the Environment was freed, the tasks of the Isolate should also be
428+
// canceled by `NodePlatform::UnregisterIsolate`. However, if the embedder
429+
// request to run the foreground task after the Environment was freed, run
430+
// the task without InternalCallbackScope.
431+
427432
// The task is moved out of InternalCallbackScope if env is not available.
428433
// This is a required else block, and should not be removed.
429434
// See comment: https://github.com/nodejs/node/pull/34688#pullrequestreview-463867489
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Flags: --expose-gc
2+
'use strict';
3+
const common = require('../common');
4+
5+
const reg = new FinalizationRegistry(
6+
common.mustNotCall('This FinalizationRegistry callback should never be called'));
7+
8+
function register() {
9+
// Create a temporary object in a new function scope to allow it to be GC-ed.
10+
reg.register({});
11+
}
12+
13+
process.on('exit', () => {
14+
// This is the final chance to execute JavaScript.
15+
register();
16+
// Queue a FinalizationRegistryCleanupTask by a testing gc request.
17+
global.gc();
18+
});

0 commit comments

Comments
 (0)