Coverage Report

Created: 2026-01-21 08:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/node_main_instance.cc
Line
Count
Source
1
#include "node_main_instance.h"
2
#include <memory>
3
#if HAVE_OPENSSL
4
#include "crypto/crypto_util.h"
5
#endif  // HAVE_OPENSSL
6
#include "debug_utils-inl.h"
7
#include "node_builtins.h"
8
#include "node_external_reference.h"
9
#include "node_internals.h"
10
#include "node_options-inl.h"
11
#include "node_realm.h"
12
#include "node_sea.h"
13
#include "node_snapshot_builder.h"
14
#include "node_snapshotable.h"
15
#include "node_v8_platform-inl.h"
16
#include "util-inl.h"
17
#if defined(LEAK_SANITIZER)
18
#include <sanitizer/lsan_interface.h>
19
#endif
20
21
#if HAVE_INSPECTOR
22
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
23
#endif
24
25
namespace node {
26
27
using v8::Context;
28
using v8::HandleScope;
29
using v8::Isolate;
30
using v8::Local;
31
using v8::Locker;
32
33
NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
34
                                   uv_loop_t* event_loop,
35
                                   MultiIsolatePlatform* platform,
36
                                   const std::vector<std::string>& args,
37
                                   const std::vector<std::string>& exec_args)
38
0
    : args_(args),
39
0
      exec_args_(exec_args),
40
0
      array_buffer_allocator_(ArrayBufferAllocator::Create()),
41
0
      isolate_(nullptr),
42
0
      platform_(platform),
43
0
      isolate_data_(),
44
0
      isolate_params_(std::make_unique<Isolate::CreateParams>()),
45
0
      snapshot_data_(snapshot_data) {
46
0
  isolate_params_->array_buffer_allocator = array_buffer_allocator_.get();
47
48
0
  isolate_ =
49
0
      NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data);
50
0
  CHECK_NOT_NULL(isolate_);
51
52
  // If the indexes are not nullptr, we are not deserializing
53
0
  isolate_data_.reset(
54
0
      CreateIsolateData(isolate_,
55
0
                        event_loop,
56
0
                        platform,
57
0
                        array_buffer_allocator_.get(),
58
0
                        snapshot_data->AsEmbedderWrapper().get()));
59
60
0
  isolate_data_->max_young_gen_size =
61
0
      isolate_params_->constraints.max_young_generation_size_in_bytes();
62
0
}
63
64
0
NodeMainInstance::~NodeMainInstance() {
65
0
  if (isolate_params_ == nullptr) {
66
0
    return;
67
0
  }
68
69
0
  {
70
#ifdef DEBUG
71
    // node::Environment has been disposed and no JavaScript Execution is
72
    // allowed at this point.
73
    // Create a scope to check that no JavaScript is executed in debug build
74
    // and proactively crash the process in the case JavaScript is being
75
    // executed.
76
    // Isolate::Dispose() must be invoked outside of this scope to avoid
77
    // use-after-free.
78
    Isolate::DisallowJavascriptExecutionScope disallow_js(
79
        isolate_, Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
80
#endif
81
    // This should only be done on a main instance that owns its isolate.
82
    // IsolateData must be freed before UnregisterIsolate() is called.
83
0
    isolate_data_.reset();
84
0
  }
85
0
  platform_->DisposeIsolate(isolate_);
86
0
}
87
88
0
ExitCode NodeMainInstance::Run() {
89
0
  Locker locker(isolate_);
90
0
  Isolate::Scope isolate_scope(isolate_);
91
0
  HandleScope handle_scope(isolate_);
92
93
0
  ExitCode exit_code = ExitCode::kNoFailure;
94
0
  DeleteFnPtr<Environment, FreeEnvironment> env =
95
0
      CreateMainEnvironment(&exit_code);
96
0
  CHECK_NOT_NULL(env);
97
98
0
  Context::Scope context_scope(env->context());
99
0
  Run(&exit_code, env.get());
100
0
  return exit_code;
101
0
}
102
103
0
void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) {
104
0
  if (*exit_code == ExitCode::kNoFailure) {
105
0
    if (!sea::MaybeLoadSingleExecutableApplication(env)) {
106
0
      LoadEnvironment(env, StartExecutionCallback{});
107
0
    }
108
109
0
    *exit_code =
110
0
        SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError);
111
0
  }
112
113
#if defined(LEAK_SANITIZER)
114
  __lsan_do_leak_check();
115
#endif
116
0
}
117
118
DeleteFnPtr<Environment, FreeEnvironment>
119
0
NodeMainInstance::CreateMainEnvironment(ExitCode* exit_code) {
120
0
  *exit_code = ExitCode::kNoFailure;  // Reset the exit code to 0
121
122
0
  HandleScope handle_scope(isolate_);
123
124
  // TODO(addaleax): This should load a real per-Isolate option, currently
125
  // this is still effectively per-process.
126
0
  if (isolate_data_->options()->track_heap_objects) {
127
0
    isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true);
128
0
  }
129
130
0
  Local<Context> context;
131
0
  DeleteFnPtr<Environment, FreeEnvironment> env;
132
133
0
  if (snapshot_data_ != nullptr) {
134
0
    env.reset(CreateEnvironment(isolate_data_.get(),
135
0
                                Local<Context>(),  // read from snapshot
136
0
                                args_,
137
0
                                exec_args_));
138
0
#if HAVE_OPENSSL
139
0
    crypto::InitCryptoOnce(isolate_);
140
0
#endif  // HAVE_OPENSSL
141
0
  } else {
142
0
    context = NewContext(isolate_);
143
0
    CHECK(!context.IsEmpty());
144
0
    Context::Scope context_scope(context);
145
0
    env.reset(
146
0
        CreateEnvironment(isolate_data_.get(), context, args_, exec_args_));
147
0
  }
148
149
0
  return env;
150
0
}
151
152
}  // namespace node