src: avoid draining platform tasks at FreeEnvironment · nodejs/node@d9d9e62 · GitHub
Skip to content

Commit d9d9e62

Browse files
legendecasrichardlau
authored andcommitted
src: avoid draining platform 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`. PR-URL: #51290 Fixes: #47748 Fixes: #49344 Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent e5fc8ec commit d9d9e62

4 files changed

Lines changed: 46 additions & 9 deletions

File tree

src/api/environment.cc

Lines changed: 0 additions & 7 deletions

src/node_main_instance.cc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,24 @@ NodeMainInstance::~NodeMainInstance() {
103103
if (isolate_params_ == nullptr) {
104104
return;
105105
}
106-
// This should only be done on a main instance that owns its isolate.
107-
platform_->UnregisterIsolate(isolate_);
106+
107+
{
108+
#ifdef DEBUG
109+
// node::Environment has been disposed and no JavaScript Execution is
110+
// allowed at this point.
111+
// Create a scope to check that no JavaScript is executed in debug build
112+
// and proactively crash the process in the case JavaScript is being
113+
// executed.
114+
// Isolate::Dispose() must be invoked outside of this scope to avoid
115+
// use-after-free.
116+
Isolate::DisallowJavascriptExecutionScope disallow_js(
117+
isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
118+
#endif
119+
// This should only be done on a main instance that owns its isolate.
120+
// IsolateData must be freed before UnregisterIsolate() is called.
121+
isolate_data_.reset();
122+
platform_->UnregisterIsolate(isolate_);
123+
}
108124
isolate_->Dispose();
109125
}
110126

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: 23 additions & 0 deletions

0 commit comments

Comments
 (0)