Coverage Report

Created: 2025-07-04 09:33

/src/node/src/node_main_instance.cc
Line
Count
Source (jump to first uncovered line)
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
    platform_->UnregisterIsolate(isolate_);
85
0
  }
86
0
  isolate_->Dispose();
87
0
}
88
89
0
ExitCode NodeMainInstance::Run() {
90
0
  Locker locker(isolate_);
91
0
  Isolate::Scope isolate_scope(isolate_);
92
0
  HandleScope handle_scope(isolate_);
93
94
0
  ExitCode exit_code = ExitCode::kNoFailure;
95
0
  DeleteFnPtr<Environment, FreeEnvironment> env =
96
0
      CreateMainEnvironment(&exit_code);
97
0
  CHECK_NOT_NULL(env);
98
99
0
  Context::Scope context_scope(env->context());
100
0
  Run(&exit_code, env.get());
101
0
  return exit_code;
102
0
}
103
104
0
void NodeMainInstance::Run(ExitCode* exit_code, Environment* env) {
105
0
  if (*exit_code == ExitCode::kNoFailure) {
106
0
    bool runs_sea_code = false;
107
0
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
108
0
    if (sea::IsSingleExecutable()) {
109
0
      sea::SeaResource sea = sea::FindSingleExecutableResource();
110
0
      if (!sea.use_snapshot()) {
111
0
        runs_sea_code = true;
112
0
        std::string_view code = sea.main_code_or_snapshot;
113
0
        LoadEnvironment(env, code);
114
0
      }
115
0
    }
116
0
#endif
117
    // Either there is already a snapshot main function from SEA, or it's not
118
    // a SEA at all.
119
0
    if (!runs_sea_code) {
120
0
      LoadEnvironment(env, StartExecutionCallback{});
121
0
    }
122
123
0
    *exit_code =
124
0
        SpinEventLoopInternal(env).FromMaybe(ExitCode::kGenericUserError);
125
0
  }
126
127
#if defined(LEAK_SANITIZER)
128
  __lsan_do_leak_check();
129
#endif
130
0
}
131
132
DeleteFnPtr<Environment, FreeEnvironment>
133
0
NodeMainInstance::CreateMainEnvironment(ExitCode* exit_code) {
134
0
  *exit_code = ExitCode::kNoFailure;  // Reset the exit code to 0
135
136
0
  HandleScope handle_scope(isolate_);
137
138
  // TODO(addaleax): This should load a real per-Isolate option, currently
139
  // this is still effectively per-process.
140
0
  if (isolate_data_->options()->track_heap_objects) {
141
0
    isolate_->GetHeapProfiler()->StartTrackingHeapObjects(true);
142
0
  }
143
144
0
  Local<Context> context;
145
0
  DeleteFnPtr<Environment, FreeEnvironment> env;
146
147
0
  if (snapshot_data_ != nullptr) {
148
0
    env.reset(CreateEnvironment(isolate_data_.get(),
149
0
                                Local<Context>(),  // read from snapshot
150
0
                                args_,
151
0
                                exec_args_));
152
0
#if HAVE_OPENSSL
153
0
    crypto::InitCryptoOnce(isolate_);
154
0
#endif  // HAVE_OPENSSL
155
0
  } else {
156
0
    context = NewContext(isolate_);
157
0
    CHECK(!context.IsEmpty());
158
0
    Context::Scope context_scope(context);
159
0
    env.reset(
160
0
        CreateEnvironment(isolate_data_.get(), context, args_, exec_args_));
161
0
  }
162
163
0
  return env;
164
0
}
165
166
}  // namespace node