Files
node/src/node_main_instance.cc
T
Joyee Cheung 5d3e1b555c src,test: unregister the isolate after disposal and before freeing
The order of these calls is important. When the Isolate is disposed,
it may still post tasks to the platform, so it must still be registered
for the task runner to be found from the map. After the isolate is torn
down, we need to remove it from the map before we can free the address,
so that when another Isolate::Allocate() is called, that would not be
allocated to the same address and be registered on an existing map
entry.

PR-URL: https://github.com/nodejs/node/pull/58070
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
2025-05-02 15:10:39 +02:00

153 lines
4.6 KiB
C++

#include "node_main_instance.h"
#include <memory>
#if HAVE_OPENSSL
#include "crypto/crypto_util.h"
#endif // HAVE_OPENSSL
#include "debug_utils-inl.h"
#include "node_builtins.h"
#include "node_external_reference.h"
#include "node_internals.h"
#include "node_options-inl.h"
#include "node_realm.h"
#include "node_sea.h"
#include "node_snapshot_builder.h"
#include "node_snapshotable.h"
#include "node_v8_platform-inl.h"
#include "util-inl.h"
#if defined(LEAK_SANITIZER)
#include <sanitizer/lsan_interface.h>
#endif
#if HAVE_INSPECTOR
#include "inspector/worker_inspector.h" // ParentInspectorHandle
#endif
namespace node {
using v8::Context;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Locker;
NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform,
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args)
: args_(args),
exec_args_(exec_args),
array_buffer_allocator_(ArrayBufferAllocator::Create()),
isolate_(nullptr),
platform_(platform),
isolate_data_(),
isolate_params_(std::make_unique<Isolate::CreateParams>()),
snapshot_data_(snapshot_data) {
isolate_params_->array_buffer_allocator = array_buffer_allocator_.get();
isolate_ =
NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data);
CHECK_NOT_NULL(isolate_);
// If the indexes are not nullptr, we are not deserializing
isolate_data_.reset(
CreateIsolateData(isolate_,
event_loop,
platform,
array_buffer_allocator_.get(),
snapshot_data->AsEmbedderWrapper().get()));
isolate_data_->max_young_gen_size =
isolate_params_->constraints.max_young_generation_size_in_bytes();
}
NodeMainInstance::~NodeMainInstance() {
if (isolate_params_ == nullptr) {
return;
}
{
#ifdef DEBUG
// node::Environment has been disposed and no JavaScript Execution is
// allowed at this point.
// Create a scope to check that no JavaScript is executed in debug build
// and proactively crash the process in the case JavaScript is being
// executed.
// Isolate::Dispose() must be invoked outside of this scope to avoid
// use-after-free.
Isolate::DisallowJavascriptExecutionScope disallow_js(
isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
#endif
// This should only be done on a main instance that owns its isolate.
// IsolateData must be freed before UnregisterIsolate() is called.
isolate_data_.reset();
}
platform_->DisposeIsolate(isolate_);
}
ExitCode NodeMainInstance::Run() {
Locker locker(isolate_);
Isolate::Scope isolate_scope(isolate_);
HandleScope handle_scope(isolate_);
ExitCode exit_code = ExitCode::kNoFailure;
DeleteFnPtr<Environment, FreeEnvironment> env =
CreateMainEnvironment(&exit_code);
CHECK_NOT_NULL(env);
Context::Scope context_scope(env->context());
Run(&exit_code, env.get());
return exit_code;
}
void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) {
if (*exit_code == ExitCode::kNoFailure) {
if (!sea::MaybeLoadSingleExecutableApplication(env)) {
LoadEnvironment(env, StartExecutionCallback{});
}
*exit_code =
SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError);
}
#if defined(LEAK_SANITIZER)
__lsan_do_leak_check();
#endif
}
DeleteFnPtr<Environment, FreeEnvironment>
NodeMainInstance::CreateMainEnvironment(ExitCode* exit_code) {
*exit_code = ExitCode::kNoFailure; // Reset the exit code to 0
HandleScope handle_scope(isolate_);
// TODO(addaleax): This should load a real per-Isolate option, currently
// this is still effectively per-process.
if (isolate_data_->options()->track_heap_objects) {
isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true);
}
Local<Context> context;
DeleteFnPtr<Environment, FreeEnvironment> env;
if (snapshot_data_ != nullptr) {
env.reset(CreateEnvironment(isolate_data_.get(),
Local<Context>(), // read from snapshot
args_,
exec_args_));
#if HAVE_OPENSSL
crypto::InitCryptoOnce(isolate_);
#endif // HAVE_OPENSSL
} else {
context = NewContext(isolate_);
CHECK(!context.IsEmpty());
Context::Scope context_scope(context);
env.reset(
CreateEnvironment(isolate_data_.get(), context, args_, exec_args_));
}
return env;
}
} // namespace node