GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_contextify.cc Lines: 418 465 89.9 %
Date: 2019-01-07 12:15:22 Branches: 251 356 70.5 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_errors.h"
23
#include "node_internals.h"
24
#include "node_watchdog.h"
25
#include "base_object-inl.h"
26
#include "node_contextify.h"
27
#include "node_context_data.h"
28
#include "node_errors.h"
29
#include "module_wrap.h"
30
31
namespace node {
32
namespace contextify {
33
34
using errors::TryCatchScope;
35
36
using v8::Array;
37
using v8::ArrayBuffer;
38
using v8::ArrayBufferView;
39
using v8::Boolean;
40
using v8::Context;
41
using v8::EscapableHandleScope;
42
using v8::External;
43
using v8::Function;
44
using v8::FunctionCallbackInfo;
45
using v8::FunctionTemplate;
46
using v8::HandleScope;
47
using v8::IndexedPropertyHandlerConfiguration;
48
using v8::Integer;
49
using v8::Isolate;
50
using v8::Just;
51
using v8::Local;
52
using v8::Maybe;
53
using v8::MaybeLocal;
54
using v8::Name;
55
using v8::NamedPropertyHandlerConfiguration;
56
using v8::Number;
57
using v8::Object;
58
using v8::ObjectTemplate;
59
using v8::PrimitiveArray;
60
using v8::PropertyAttribute;
61
using v8::PropertyCallbackInfo;
62
using v8::PropertyDescriptor;
63
using v8::Script;
64
using v8::ScriptCompiler;
65
using v8::ScriptOrigin;
66
using v8::String;
67
using v8::Symbol;
68
using v8::Uint32;
69
using v8::UnboundScript;
70
using v8::Value;
71
using v8::WeakCallbackInfo;
72
using v8::WeakCallbackType;
73
74
// The vm module executes code in a sandboxed environment with a different
75
// global object than the rest of the code. This is achieved by applying
76
// every call that changes or queries a property on the global `this` in the
77
// sandboxed code, to the sandbox object.
78
//
79
// The implementation uses V8's interceptors for methods like `set`, `get`,
80
// `delete`, `defineProperty`, and for any query of the property attributes.
81
// Property handlers with interceptors are set on the object template for
82
// the sandboxed code. Handlers for both named properties and for indexed
83
// properties are used. Their functionality is almost identical, the indexed
84
// interceptors mostly just call the named interceptors.
85
//
86
// For every `get` of a global property in the sandboxed context, the
87
// interceptor callback checks the sandbox object for the property.
88
// If the property is defined on the sandbox, that result is returned to
89
// the original call instead of finishing the query on the global object.
90
//
91
// For every `set` of a global property, the interceptor callback defines or
92
// changes the property both on the sandbox and the global proxy.
93
94
namespace {
95
96
// Convert an int to a V8 Name (String or Symbol).
97
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
98
12
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
99
9
      .ToLocalChecked();
100
}
101
102
}  // anonymous namespace
103
104
466
ContextifyContext::ContextifyContext(
105
    Environment* env,
106
466
    Local<Object> sandbox_obj, const ContextOptions& options) : env_(env) {
107
466
  Local<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
108
466
  context_.Reset(env->isolate(), v8_context);
109
110
  // Allocation failure or maximum call stack size reached
111
932
  if (context_.IsEmpty())
112
535
    return;
113
397
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
114
}
115
116
117
// This is an object that just keeps an internal pointer to this
118
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
119
// pass the main JavaScript context object we're embedded in, then the
120
// NamedPropertyHandler will store a reference to it forever and keep it
121
// from getting gc'd.
122
932
Local<Value> ContextifyContext::CreateDataWrapper(Environment* env) {
123
932
  EscapableHandleScope scope(env->isolate());
124
  Local<Object> wrapper =
125
      env->script_data_constructor_function()
126
2796
          ->NewInstance(env->context()).FromMaybe(Local<Object>());
127
932
  if (wrapper.IsEmpty())
128
    return scope.Escape(Local<Value>::New(env->isolate(), Local<Value>()));
129
130
932
  wrapper->SetAlignedPointerInInternalField(0, this);
131
932
  return scope.Escape(wrapper);
132
}
133
134
135
466
Local<Context> ContextifyContext::CreateV8Context(
136
    Environment* env,
137
    Local<Object> sandbox_obj,
138
    const ContextOptions& options) {
139
466
  EscapableHandleScope scope(env->isolate());
140
  Local<FunctionTemplate> function_template =
141
466
      FunctionTemplate::New(env->isolate());
142
143
932
  function_template->SetClassName(sandbox_obj->GetConstructorName());
144
145
  Local<ObjectTemplate> object_template =
146
466
      function_template->InstanceTemplate();
147
148
  NamedPropertyHandlerConfiguration config(PropertyGetterCallback,
149
                                           PropertySetterCallback,
150
                                           PropertyDescriptorCallback,
151
                                           PropertyDeleterCallback,
152
                                           PropertyEnumeratorCallback,
153
                                           PropertyDefinerCallback,
154
466
                                           CreateDataWrapper(env));
155
156
  IndexedPropertyHandlerConfiguration indexed_config(
157
      IndexedPropertyGetterCallback,
158
      IndexedPropertySetterCallback,
159
      IndexedPropertyDescriptorCallback,
160
      IndexedPropertyDeleterCallback,
161
      PropertyEnumeratorCallback,
162
      IndexedPropertyDefinerCallback,
163
466
      CreateDataWrapper(env));
164
165
466
  object_template->SetHandler(config);
166
466
  object_template->SetHandler(indexed_config);
167
168
466
  Local<Context> ctx = NewContext(env->isolate(), object_template);
169
170
466
  if (ctx.IsEmpty()) {
171
69
    env->ThrowError("Could not instantiate context");
172
69
    return Local<Context>();
173
  }
174
175
1191
  ctx->SetSecurityToken(env->context()->GetSecurityToken());
176
177
  // We need to tie the lifetime of the sandbox object with the lifetime of
178
  // newly created context. We do this by making them hold references to each
179
  // other. The context can directly hold a reference to the sandbox as an
180
  // embedder data field. However, we cannot hold a reference to a v8::Context
181
  // directly in an Object, we instead hold onto the new context's global
182
  // object instead (which then has a reference to the context).
183
397
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
184
  sandbox_obj->SetPrivate(env->context(),
185
                          env->contextify_global_private_symbol(),
186
1191
                          ctx->Global());
187
188
794
  Utf8Value name_val(env->isolate(), options.name);
189
1191
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
190
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
191
397
                       options.allow_code_gen_wasm);
192
193
794
  ContextInfo info(*name_val);
194
195
794
  if (!options.origin.IsEmpty()) {
196
2
    Utf8Value origin_val(env->isolate(), options.origin);
197
2
    info.origin = *origin_val;
198
  }
199
200
397
  env->AssignToContext(ctx, info);
201
202
  return scope.Escape(ctx);
203
}
204
205
206
3661
void ContextifyContext::Init(Environment* env, Local<Object> target) {
207
  Local<FunctionTemplate> function_template =
208
3661
      FunctionTemplate::New(env->isolate());
209
7322
  function_template->InstanceTemplate()->SetInternalFieldCount(1);
210
  env->set_script_data_constructor_function(
211
10983
      function_template->GetFunction(env->context()).ToLocalChecked());
212
213
3661
  env->SetMethod(target, "makeContext", MakeContext);
214
3661
  env->SetMethod(target, "isContext", IsContext);
215
3661
  env->SetMethod(target, "compileFunction", CompileFunction);
216
3661
}
217
218
219
// makeContext(sandbox, name, origin, strings, wasm);
220
466
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
221
466
  Environment* env = Environment::GetCurrent(args);
222
223
466
  CHECK_EQ(args.Length(), 5);
224
932
  CHECK(args[0]->IsObject());
225
932
  Local<Object> sandbox = args[0].As<Object>();
226
227
  // Don't allow contextifying a sandbox multiple times.
228
1398
  CHECK(
229
      !sandbox->HasPrivate(
230
          env->context(),
231
          env->contextify_context_private_symbol()).FromJust());
232
233
466
  ContextOptions options;
234
235
1398
  CHECK(args[1]->IsString());
236
932
  options.name = args[1].As<String>();
237
238


3256
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
239
1398
  if (args[2]->IsString()) {
240
4
    options.origin = args[2].As<String>();
241
  }
242
243
932
  CHECK(args[3]->IsBoolean());
244
932
  options.allow_code_gen_strings = args[3].As<Boolean>();
245
246
932
  CHECK(args[4]->IsBoolean());
247
932
  options.allow_code_gen_wasm = args[4].As<Boolean>();
248
249
466
  TryCatchScope try_catch(env);
250
466
  ContextifyContext* context = new ContextifyContext(env, sandbox, options);
251
252
466
  if (try_catch.HasCaught()) {
253
69
    try_catch.ReThrow();
254
69
    return;
255
  }
256
257
794
  if (context->context().IsEmpty())
258
    return;
259
260
  sandbox->SetPrivate(
261
      env->context(),
262
      env->contextify_context_private_symbol(),
263
1191
      External::New(env->isolate(), context));
264
}
265
266
267
1323
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
268
1323
  Environment* env = Environment::GetCurrent(args);
269
270
2646
  CHECK(args[0]->IsObject());
271
2646
  Local<Object> sandbox = args[0].As<Object>();
272
273
  Maybe<bool> result =
274
      sandbox->HasPrivate(env->context(),
275
2646
                          env->contextify_context_private_symbol());
276
3969
  args.GetReturnValue().Set(result.FromJust());
277
1323
}
278
279
280
11
void ContextifyContext::WeakCallback(
281
    const WeakCallbackInfo<ContextifyContext>& data) {
282
11
  ContextifyContext* context = data.GetParameter();
283
11
  delete context;
284
11
}
285
286
// static
287
784
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
288
    Environment* env,
289
    const Local<Object>& sandbox) {
290
  MaybeLocal<Value> maybe_value =
291
      sandbox->GetPrivate(env->context(),
292
1568
                          env->contextify_context_private_symbol());
293
  Local<Value> context_external_v;
294

1568
  if (maybe_value.ToLocal(&context_external_v) &&
295
784
      context_external_v->IsExternal()) {
296
784
    Local<External> context_external = context_external_v.As<External>();
297
784
    return static_cast<ContextifyContext*>(context_external->Value());
298
  }
299
  return nullptr;
300
}
301
302
// static
303
template <typename T>
304
1008521
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
305
1008521
  Local<Value> data = args.Data();
306
  return static_cast<ContextifyContext*>(
307
3025563
      data.As<Object>()->GetAlignedPointerFromInternalField(0));
308
}
309
310
// static
311
1007062
void ContextifyContext::PropertyGetterCallback(
312
    Local<Name> property,
313
    const PropertyCallbackInfo<Value>& args) {
314
1007062
  ContextifyContext* ctx = ContextifyContext::Get(args);
315
316
  // Still initializing
317
2014124
  if (ctx->context_.IsEmpty())
318
1009841
    return;
319
320
1004283
  Local<Context> context = ctx->context();
321
1004283
  Local<Object> sandbox = ctx->sandbox();
322
  MaybeLocal<Value> maybe_rv =
323
1004283
      sandbox->GetRealNamedProperty(context, property);
324
1004283
  if (maybe_rv.IsEmpty()) {
325
    maybe_rv =
326
5202
        ctx->global_proxy()->GetRealNamedProperty(context, property);
327
  }
328
329
  Local<Value> rv;
330
1004283
  if (maybe_rv.ToLocal(&rv)) {
331
1003791
    if (rv == sandbox)
332
126
      rv = ctx->global_proxy();
333
334
2007582
    args.GetReturnValue().Set(rv);
335
  }
336
}
337
338
// static
339
1400
void ContextifyContext::PropertySetterCallback(
340
    Local<Name> property,
341
    Local<Value> value,
342
    const PropertyCallbackInfo<Value>& args) {
343
1400
  ContextifyContext* ctx = ContextifyContext::Get(args);
344
345
  // Still initializing
346
2800
  if (ctx->context_.IsEmpty())
347
808
    return;
348
349
1003
  auto attributes = PropertyAttribute::None;
350
  bool is_declared_on_global_proxy = ctx->global_proxy()
351
3009
      ->GetRealNamedPropertyAttributes(ctx->context(), property)
352
2006
      .To(&attributes);
353
  bool read_only =
354
1003
      static_cast<int>(attributes) &
355
1003
      static_cast<int>(PropertyAttribute::ReadOnly);
356
357
  bool is_declared_on_sandbox = ctx->sandbox()
358
3009
      ->GetRealNamedPropertyAttributes(ctx->context(), property)
359
2006
      .To(&attributes);
360

2002
  read_only = read_only ||
361
999
      (static_cast<int>(attributes) &
362
1003
      static_cast<int>(PropertyAttribute::ReadOnly));
363
364
1003
  if (read_only)
365
13
    return;
366
367
  // true for x = 5
368
  // false for this.x = 5
369
  // false for Object.defineProperty(this, 'foo', ...)
370
  // false for vmResult.x = 5 where vmResult = vm.runInContext();
371
1980
  bool is_contextual_store = ctx->global_proxy() != args.This();
372
373
  // Indicator to not return before setting (undeclared) function declarations
374
  // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
375
  // True for 'function f() {}', 'this.f = function() {}',
376
  // 'var f = function()'.
377
  // In effect only for 'function f() {}' because
378
  // var f = function(), is_declared = true
379
  // this.f = function() {}, is_contextual_store = false.
380
990
  bool is_function = value->IsFunction();
381
382

990
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
383


1924
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
384
26
      !is_function)
385
1
    return;
386
387

2917
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
388

1010
      args.ShouldThrowOnError() && is_contextual_store && !is_function) {
389
    // The property exists on the sandbox but not on the global
390
    // proxy. Setting it would throw because we are in strict mode.
391
    // Don't attempt to set it by signaling that the call was
392
    // intercepted. Only change the value on the sandbox.
393
8
    args.GetReturnValue().Set(false);
394
  }
395
396
2967
  ctx->sandbox()->Set(ctx->context(), property, value).FromJust();
397
}
398
399
// static
400
29
void ContextifyContext::PropertyDescriptorCallback(
401
    Local<Name> property,
402
    const PropertyCallbackInfo<Value>& args) {
403
29
  ContextifyContext* ctx = ContextifyContext::Get(args);
404
405
  // Still initializing
406
58
  if (ctx->context_.IsEmpty())
407
29
    return;
408
409
29
  Local<Context> context = ctx->context();
410
411
29
  Local<Object> sandbox = ctx->sandbox();
412
413
87
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
414
    args.GetReturnValue().Set(
415
14
        sandbox->GetOwnPropertyDescriptor(context, property)
416
42
            .ToLocalChecked());
417
  }
418
}
419
420
// static
421
15
void ContextifyContext::PropertyDefinerCallback(
422
    Local<Name> property,
423
    const PropertyDescriptor& desc,
424
    const PropertyCallbackInfo<Value>& args) {
425
15
  ContextifyContext* ctx = ContextifyContext::Get(args);
426
427
  // Still initializing
428
30
  if (ctx->context_.IsEmpty())
429
    return;
430
431
15
  Local<Context> context = ctx->context();
432
15
  Isolate* isolate = context->GetIsolate();
433
434
15
  auto attributes = PropertyAttribute::None;
435
  bool is_declared =
436
      ctx->global_proxy()->GetRealNamedPropertyAttributes(ctx->context(),
437
45
                                                          property)
438
30
          .To(&attributes);
439
  bool read_only =
440
15
      static_cast<int>(attributes) &
441
15
          static_cast<int>(PropertyAttribute::ReadOnly);
442
443
  // If the property is set on the global as read_only, don't change it on
444
  // the global or sandbox.
445

15
  if (is_declared && read_only)
446
    return;
447
448
15
  Local<Object> sandbox = ctx->sandbox();
449
450
  auto define_prop_on_sandbox =
451
15
      [&] (PropertyDescriptor* desc_for_sandbox) {
452
15
        if (desc.has_enumerable()) {
453
2
          desc_for_sandbox->set_enumerable(desc.enumerable());
454
        }
455
15
        if (desc.has_configurable()) {
456
1
          desc_for_sandbox->set_configurable(desc.configurable());
457
        }
458
        // Set the property on the sandbox.
459
30
        sandbox->DefineProperty(context, property, *desc_for_sandbox)
460
30
            .FromJust();
461
30
      };
462
463

15
  if (desc.has_get() || desc.has_set()) {
464
    PropertyDescriptor desc_for_sandbox(
465
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
466

23
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
467
468
5
    define_prop_on_sandbox(&desc_for_sandbox);
469
  } else {
470
    Local<Value> value =
471

12
        desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
472
473
10
    if (desc.has_writable()) {
474
      PropertyDescriptor desc_for_sandbox(value, desc.writable());
475
      define_prop_on_sandbox(&desc_for_sandbox);
476
    } else {
477
10
      PropertyDescriptor desc_for_sandbox(value);
478
10
      define_prop_on_sandbox(&desc_for_sandbox);
479
    }
480
  }
481
}
482
483
// static
484
2
void ContextifyContext::PropertyDeleterCallback(
485
    Local<Name> property,
486
    const PropertyCallbackInfo<Boolean>& args) {
487
2
  ContextifyContext* ctx = ContextifyContext::Get(args);
488
489
  // Still initializing
490
4
  if (ctx->context_.IsEmpty())
491
1
    return;
492
493
4
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
494
495
4
  if (success.FromMaybe(false))
496
1
    return;
497
498
  // Delete failed on the sandbox, intercept and do not delete on
499
  // the global object.
500
2
  args.GetReturnValue().Set(false);
501
}
502
503
// static
504
10
void ContextifyContext::PropertyEnumeratorCallback(
505
    const PropertyCallbackInfo<Array>& args) {
506
10
  ContextifyContext* ctx = ContextifyContext::Get(args);
507
508
  // Still initializing
509
20
  if (ctx->context_.IsEmpty())
510
    return;
511
512
  Local<Array> properties;
513
514
30
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
515
    return;
516
517
20
  args.GetReturnValue().Set(properties);
518
}
519
520
// static
521
void ContextifyContext::IndexedPropertyGetterCallback(
522
    uint32_t index,
523
    const PropertyCallbackInfo<Value>& args) {
524
  ContextifyContext* ctx = ContextifyContext::Get(args);
525
526
  // Still initializing
527
  if (ctx->context_.IsEmpty())
528
    return;
529
530
  ContextifyContext::PropertyGetterCallback(
531
      Uint32ToName(ctx->context(), index), args);
532
}
533
534
535
1
void ContextifyContext::IndexedPropertySetterCallback(
536
    uint32_t index,
537
    Local<Value> value,
538
    const PropertyCallbackInfo<Value>& args) {
539
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
540
541
  // Still initializing
542
2
  if (ctx->context_.IsEmpty())
543
1
    return;
544
545
  ContextifyContext::PropertySetterCallback(
546
1
      Uint32ToName(ctx->context(), index), value, args);
547
}
548
549
// static
550
1
void ContextifyContext::IndexedPropertyDescriptorCallback(
551
    uint32_t index,
552
    const PropertyCallbackInfo<Value>& args) {
553
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
554
555
  // Still initializing
556
2
  if (ctx->context_.IsEmpty())
557
1
    return;
558
559
  ContextifyContext::PropertyDescriptorCallback(
560
1
      Uint32ToName(ctx->context(), index), args);
561
}
562
563
564
1
void ContextifyContext::IndexedPropertyDefinerCallback(
565
    uint32_t index,
566
    const PropertyDescriptor& desc,
567
    const PropertyCallbackInfo<Value>& args) {
568
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
569
570
  // Still initializing
571
2
  if (ctx->context_.IsEmpty())
572
1
    return;
573
574
  ContextifyContext::PropertyDefinerCallback(
575
1
      Uint32ToName(ctx->context(), index), desc, args);
576
}
577
578
// static
579
void ContextifyContext::IndexedPropertyDeleterCallback(
580
    uint32_t index,
581
    const PropertyCallbackInfo<Boolean>& args) {
582
  ContextifyContext* ctx = ContextifyContext::Get(args);
583
584
  // Still initializing
585
  if (ctx->context_.IsEmpty())
586
    return;
587
588
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
589
590
  if (success.FromMaybe(false))
591
    return;
592
593
  // Delete failed on the sandbox, intercept and do not delete on
594
  // the global object.
595
  args.GetReturnValue().Set(false);
596
}
597
598
3661
void ContextifyScript::Init(Environment* env, Local<Object> target) {
599
3661
  HandleScope scope(env->isolate());
600
  Local<String> class_name =
601
3661
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
602
603
3661
  Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
604
7322
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
605
3661
  script_tmpl->SetClassName(class_name);
606
3661
  env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
607
3661
  env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
608
3661
  env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);
609
610
  target->Set(env->context(), class_name,
611
18305
      script_tmpl->GetFunction(env->context()).ToLocalChecked()).FromJust();
612
3661
  env->set_script_context_constructor_template(script_tmpl);
613
3661
}
614
615
42625
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
616
42625
  Environment* env = Environment::GetCurrent(args);
617
42626
  Isolate* isolate = env->isolate();
618
42626
  Local<Context> context = env->context();
619
620
42626
  CHECK(args.IsConstructCall());
621
622
42626
  const int argc = args.Length();
623
42626
  CHECK_GE(argc, 2);
624
625
127878
  CHECK(args[0]->IsString());
626
85252
  Local<String> code = args[0].As<String>();
627
628
127878
  CHECK(args[1]->IsString());
629
85252
  Local<String> filename = args[1].As<String>();
630
631
  Local<Integer> line_offset;
632
  Local<Integer> column_offset;
633
  Local<ArrayBufferView> cached_data_buf;
634
42626
  bool produce_cached_data = false;
635
42626
  Local<Context> parsing_context = context;
636
637
42626
  if (argc > 2) {
638
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
639
    //                      cachedData, produceCachedData, parsingContext)
640
42626
    CHECK_EQ(argc, 7);
641
85252
    CHECK(args[2]->IsNumber());
642
85250
    line_offset = args[2].As<Integer>();
643
85250
    CHECK(args[3]->IsNumber());
644
85252
    column_offset = args[3].As<Integer>();
645
127878
    if (!args[4]->IsUndefined()) {
646
46
      CHECK(args[4]->IsArrayBufferView());
647
46
      cached_data_buf = args[4].As<ArrayBufferView>();
648
    }
649
85252
    CHECK(args[5]->IsBoolean());
650
85250
    produce_cached_data = args[5]->IsTrue();
651
127875
    if (!args[6]->IsUndefined()) {
652
524
      CHECK(args[6]->IsObject());
653
      ContextifyContext* sandbox =
654
          ContextifyContext::ContextFromContextifiedSandbox(
655
524
              env, args[6].As<Object>());
656
262
      CHECK_NOT_NULL(sandbox);
657
262
      parsing_context = sandbox->context();
658
    }
659
  } else {
660
    line_offset = Integer::New(isolate, 0);
661
    column_offset = Integer::New(isolate, 0);
662
  }
663
664
  ContextifyScript* contextify_script =
665
42626
      new ContextifyScript(env, args.This());
666
667
85251
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
668
42626
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
669
19
    Utf8Value fn(isolate, filename);
670

19
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
671
        TRACING_CATEGORY_NODE2(vm, script),
672
        "ContextifyScript::New",
673
        contextify_script,
674
19
        "filename", TRACE_STR_COPY(*fn));
675
  }
676
677
42625
  ScriptCompiler::CachedData* cached_data = nullptr;
678
42625
  if (!cached_data_buf.IsEmpty()) {
679
46
    ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents();
680
23
    uint8_t* data = static_cast<uint8_t*>(contents.Data());
681
    cached_data = new ScriptCompiler::CachedData(
682
46
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
683
  }
684
685
  Local<PrimitiveArray> host_defined_options =
686
42625
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
687
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
688
85252
                            Number::New(isolate, loader::ScriptType::kScript));
689
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
690
85251
                            Number::New(isolate, contextify_script->id()));
691
692
  ScriptOrigin origin(filename,
693
                      line_offset,                          // line offset
694
                      column_offset,                        // column offset
695
                      False(isolate),                       // is cross origin
696
                      Local<Integer>(),                     // script id
697
                      Local<Value>(),                       // source map URL
698
                      False(isolate),                       // is opaque (?)
699
                      False(isolate),                       // is WASM
700
                      False(isolate),                       // is ES Module
701
42625
                      host_defined_options);
702
  ScriptCompiler::Source source(code, origin, cached_data);
703
  ScriptCompiler::CompileOptions compile_options =
704
42625
      ScriptCompiler::kNoCompileOptions;
705
706
42625
  if (source.GetCachedData() != nullptr)
707
23
    compile_options = ScriptCompiler::kConsumeCodeCache;
708
709
84930
  TryCatchScope try_catch(env);
710
84931
  Environment::ShouldNotAbortOnUncaughtScope no_abort_scope(env);
711
42306
  Context::Scope scope(parsing_context);
712
713
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
714
      isolate,
715
      &source,
716
42626
      compile_options);
717
718
42626
  if (v8_script.IsEmpty()) {
719
320
    DecorateErrorStack(env, try_catch);
720
320
    no_abort_scope.Close();
721
320
    try_catch.ReThrow();
722

320
    TRACE_EVENT_NESTABLE_ASYNC_END0(
723
        TRACING_CATEGORY_NODE2(vm, script),
724
        "ContextifyScript::New",
725
        contextify_script);
726
42945
    return;
727
  }
728
84610
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
729
730
42305
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
731
    args.This()->Set(
732
        env->context(),
733
        env->cached_data_rejected_string(),
734
138
        Boolean::New(isolate, source.GetCachedData()->rejected)).FromJust();
735
42282
  } else if (produce_cached_data) {
736
    const ScriptCompiler::CachedData* cached_data =
737
6
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked());
738
6
    bool cached_data_produced = cached_data != nullptr;
739
6
    if (cached_data_produced) {
740
      MaybeLocal<Object> buf = Buffer::Copy(
741
          env,
742
          reinterpret_cast<const char*>(cached_data->data),
743
6
          cached_data->length);
744
      args.This()->Set(env->context(),
745
                       env->cached_data_string(),
746
30
                       buf.ToLocalChecked()).FromJust();
747
    }
748
    args.This()->Set(
749
        env->context(),
750
        env->cached_data_produced_string(),
751
36
        Boolean::New(isolate, cached_data_produced)).FromJust();
752
  }
753

42305
  TRACE_EVENT_NESTABLE_ASYNC_END0(
754
      TRACING_CATEGORY_NODE2(vm, script),
755
      "ContextifyScript::New",
756
42305
      contextify_script);
757
}
758
759
42272
bool ContextifyScript::InstanceOf(Environment* env,
760
                                  const Local<Value>& value) {
761

169090
  return !value.IsEmpty() &&
762
126818
         env->script_context_constructor_template()->HasInstance(value);
763
}
764
765
11
void ContextifyScript::CreateCachedData(
766
    const FunctionCallbackInfo<Value>& args) {
767
11
  Environment* env = Environment::GetCurrent(args);
768
  ContextifyScript* wrapped_script;
769
22
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
770
  Local<UnboundScript> unbound_script =
771
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
772
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
773
11
      ScriptCompiler::CreateCodeCache(unbound_script));
774
11
  if (!cached_data) {
775
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
776
  } else {
777
    MaybeLocal<Object> buf = Buffer::Copy(
778
        env,
779
11
        reinterpret_cast<const char*>(cached_data->data),
780
22
        cached_data->length);
781
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
782
11
  }
783
}
784
785
41758
void ContextifyScript::RunInThisContext(
786
    const FunctionCallbackInfo<Value>& args) {
787
41758
  Environment* env = Environment::GetCurrent(args);
788
789
  ContextifyScript* wrapped_script;
790
83504
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
791
792

41759
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
793
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
794
795
41759
  CHECK_EQ(args.Length(), 3);
796
797
83518
  CHECK(args[0]->IsNumber());
798
167035
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
799
800
83516
  CHECK(args[1]->IsBoolean());
801
83518
  bool display_errors = args[1]->IsTrue();
802
803
83518
  CHECK(args[2]->IsBoolean());
804
83518
  bool break_on_sigint = args[2]->IsTrue();
805
806
  // Do the eval within this context
807
41759
  EvalMachine(env, timeout, display_errors, break_on_sigint, args);
808
809

41745
  TRACE_EVENT_NESTABLE_ASYNC_END0(
810
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
811
}
812
813
514
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
814
514
  Environment* env = Environment::GetCurrent(args);
815
816
  ContextifyScript* wrapped_script;
817
514
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
818
819
514
  CHECK_EQ(args.Length(), 4);
820
821
1028
  CHECK(args[0]->IsObject());
822
1028
  Local<Object> sandbox = args[0].As<Object>();
823
  // Get the context from the sandbox
824
  ContextifyContext* contextify_context =
825
514
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
826
514
  CHECK_NOT_NULL(contextify_context);
827
828
1028
  if (contextify_context->context().IsEmpty())
829
    return;
830
831

514
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
832
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
833
834
1028
  CHECK(args[1]->IsNumber());
835
2056
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
836
837
1028
  CHECK(args[2]->IsBoolean());
838
1028
  bool display_errors = args[2]->IsTrue();
839
840
1028
  CHECK(args[3]->IsBoolean());
841
1028
  bool break_on_sigint = args[3]->IsTrue();
842
843
  // Do the eval within the context
844
514
  Context::Scope context_scope(contextify_context->context());
845
  EvalMachine(contextify_context->env(),
846
              timeout,
847
              display_errors,
848
              break_on_sigint,
849
514
              args);
850
851

514
  TRACE_EVENT_NESTABLE_ASYNC_END0(
852
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
853
}
854
855
42272
bool ContextifyScript::EvalMachine(Environment* env,
856
                                   const int64_t timeout,
857
                                   const bool display_errors,
858
                                   const bool break_on_sigint,
859
                                   const FunctionCallbackInfo<Value>& args) {
860
42272
  if (!env->can_call_into_js())
861
    return false;
862
42273
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
863
    env->ThrowTypeError(
864
        "Script methods can only be called on script instances.");
865
    return false;
866
  }
867
42273
  TryCatchScope try_catch(env);
868
  ContextifyScript* wrapped_script;
869
42273
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
870
  Local<UnboundScript> unbound_script =
871
42273
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
872
42272
  Local<Script> script = unbound_script->BindToCurrentContext();
873
874
  MaybeLocal<Value> result;
875
42272
  bool timed_out = false;
876
42272
  bool received_signal = false;
877

42272
  if (break_on_sigint && timeout != -1) {
878
    Watchdog wd(env->isolate(), timeout, &timed_out);
879
    SigintWatchdog swd(env->isolate(), &received_signal);
880
    result = script->Run(env->context());
881
42272
  } else if (break_on_sigint) {
882
86
    SigintWatchdog swd(env->isolate(), &received_signal);
883
172
    result = script->Run(env->context());
884
42186
  } else if (timeout != -1) {
885
12
    Watchdog wd(env->isolate(), timeout, &timed_out);
886
24
    result = script->Run(env->context());
887
  } else {
888
84348
    result = script->Run(env->context());
889
  }
890
891
  // Convert the termination exception into a regular exception.
892

42259
  if (timed_out || received_signal) {
893
17
    env->isolate()->CancelTerminateExecution();
894
    // It is possible that execution was terminated by another timeout in
895
    // which this timeout is nested, so check whether one of the watchdogs
896
    // from this invocation is responsible for termination.
897
18
    if (timed_out) {
898
7
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
899
11
    } else if (received_signal) {
900
11
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
901
    }
902
  }
903
904
42260
  if (try_catch.HasCaught()) {
905

107
    if (!timed_out && !received_signal && display_errors) {
906
      // We should decorate non-termination exceptions
907
57
      DecorateErrorStack(env, try_catch);
908
    }
909
910
    // If there was an exception thrown during script execution, re-throw it.
911
    // If one of the above checks threw, re-throw the exception instead of
912
    // letting try_catch catch it.
913
    // If execution has been terminated, but not by one of the watchdogs from
914
    // this invocation, this will re-throw a `null` value.
915
107
    try_catch.ReThrow();
916
917
107
    return false;
918
  }
919
920
84304
  args.GetReturnValue().Set(result.ToLocalChecked());
921
42152
  return true;
922
}
923
924
925
42625
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
926
    : BaseObject(env, object),
927
85250
      id_(env->get_next_script_id()) {
928
42626
  MakeWeak();
929
42626
  env->id_to_script_map.emplace(id_, this);
930
42626
}
931
932
933
158788
ContextifyScript::~ContextifyScript() {
934
39697
  env()->id_to_script_map.erase(id_);
935
79394
}
936
937
938
13
void ContextifyContext::CompileFunction(
939
    const FunctionCallbackInfo<Value>& args) {
940
13
  Environment* env = Environment::GetCurrent(args);
941
13
  Isolate* isolate = env->isolate();
942
13
  Local<Context> context = env->context();
943
944
  // Argument 1: source code
945
39
  CHECK(args[0]->IsString());
946
26
  Local<String> code = args[0].As<String>();
947
948
  // Argument 2: filename
949
39
  CHECK(args[1]->IsString());
950
26
  Local<String> filename = args[1].As<String>();
951
952
  // Argument 3: line offset
953
26
  CHECK(args[2]->IsNumber());
954
26
  Local<Integer> line_offset = args[2].As<Integer>();
955
956
  // Argument 4: column offset
957
26
  CHECK(args[3]->IsNumber());
958
26
  Local<Integer> column_offset = args[3].As<Integer>();
959
960
  // Argument 5: cached data (optional)
961
  Local<ArrayBufferView> cached_data_buf;
962
39
  if (!args[4]->IsUndefined()) {
963
    CHECK(args[4]->IsArrayBufferView());
964
    cached_data_buf = args[4].As<ArrayBufferView>();
965
  }
966
967
  // Argument 6: produce cache data
968
26
  CHECK(args[5]->IsBoolean());
969
26
  bool produce_cached_data = args[5]->IsTrue();
970
971
  // Argument 7: parsing context (optional)
972
  Local<Context> parsing_context;
973
39
  if (!args[6]->IsUndefined()) {
974
4
    CHECK(args[6]->IsObject());
975
    ContextifyContext* sandbox =
976
        ContextifyContext::ContextFromContextifiedSandbox(
977
4
            env, args[6].As<Object>());
978
2
    CHECK_NOT_NULL(sandbox);
979
2
    parsing_context = sandbox->context();
980
  } else {
981
11
    parsing_context = context;
982
  }
983
984
  // Argument 8: context extensions (optional)
985
  Local<Array> context_extensions_buf;
986
39
  if (!args[7]->IsUndefined()) {
987
26
    CHECK(args[7]->IsArray());
988
26
    context_extensions_buf = args[7].As<Array>();
989
  }
990
991
  // Argument 9: params for the function (optional)
992
  Local<Array> params_buf;
993
39
  if (!args[8]->IsUndefined()) {
994
14
    CHECK(args[8]->IsArray());
995
14
    params_buf = args[8].As<Array>();
996
  }
997
998
  // Read cache from cached data buffer
999
13
  ScriptCompiler::CachedData* cached_data = nullptr;
1000
13
  if (!cached_data_buf.IsEmpty()) {
1001
    ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents();
1002
    uint8_t* data = static_cast<uint8_t*>(contents.Data());
1003
    cached_data = new ScriptCompiler::CachedData(
1004
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1005
  }
1006
1007
13
  ScriptOrigin origin(filename, line_offset, column_offset);
1008
  ScriptCompiler::Source source(code, origin, cached_data);
1009
  ScriptCompiler::CompileOptions options;
1010
13
  if (source.GetCachedData() == nullptr) {
1011
13
    options = ScriptCompiler::kNoCompileOptions;
1012
  } else {
1013
    options = ScriptCompiler::kConsumeCodeCache;
1014
  }
1015
1016
25
  TryCatchScope try_catch(env);
1017
12
  Context::Scope scope(parsing_context);
1018
1019
  // Read context extensions from buffer
1020
25
  std::vector<Local<Object>> context_extensions;
1021
13
  if (!context_extensions_buf.IsEmpty()) {
1022
28
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1023
      Local<Value> val;
1024
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1025
1
      CHECK(val->IsObject());
1026
1
      context_extensions.push_back(val.As<Object>());
1027
    }
1028
  }
1029
1030
  // Read params from params buffer
1031
25
  std::vector<Local<String>> params;
1032
13
  if (!params_buf.IsEmpty()) {
1033
24
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1034
      Local<Value> val;
1035
10
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1036
10
      CHECK(val->IsString());
1037
5
      params.push_back(val.As<String>());
1038
    }
1039
  }
1040
1041
  MaybeLocal<Function> maybe_fun = ScriptCompiler::CompileFunctionInContext(
1042
      parsing_context, &source, params.size(), params.data(),
1043
13
      context_extensions.size(), context_extensions.data(), options);
1044
1045
  Local<Function> fun;
1046

25
  if (maybe_fun.IsEmpty() || !maybe_fun.ToLocal(&fun)) {
1047
1
    DecorateErrorStack(env, try_catch);
1048
1
    try_catch.ReThrow();
1049
1
    return;
1050
  }
1051
1052
12
  if (produce_cached_data) {
1053
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1054
        ScriptCompiler::CreateCodeCacheForFunction(fun));
1055
    bool cached_data_produced = cached_data != nullptr;
1056
    if (cached_data_produced) {
1057
      MaybeLocal<Object> buf = Buffer::Copy(
1058
          env,
1059
          reinterpret_cast<const char*>(cached_data->data),
1060
          cached_data->length);
1061
      if (fun->Set(
1062
          parsing_context,
1063
          env->cached_data_string(),
1064
          buf.ToLocalChecked()).IsNothing()) return;
1065
    }
1066
    if (fun->Set(
1067
        parsing_context,
1068
        env->cached_data_produced_string(),
1069
        Boolean::New(isolate, cached_data_produced)).IsNothing()) return;
1070
  }
1071
1072
36
  args.GetReturnValue().Set(fun);
1073
}
1074
1075
1076
3661
void Initialize(Local<Object> target,
1077
                Local<Value> unused,
1078
                Local<Context> context,
1079
                void* priv) {
1080
3661
  Environment* env = Environment::GetCurrent(context);
1081
3661
  ContextifyContext::Init(env, target);
1082
3661
  ContextifyScript::Init(env, target);
1083
3661
}
1084
1085
}  // namespace contextify
1086
}  // namespace node
1087
1088
3596
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)