GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 338 388 87.1 %
Date: 2022-08-29 04:21:03 Branches: 109 190 57.4 %

Line Branch Exec Source
1
#include "node.h"
2
#include "node_builtins.h"
3
#include "node_context_data.h"
4
#include "node_errors.h"
5
#include "node_internals.h"
6
#include "node_options-inl.h"
7
#include "node_platform.h"
8
#include "node_shadow_realm.h"
9
#include "node_v8_platform-inl.h"
10
#include "node_wasm_web_api.h"
11
#include "uv.h"
12
13
#if HAVE_INSPECTOR
14
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
15
#endif
16
17
namespace node {
18
using errors::TryCatchScope;
19
using v8::Array;
20
using v8::Context;
21
using v8::EscapableHandleScope;
22
using v8::Function;
23
using v8::FunctionCallbackInfo;
24
using v8::HandleScope;
25
using v8::Isolate;
26
using v8::Just;
27
using v8::Local;
28
using v8::Maybe;
29
using v8::MaybeLocal;
30
using v8::Nothing;
31
using v8::Null;
32
using v8::Object;
33
using v8::ObjectTemplate;
34
using v8::Private;
35
using v8::PropertyDescriptor;
36
using v8::SealHandleScope;
37
using v8::String;
38
using v8::Value;
39
40
378
bool AllowWasmCodeGenerationCallback(Local<Context> context,
41
                                     Local<String>) {
42
  Local<Value> wasm_code_gen =
43
756
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
44

1134
  return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
45
}
46
47
33
bool ShouldAbortOnUncaughtException(Isolate* isolate) {
48
33
  DebugSealHandleScope scope(isolate);
49
33
  Environment* env = Environment::GetCurrent(isolate);
50
33
  return env != nullptr &&
51

68
         (env->is_main_thread() || !env->is_stopping()) &&
52
63
         env->abort_on_uncaught_exception() &&
53
96
         env->should_abort_on_uncaught_toggle()[0] &&
54
34
         !env->inside_should_not_abort_on_uncaught_scope();
55
}
56
57
67539
MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
58
                                            Local<Value> exception,
59
                                            Local<Array> trace) {
60
67539
  Environment* env = Environment::GetCurrent(context);
61
67539
  if (env == nullptr) {
62
    return exception->ToString(context).FromMaybe(Local<Value>());
63
  }
64
67539
  Local<Function> prepare = env->prepare_stack_trace_callback();
65
67539
  if (prepare.IsEmpty()) {
66
    return exception->ToString(context).FromMaybe(Local<Value>());
67
  }
68
  Local<Value> args[] = {
69
      context->Global(),
70
      exception,
71
      trace,
72
135078
  };
73
  // This TryCatch + Rethrow is required by V8 due to details around exception
74
  // handling there. For C++ callbacks, V8 expects a scheduled exception (which
75
  // is what ReThrow gives us). Just returning the empty MaybeLocal would leave
76
  // us with a pending exception.
77
67539
  TryCatchScope try_catch(env);
78
  MaybeLocal<Value> result = prepare->Call(
79
135078
      context, Undefined(env->isolate()), arraysize(args), args);
80

67539
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
81
2
    try_catch.ReThrow();
82
  }
83
67539
  return result;
84
}
85
86
372664
void* NodeArrayBufferAllocator::Allocate(size_t size) {
87
  void* ret;
88

372664
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
89
61835
    ret = allocator_->Allocate(size);
90
  else
91
310829
    ret = allocator_->AllocateUninitialized(size);
92
372664
  if (LIKELY(ret != nullptr))
93
372664
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
94
372664
  return ret;
95
}
96
97
167707
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
98
167707
  void* ret = allocator_->AllocateUninitialized(size);
99
167707
  if (LIKELY(ret != nullptr))
100
167707
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
101
167707
  return ret;
102
}
103
104
62675
void* NodeArrayBufferAllocator::Reallocate(
105
    void* data, size_t old_size, size_t size) {
106
62675
  void* ret = allocator_->Reallocate(data, old_size, size);
107

62675
  if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
108
62675
    total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
109
62675
  return ret;
110
}
111
112
517493
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
113
517493
  total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
114
517493
  allocator_->Free(data, size);
115
517493
}
116
117
12
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
118
6
  CHECK(allocations_.empty());
119
12
}
120
121
80
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
122
80
  Mutex::ScopedLock lock(mutex_);
123
80
  void* data = NodeArrayBufferAllocator::Allocate(size);
124
80
  RegisterPointerInternal(data, size);
125
80
  return data;
126
}
127
128
42
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
129
42
  Mutex::ScopedLock lock(mutex_);
130
42
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
131
42
  RegisterPointerInternal(data, size);
132
42
  return data;
133
}
134
135
122
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
136
244
  Mutex::ScopedLock lock(mutex_);
137
122
  UnregisterPointerInternal(data, size);
138
122
  NodeArrayBufferAllocator::Free(data, size);
139
122
}
140
141
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
142
                                                size_t old_size,
143
                                                size_t size) {
144
  Mutex::ScopedLock lock(mutex_);
145
  void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
146
  if (ret == nullptr) {
147
    if (size == 0) {  // i.e. equivalent to free().
148
      // suppress coverity warning as data is used as key versus as pointer
149
      // in UnregisterPointerInternal
150
      // coverity[pass_freed_arg]
151
      UnregisterPointerInternal(data, old_size);
152
    }
153
    return nullptr;
154
  }
155
156
  if (data != nullptr) {
157
    auto it = allocations_.find(data);
158
    CHECK_NE(it, allocations_.end());
159
    allocations_.erase(it);
160
  }
161
162
  RegisterPointerInternal(ret, size);
163
  return ret;
164
}
165
166
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
167
  Mutex::ScopedLock lock(mutex_);
168
  NodeArrayBufferAllocator::RegisterPointer(data, size);
169
  RegisterPointerInternal(data, size);
170
}
171
172
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
173
  Mutex::ScopedLock lock(mutex_);
174
  NodeArrayBufferAllocator::UnregisterPointer(data, size);
175
  UnregisterPointerInternal(data, size);
176
}
177
178
122
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
179
                                                              size_t size) {
180
122
  if (data == nullptr) return;
181
122
  auto it = allocations_.find(data);
182
122
  CHECK_NE(it, allocations_.end());
183
122
  if (size > 0) {
184
    // We allow allocations with size 1 for 0-length buffers to avoid having
185
    // to deal with nullptr values.
186
122
    CHECK_EQ(it->second, size);
187
  }
188
122
  allocations_.erase(it);
189
}
190
191
122
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
192
                                                            size_t size) {
193
122
  if (data == nullptr) return;
194
122
  CHECK_EQ(allocations_.count(data), 0);
195
122
  allocations_[data] = size;
196
}
197
198
6212
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
199

6212
  if (debug || per_process::cli_options->debug_arraybuffer_allocations)
200
3
    return std::make_unique<DebuggingArrayBufferAllocator>();
201
  else
202
6209
    return std::make_unique<NodeArrayBufferAllocator>();
203
}
204
205
61
ArrayBufferAllocator* CreateArrayBufferAllocator() {
206
61
  return ArrayBufferAllocator::Create().release();
207
}
208
209
61
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
210
61
  delete allocator;
211
61
}
212
213
6210
void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
214
6210
  const uint64_t constrained_memory = uv_get_constrained_memory();
215
12413
  const uint64_t total_memory = constrained_memory > 0 ?
216
6203
      std::min(uv_get_total_memory(), constrained_memory) :
217
7
      uv_get_total_memory();
218
6210
  if (total_memory > 0) {
219
    // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
220
    // This default is based on browser use-cases. Tell V8 to configure the
221
    // heap based on the actual physical memory.
222
6210
    params->constraints.ConfigureDefaults(total_memory, 0);
223
  }
224
6210
  params->embedder_wrapper_object_index = BaseObject::InternalFields::kSlot;
225
6210
  params->embedder_wrapper_type_index = std::numeric_limits<int>::max();
226
6210
}
227
228
6210
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
229
6210
  if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
230
6210
    isolate->AddMessageListenerWithErrorLevel(
231
            errors::PerIsolateMessageListener,
232
            Isolate::MessageErrorLevel::kMessageError |
233
                Isolate::MessageErrorLevel::kMessageWarning);
234
235
6210
  auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
236
      s.should_abort_on_uncaught_exception_callback :
237
      ShouldAbortOnUncaughtException;
238
6210
  isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
239
240
6210
  auto* fatal_error_cb = s.fatal_error_callback ?
241
      s.fatal_error_callback : OnFatalError;
242
6210
  isolate->SetFatalErrorHandler(fatal_error_cb);
243
6210
  isolate->SetOOMErrorHandler(OOMErrorHandler);
244
245
6210
  if ((s.flags & SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK) == 0) {
246
6210
    auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
247
        s.prepare_stack_trace_callback : PrepareStackTraceCallback;
248
6210
    isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
249
  }
250
6210
}
251
252
6217
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
253
6217
  isolate->SetMicrotasksPolicy(s.policy);
254
255
6217
  auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
256
    s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
257
6217
  isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
258
6217
  isolate->SetModifyCodeGenerationFromStringsCallback(
259
      ModifyCodeGenerationFromStrings);
260
261
12434
  Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
262
6217
  if (per_process::cli_options->get_per_isolate_options()
263
6217
          ->get_per_env_options()
264
6217
          ->experimental_fetch) {
265
6216
    isolate->SetWasmStreamingCallback(wasm_web_api::StartStreamingCompilation);
266
  }
267
268
6217
  if (per_process::cli_options->get_per_isolate_options()
269
6217
          ->experimental_shadow_realm) {
270
1
    isolate->SetHostCreateShadowRealmContextCallback(
271
        shadow_realm::HostCreateShadowRealmContextCallback);
272
  }
273
274
6217
  if ((s.flags & SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK) == 0) {
275
6217
    auto* promise_reject_cb = s.promise_reject_callback ?
276
      s.promise_reject_callback : PromiseRejectCallback;
277
6217
    isolate->SetPromiseRejectCallback(promise_reject_cb);
278
  }
279
280
6217
  if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
281
6217
    v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
282
6217
}
283
284
800
void SetIsolateUpForNode(v8::Isolate* isolate,
285
                         const IsolateSettings& settings) {
286
800
  SetIsolateErrorHandlers(isolate, settings);
287
800
  SetIsolateMiscHandlers(isolate, settings);
288
800
}
289
290
800
void SetIsolateUpForNode(v8::Isolate* isolate) {
291
800
  IsolateSettings settings;
292
800
  SetIsolateUpForNode(isolate, settings);
293
800
}
294
295
// TODO(joyeecheung): we may want to expose this, but then we need to be
296
// careful about what we override in the params.
297
67
Isolate* NewIsolate(Isolate::CreateParams* params,
298
                    uv_loop_t* event_loop,
299
                    MultiIsolatePlatform* platform) {
300
67
  Isolate* isolate = Isolate::Allocate();
301
67
  if (isolate == nullptr) return nullptr;
302
303
  // Register the isolate on the platform before the isolate gets initialized,
304
  // so that the isolate can access the platform during initialization.
305
67
  platform->RegisterIsolate(isolate, event_loop);
306
307
67
  SetIsolateCreateParamsForNode(params);
308
67
  Isolate::Initialize(isolate, *params);
309
67
  SetIsolateUpForNode(isolate);
310
311
67
  return isolate;
312
}
313
314
59
Isolate* NewIsolate(ArrayBufferAllocator* allocator,
315
                    uv_loop_t* event_loop,
316
                    MultiIsolatePlatform* platform) {
317
118
  Isolate::CreateParams params;
318
59
  if (allocator != nullptr) params.array_buffer_allocator = allocator;
319
59
  return NewIsolate(&params, event_loop, platform);
320
}
321
322
8
Isolate* NewIsolate(std::shared_ptr<ArrayBufferAllocator> allocator,
323
                    uv_loop_t* event_loop,
324
                    MultiIsolatePlatform* platform) {
325
16
  Isolate::CreateParams params;
326
8
  if (allocator) params.array_buffer_allocator_shared = allocator;
327
8
  return NewIsolate(&params, event_loop, platform);
328
}
329
330
783
IsolateData* CreateIsolateData(Isolate* isolate,
331
                               uv_loop_t* loop,
332
                               MultiIsolatePlatform* platform,
333
                               ArrayBufferAllocator* allocator) {
334
783
  return new IsolateData(isolate, loop, platform, allocator);
335
}
336
337
781
void FreeIsolateData(IsolateData* isolate_data) {
338
781
  delete isolate_data;
339
781
}
340
341
1920
InspectorParentHandle::~InspectorParentHandle() {}
342
343
// Hide the internal handle class from the public API.
344
#if HAVE_INSPECTOR
345
struct InspectorParentHandleImpl : public InspectorParentHandle {
346
  std::unique_ptr<inspector::ParentInspectorHandle> impl;
347
348
960
  explicit InspectorParentHandleImpl(
349
      std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
350
960
    : impl(std::move(impl)) {}
351
};
352
#endif
353
354
772
Environment* CreateEnvironment(
355
    IsolateData* isolate_data,
356
    Local<Context> context,
357
    const std::vector<std::string>& args,
358
    const std::vector<std::string>& exec_args,
359
    EnvironmentFlags::Flags flags,
360
    ThreadId thread_id,
361
    std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
362
772
  Isolate* isolate = context->GetIsolate();
363
1544
  HandleScope handle_scope(isolate);
364
772
  Context::Scope context_scope(context);
365
  // TODO(addaleax): This is a much better place for parsing per-Environment
366
  // options than the global parse call.
367
  Environment* env = new Environment(
368
772
      isolate_data, context, args, exec_args, nullptr, flags, thread_id);
369
#if HAVE_INSPECTOR
370
772
  if (env->should_create_inspector()) {
371
772
    if (inspector_parent_handle) {
372
723
      env->InitializeInspector(
373
          std::move(static_cast<InspectorParentHandleImpl*>(
374
723
              inspector_parent_handle.get())->impl));
375
    } else {
376
49
      env->InitializeInspector({});
377
    }
378
  }
379
#endif
380
381
1544
  if (env->RunBootstrapping().IsEmpty()) {
382
    FreeEnvironment(env);
383
    return nullptr;
384
  }
385
386
772
  return env;
387
}
388
389
5548
void FreeEnvironment(Environment* env) {
390
5548
  Isolate* isolate = env->isolate();
391
  Isolate::DisallowJavascriptExecutionScope disallow_js(isolate,
392
11096
      Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
393
  {
394
11096
    HandleScope handle_scope(isolate);  // For env->context().
395
5548
    Context::Scope context_scope(env->context());
396
11096
    SealHandleScope seal_handle_scope(isolate);
397
398
5548
    env->set_stopping(true);
399
5548
    env->stop_sub_worker_contexts();
400
5548
    env->RunCleanup();
401
5548
    RunAtExit(env);
402
  }
403
404
  // This call needs to be made while the `Environment` is still alive
405
  // because we assume that it is available for async tracking in the
406
  // NodePlatform implementation.
407
5548
  MultiIsolatePlatform* platform = env->isolate_data()->platform();
408
5548
  if (platform != nullptr)
409
5548
    platform->DrainTasks(isolate);
410
411
5548
  delete env;
412
5548
}
413
414
960
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
415
    Environment* env,
416
    ThreadId thread_id,
417
    const char* url) {
418
960
  CHECK_NOT_NULL(env);
419
960
  CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
420
#if HAVE_INSPECTOR
421
1920
  return std::make_unique<InspectorParentHandleImpl>(
422
2880
      env->inspector_agent()->GetParentHandle(thread_id.id, url));
423
#else
424
  return {};
425
#endif
426
}
427
428
6156
MaybeLocal<Value> LoadEnvironment(
429
    Environment* env,
430
    StartExecutionCallback cb) {
431
6156
  env->InitializeLibuv();
432
6156
  env->InitializeDiagnostics();
433
434
6156
  return StartExecution(env, cb);
435
}
436
437
19
MaybeLocal<Value> LoadEnvironment(
438
    Environment* env,
439
    const char* main_script_source_utf8) {
440
19
  CHECK_NOT_NULL(main_script_source_utf8);
441
19
  Isolate* isolate = env->isolate();
442
  return LoadEnvironment(
443
      env,
444
19
      [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
445
        // This is a slightly hacky way to convert UTF-8 to UTF-16.
446
        Local<String> str =
447
38
            String::NewFromUtf8(isolate,
448
19
                                main_script_source_utf8).ToLocalChecked();
449
36
        auto main_utf16 = std::make_unique<String::Value>(isolate, str);
450
451
        // TODO(addaleax): Avoid having a global table for all scripts.
452
36
        std::string name = "embedder_main_" + std::to_string(env->thread_id());
453
19
        builtins::BuiltinLoader::Add(
454
19
            name.c_str(), UnionBytes(**main_utf16, main_utf16->length()));
455
19
        env->set_main_utf16(std::move(main_utf16));
456
        // Arguments must match the parameters specified in
457
        // BuiltinLoader::LookupAndCompile().
458
        std::vector<Local<Value>> args = {env->process_object(),
459
74
                                          env->builtin_module_require()};
460
19
        return ExecuteBootstrapper(env, name.c_str(), &args);
461
19
      });
462
}
463
464
7
Environment* GetCurrentEnvironment(Local<Context> context) {
465
7
  return Environment::GetCurrent(context);
466
}
467
468
1
IsolateData* GetEnvironmentIsolateData(Environment* env) {
469
1
  return env->isolate_data();
470
}
471
472
1
ArrayBufferAllocator* GetArrayBufferAllocator(IsolateData* isolate_data) {
473
1
  return isolate_data->node_allocator();
474
}
475
476
5828
MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env) {
477
5828
  return GetMultiIsolatePlatform(env->isolate_data());
478
}
479
480
5828
MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
481
5828
  return env->platform();
482
}
483
484
MultiIsolatePlatform* CreatePlatform(
485
    int thread_pool_size,
486
    node::tracing::TracingController* tracing_controller) {
487
  return CreatePlatform(
488
      thread_pool_size,
489
      static_cast<v8::TracingController*>(tracing_controller));
490
}
491
492
MultiIsolatePlatform* CreatePlatform(
493
    int thread_pool_size,
494
    v8::TracingController* tracing_controller) {
495
  return MultiIsolatePlatform::Create(thread_pool_size,
496
                                      tracing_controller)
497
      .release();
498
}
499
500
void FreePlatform(MultiIsolatePlatform* platform) {
501
  delete platform;
502
}
503
504
7
std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
505
    int thread_pool_size,
506
    v8::TracingController* tracing_controller,
507
    v8::PageAllocator* page_allocator) {
508
14
  return std::make_unique<NodePlatform>(thread_pool_size,
509
                                        tracing_controller,
510
7
                                        page_allocator);
511
}
512
513
36423
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
514
36423
  Isolate* isolate = context->GetIsolate();
515
36423
  EscapableHandleScope handle_scope(isolate);
516
517
36423
  Local<Object> global = context->Global();
518
  Local<Private> key = Private::ForApi(isolate,
519
36423
      FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
520
521
  Local<Value> existing_value;
522
72846
  if (!global->GetPrivate(context, key).ToLocal(&existing_value))
523
    return MaybeLocal<Object>();
524
36423
  if (existing_value->IsObject())
525
36351
    return handle_scope.Escape(existing_value.As<Object>());
526
527
72
  Local<Object> exports = Object::New(isolate);
528
288
  if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
529

216
      InitializePrimordials(context).IsNothing())
530
    return MaybeLocal<Object>();
531
72
  return handle_scope.Escape(exports);
532
}
533
534
// Any initialization logic should be performed in
535
// InitializeContext, because embedders don't necessarily
536
// call NewContext and so they will experience breakages.
537
66
Local<Context> NewContext(Isolate* isolate,
538
                          Local<ObjectTemplate> object_template) {
539
132
  auto context = Context::New(isolate, nullptr, object_template);
540
66
  if (context.IsEmpty()) return context;
541
542
132
  if (InitializeContext(context).IsNothing()) {
543
    return Local<Context>();
544
  }
545
546
66
  return context;
547
}
548
549
8
void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
550
8
  THROW_ERR_PROTO_ACCESS(info.GetIsolate());
551
8
}
552
553
// This runs at runtime, regardless of whether the context
554
// is created from a snapshot.
555
6806
Maybe<bool> InitializeContextRuntime(Local<Context> context) {
556
6806
  Isolate* isolate = context->GetIsolate();
557
13612
  HandleScope handle_scope(isolate);
558
559
  // When `IsCodeGenerationFromStringsAllowed` is true, V8 takes the fast path
560
  // and ignores the ModifyCodeGenerationFromStrings callback. Set it to false
561
  // to delegate the code generation validation to
562
  // node::ModifyCodeGenerationFromStrings.
563
  // The `IsCodeGenerationFromStringsAllowed` can be refreshed by V8 according
564
  // to the runtime flags, propagate the value to the embedder data.
565
  bool is_code_generation_from_strings_allowed =
566
6806
      context->IsCodeGenerationFromStringsAllowed();
567
6806
  context->AllowCodeGenerationFromStrings(false);
568
13612
  context->SetEmbedderData(
569
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
570
      is_code_generation_from_strings_allowed ? True(isolate) : False(isolate));
571
572
6806
  if (per_process::cli_options->disable_proto == "") {
573
6798
    return Just(true);
574
  }
575
576
  // Remove __proto__
577
  // https://github.com/nodejs/node/issues/31951
578
  Local<Object> prototype;
579
  {
580
    Local<String> object_string =
581
8
      FIXED_ONE_BYTE_STRING(isolate, "Object");
582
    Local<String> prototype_string =
583
8
      FIXED_ONE_BYTE_STRING(isolate, "prototype");
584
585
    Local<Value> object_v;
586
8
    if (!context->Global()
587
8
        ->Get(context, object_string)
588
8
        .ToLocal(&object_v)) {
589
      return Nothing<bool>();
590
    }
591
592
    Local<Value> prototype_v;
593
8
    if (!object_v.As<Object>()
594
8
        ->Get(context, prototype_string)
595
8
        .ToLocal(&prototype_v)) {
596
      return Nothing<bool>();
597
    }
598
599
8
    prototype = prototype_v.As<Object>();
600
  }
601
602
  Local<String> proto_string =
603
8
    FIXED_ONE_BYTE_STRING(isolate, "__proto__");
604
605
8
  if (per_process::cli_options->disable_proto == "delete") {
606
4
    if (prototype
607
4
        ->Delete(context, proto_string)
608
4
        .IsNothing()) {
609
      return Nothing<bool>();
610
    }
611
4
  } else if (per_process::cli_options->disable_proto == "throw") {
612
    Local<Value> thrower;
613
4
    if (!Function::New(context, ProtoThrower)
614
4
        .ToLocal(&thrower)) {
615
      return Nothing<bool>();
616
    }
617
618
4
    PropertyDescriptor descriptor(thrower, thrower);
619
4
    descriptor.set_enumerable(false);
620
4
    descriptor.set_configurable(true);
621
4
    if (prototype
622
4
        ->DefineProperty(context, proto_string, descriptor)
623
4
        .IsNothing()) {
624
      return Nothing<bool>();
625
    }
626
  } else if (per_process::cli_options->disable_proto != "") {
627
    // Validated in ProcessGlobalArgs
628
    FatalError("InitializeContextRuntime()",
629
               "invalid --disable-proto mode");
630
  }
631
632
8
  return Just(true);
633
}
634
635
76
Maybe<bool> InitializeBaseContextForSnapshot(Local<Context> context) {
636
76
  Isolate* isolate = context->GetIsolate();
637
152
  HandleScope handle_scope(isolate);
638
639
  // Delete `Intl.v8BreakIterator`
640
  // https://github.com/nodejs/node/issues/14909
641
  {
642
76
    Context::Scope context_scope(context);
643
76
    Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
644
    Local<String> break_iter_string =
645
76
        FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
646
647
    Local<Value> intl_v;
648
228
    if (!context->Global()->Get(context, intl_string).ToLocal(&intl_v)) {
649
      return Nothing<bool>();
650
    }
651
652
152
    if (intl_v->IsObject() &&
653

228
        intl_v.As<Object>()->Delete(context, break_iter_string).IsNothing()) {
654
      return Nothing<bool>();
655
    }
656
  }
657
76
  return Just(true);
658
}
659
660
67
Maybe<bool> InitializeMainContextForSnapshot(Local<Context> context) {
661
67
  Isolate* isolate = context->GetIsolate();
662
134
  HandleScope handle_scope(isolate);
663
664
  // Initialize the default values.
665
134
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
666
                           True(isolate));
667
134
  context->SetEmbedderData(
668
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings, True(isolate));
669
670
134
  if (InitializeBaseContextForSnapshot(context).IsNothing()) {
671
    return Nothing<bool>();
672
  }
673
67
  return InitializePrimordials(context);
674
}
675
676
139
Maybe<bool> InitializePrimordials(Local<Context> context) {
677
  // Run per-context JS files.
678
139
  Isolate* isolate = context->GetIsolate();
679
139
  Context::Scope context_scope(context);
680
  Local<Object> exports;
681
682
  Local<String> primordials_string =
683
139
      FIXED_ONE_BYTE_STRING(isolate, "primordials");
684
685
  // Create primordials first and make it available to per-context scripts.
686
139
  Local<Object> primordials = Object::New(isolate);
687
278
  if (primordials->SetPrototype(context, Null(isolate)).IsNothing() ||
688

417
      !GetPerContextExports(context).ToLocal(&exports) ||
689

417
      exports->Set(context, primordials_string, primordials).IsNothing()) {
690
    return Nothing<bool>();
691
  }
692
693
  static const char* context_files[] = {"internal/per_context/primordials",
694
                                        "internal/per_context/domexception",
695
                                        "internal/per_context/messageport",
696
                                        nullptr};
697
698
556
  for (const char** module = context_files; *module != nullptr; module++) {
699
    // Arguments must match the parameters specified in
700
    // BuiltinLoader::LookupAndCompile().
701
834
    Local<Value> arguments[] = {context->Global(), exports, primordials};
702
    MaybeLocal<Function> maybe_fn =
703
417
        builtins::BuiltinLoader::LookupAndCompile(context, *module, nullptr);
704
    Local<Function> fn;
705
417
    if (!maybe_fn.ToLocal(&fn)) {
706
      return Nothing<bool>();
707
    }
708
    MaybeLocal<Value> result =
709
834
        fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
710
    // Execution failed during context creation.
711
417
    if (result.IsEmpty()) {
712
      return Nothing<bool>();
713
    }
714
  }
715
716
139
  return Just(true);
717
}
718
719
// This initializes the main context (i.e. vm contexts are not included).
720
67
Maybe<bool> InitializeContext(Local<Context> context) {
721
134
  if (InitializeMainContextForSnapshot(context).IsNothing()) {
722
    return Nothing<bool>();
723
  }
724
725
67
  return InitializeContextRuntime(context);
726
}
727
728
10
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
729
20
  HandleScope handle_scope(isolate);
730
10
  Local<Context> context = isolate->GetCurrentContext();
731
10
  if (context.IsEmpty()) return nullptr;
732
10
  Environment* env = Environment::GetCurrent(context);
733
10
  if (env == nullptr) return nullptr;
734
10
  return env->event_loop();
735
}
736
737
9
void AddLinkedBinding(Environment* env, const node_module& mod) {
738
9
  CHECK_NOT_NULL(env);
739
18
  Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
740
741
9
  node_module* prev_tail = env->extra_linked_bindings_tail();
742
9
  env->extra_linked_bindings()->push_back(mod);
743
9
  if (prev_tail != nullptr)
744
5
    prev_tail->nm_link = &env->extra_linked_bindings()->back();
745
9
}
746
747
3
void AddLinkedBinding(Environment* env, const napi_module& mod) {
748
3
  AddLinkedBinding(env, napi_module_to_node_module(&mod));
749
3
}
750
751
6
void AddLinkedBinding(Environment* env,
752
                      const char* name,
753
                      addon_context_register_func fn,
754
                      void* priv) {
755
6
  node_module mod = {
756
    NODE_MODULE_VERSION,
757
    NM_F_LINKED,
758
    nullptr,  // nm_dso_handle
759
    nullptr,  // nm_filename
760
    nullptr,  // nm_register_func
761
    fn,
762
    name,
763
    priv,
764
    nullptr   // nm_link
765
6
  };
766
6
  AddLinkedBinding(env, mod);
767
6
}
768
769
static std::atomic<uint64_t> next_thread_id{0};
770
771
6426
ThreadId AllocateEnvironmentThreadId() {
772
6426
  return ThreadId { next_thread_id++ };
773
}
774
775
636
void DefaultProcessExitHandler(Environment* env, int exit_code) {
776
636
  env->set_can_call_into_js(false);
777
636
  env->stop_sub_worker_contexts();
778
636
  DisposePlatform();
779
636
  uv_library_shutdown();
780
636
  exit(exit_code);
781
}
782
783
784
724
void SetProcessExitHandler(Environment* env,
785
                           std::function<void(Environment*, int)>&& handler) {
786
724
  env->set_process_exit_handler(std::move(handler));
787
724
}
788
789
}  // namespace node