• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_contextify.h"
23 
24 #include "memory_tracker-inl.h"
25 #include "node_internals.h"
26 #include "node_watchdog.h"
27 #include "base_object-inl.h"
28 #include "node_context_data.h"
29 #include "node_errors.h"
30 #include "module_wrap.h"
31 #include "util-inl.h"
32 
33 namespace node {
34 namespace contextify {
35 
36 using errors::TryCatchScope;
37 
38 using v8::Array;
39 using v8::ArrayBuffer;
40 using v8::ArrayBufferView;
41 using v8::Boolean;
42 using v8::Context;
43 using v8::EscapableHandleScope;
44 using v8::External;
45 using v8::Function;
46 using v8::FunctionCallbackInfo;
47 using v8::FunctionTemplate;
48 using v8::HandleScope;
49 using v8::IndexedPropertyHandlerConfiguration;
50 using v8::Integer;
51 using v8::Isolate;
52 using v8::Local;
53 using v8::Maybe;
54 using v8::MaybeLocal;
55 using v8::Name;
56 using v8::NamedPropertyHandlerConfiguration;
57 using v8::Number;
58 using v8::Object;
59 using v8::ObjectTemplate;
60 using v8::PrimitiveArray;
61 using v8::PropertyAttribute;
62 using v8::PropertyCallbackInfo;
63 using v8::PropertyDescriptor;
64 using v8::PropertyHandlerFlags;
65 using v8::Script;
66 using v8::ScriptCompiler;
67 using v8::ScriptOrigin;
68 using v8::ScriptOrModule;
69 using v8::String;
70 using v8::Uint32;
71 using v8::UnboundScript;
72 using v8::Value;
73 using v8::WeakCallbackInfo;
74 using v8::WeakCallbackType;
75 
76 // The vm module executes code in a sandboxed environment with a different
77 // global object than the rest of the code. This is achieved by applying
78 // every call that changes or queries a property on the global `this` in the
79 // sandboxed code, to the sandbox object.
80 //
81 // The implementation uses V8's interceptors for methods like `set`, `get`,
82 // `delete`, `defineProperty`, and for any query of the property attributes.
83 // Property handlers with interceptors are set on the object template for
84 // the sandboxed code. Handlers for both named properties and for indexed
85 // properties are used. Their functionality is almost identical, the indexed
86 // interceptors mostly just call the named interceptors.
87 //
88 // For every `get` of a global property in the sandboxed context, the
89 // interceptor callback checks the sandbox object for the property.
90 // If the property is defined on the sandbox, that result is returned to
91 // the original call instead of finishing the query on the global object.
92 //
93 // For every `set` of a global property, the interceptor callback defines or
94 // changes the property both on the sandbox and the global proxy.
95 
96 namespace {
97 
98 // Convert an int to a V8 Name (String or Symbol).
Uint32ToName(Local<Context> context,uint32_t index)99 Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
100   return Uint32::New(context->GetIsolate(), index)->ToString(context)
101       .ToLocalChecked();
102 }
103 
104 }  // anonymous namespace
105 
ContextifyContext(Environment * env,Local<Object> sandbox_obj,const ContextOptions & options)106 ContextifyContext::ContextifyContext(
107     Environment* env,
108     Local<Object> sandbox_obj, const ContextOptions& options) : env_(env) {
109   MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
110 
111   // Allocation failure, maximum call stack size reached, termination, etc.
112   if (v8_context.IsEmpty()) return;
113 
114   context_.Reset(env->isolate(), v8_context.ToLocalChecked());
115   context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
116   env->AddCleanupHook(CleanupHook, this);
117 }
118 
119 
~ContextifyContext()120 ContextifyContext::~ContextifyContext() {
121   env()->RemoveCleanupHook(CleanupHook, this);
122 }
123 
124 
CleanupHook(void * arg)125 void ContextifyContext::CleanupHook(void* arg) {
126   ContextifyContext* self = static_cast<ContextifyContext*>(arg);
127   self->context_.Reset();
128   delete self;
129 }
130 
131 
132 // This is an object that just keeps an internal pointer to this
133 // ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
134 // pass the main JavaScript context object we're embedded in, then the
135 // NamedPropertyHandler will store a reference to it forever and keep it
136 // from getting gc'd.
CreateDataWrapper(Environment * env)137 MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
138   Local<Object> wrapper;
139   if (!env->script_data_constructor_function()
140            ->NewInstance(env->context())
141            .ToLocal(&wrapper)) {
142     return MaybeLocal<Object>();
143   }
144 
145   wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
146   return wrapper;
147 }
148 
CreateV8Context(Environment * env,Local<Object> sandbox_obj,const ContextOptions & options)149 MaybeLocal<Context> ContextifyContext::CreateV8Context(
150     Environment* env,
151     Local<Object> sandbox_obj,
152     const ContextOptions& options) {
153   EscapableHandleScope scope(env->isolate());
154   Local<FunctionTemplate> function_template =
155       FunctionTemplate::New(env->isolate());
156 
157   function_template->SetClassName(sandbox_obj->GetConstructorName());
158 
159   Local<ObjectTemplate> object_template =
160       function_template->InstanceTemplate();
161 
162   Local<Object> data_wrapper;
163   if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
164     return MaybeLocal<Context>();
165 
166   NamedPropertyHandlerConfiguration config(
167       PropertyGetterCallback,
168       PropertySetterCallback,
169       PropertyDescriptorCallback,
170       PropertyDeleterCallback,
171       PropertyEnumeratorCallback,
172       PropertyDefinerCallback,
173       data_wrapper,
174       PropertyHandlerFlags::kHasNoSideEffect);
175 
176   IndexedPropertyHandlerConfiguration indexed_config(
177       IndexedPropertyGetterCallback,
178       IndexedPropertySetterCallback,
179       IndexedPropertyDescriptorCallback,
180       IndexedPropertyDeleterCallback,
181       PropertyEnumeratorCallback,
182       IndexedPropertyDefinerCallback,
183       data_wrapper,
184       PropertyHandlerFlags::kHasNoSideEffect);
185 
186   object_template->SetHandler(config);
187   object_template->SetHandler(indexed_config);
188   Local<Context> ctx = Context::New(env->isolate(), nullptr, object_template);
189   if (ctx.IsEmpty()) return MaybeLocal<Context>();
190   // Only partially initialize the context - the primordials are left out
191   // and only initialized when necessary.
192   InitializeContextRuntime(ctx);
193 
194   if (ctx.IsEmpty()) {
195     return MaybeLocal<Context>();
196   }
197 
198   ctx->SetSecurityToken(env->context()->GetSecurityToken());
199 
200   // We need to tie the lifetime of the sandbox object with the lifetime of
201   // newly created context. We do this by making them hold references to each
202   // other. The context can directly hold a reference to the sandbox as an
203   // embedder data field. However, we cannot hold a reference to a v8::Context
204   // directly in an Object, we instead hold onto the new context's global
205   // object instead (which then has a reference to the context).
206   ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
207   sandbox_obj->SetPrivate(env->context(),
208                           env->contextify_global_private_symbol(),
209                           ctx->Global());
210 
211   Utf8Value name_val(env->isolate(), options.name);
212   ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
213   ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
214                        options.allow_code_gen_wasm);
215 
216   ContextInfo info(*name_val);
217 
218   if (!options.origin.IsEmpty()) {
219     Utf8Value origin_val(env->isolate(), options.origin);
220     info.origin = *origin_val;
221   }
222 
223   env->AssignToContext(ctx, info);
224 
225   return scope.Escape(ctx);
226 }
227 
228 
Init(Environment * env,Local<Object> target)229 void ContextifyContext::Init(Environment* env, Local<Object> target) {
230   Local<FunctionTemplate> function_template =
231       FunctionTemplate::New(env->isolate());
232   function_template->InstanceTemplate()->SetInternalFieldCount(
233       ContextifyContext::kInternalFieldCount);
234   env->set_script_data_constructor_function(
235       function_template->GetFunction(env->context()).ToLocalChecked());
236 
237   env->SetMethod(target, "makeContext", MakeContext);
238   env->SetMethod(target, "isContext", IsContext);
239   env->SetMethod(target, "compileFunction", CompileFunction);
240 }
241 
242 
243 // makeContext(sandbox, name, origin, strings, wasm);
MakeContext(const FunctionCallbackInfo<Value> & args)244 void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
245   Environment* env = Environment::GetCurrent(args);
246 
247   CHECK_EQ(args.Length(), 5);
248   CHECK(args[0]->IsObject());
249   Local<Object> sandbox = args[0].As<Object>();
250 
251   // Don't allow contextifying a sandbox multiple times.
252   CHECK(
253       !sandbox->HasPrivate(
254           env->context(),
255           env->contextify_context_private_symbol()).FromJust());
256 
257   ContextOptions options;
258 
259   CHECK(args[1]->IsString());
260   options.name = args[1].As<String>();
261 
262   CHECK(args[2]->IsString() || args[2]->IsUndefined());
263   if (args[2]->IsString()) {
264     options.origin = args[2].As<String>();
265   }
266 
267   CHECK(args[3]->IsBoolean());
268   options.allow_code_gen_strings = args[3].As<Boolean>();
269 
270   CHECK(args[4]->IsBoolean());
271   options.allow_code_gen_wasm = args[4].As<Boolean>();
272 
273   TryCatchScope try_catch(env);
274   auto context_ptr = std::make_unique<ContextifyContext>(env, sandbox, options);
275 
276   if (try_catch.HasCaught()) {
277     if (!try_catch.HasTerminated())
278       try_catch.ReThrow();
279     return;
280   }
281 
282   if (context_ptr->context().IsEmpty())
283     return;
284 
285   sandbox->SetPrivate(
286       env->context(),
287       env->contextify_context_private_symbol(),
288       External::New(env->isolate(), context_ptr.release()));
289 }
290 
291 
IsContext(const FunctionCallbackInfo<Value> & args)292 void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
293   Environment* env = Environment::GetCurrent(args);
294 
295   CHECK(args[0]->IsObject());
296   Local<Object> sandbox = args[0].As<Object>();
297 
298   Maybe<bool> result =
299       sandbox->HasPrivate(env->context(),
300                           env->contextify_context_private_symbol());
301   args.GetReturnValue().Set(result.FromJust());
302 }
303 
304 
WeakCallback(const WeakCallbackInfo<ContextifyContext> & data)305 void ContextifyContext::WeakCallback(
306     const WeakCallbackInfo<ContextifyContext>& data) {
307   ContextifyContext* context = data.GetParameter();
308   delete context;
309 }
310 
311 // static
ContextFromContextifiedSandbox(Environment * env,const Local<Object> & sandbox)312 ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
313     Environment* env,
314     const Local<Object>& sandbox) {
315   MaybeLocal<Value> maybe_value =
316       sandbox->GetPrivate(env->context(),
317                           env->contextify_context_private_symbol());
318   Local<Value> context_external_v;
319   if (maybe_value.ToLocal(&context_external_v) &&
320       context_external_v->IsExternal()) {
321     Local<External> context_external = context_external_v.As<External>();
322     return static_cast<ContextifyContext*>(context_external->Value());
323   }
324   return nullptr;
325 }
326 
327 // static
328 template <typename T>
Get(const PropertyCallbackInfo<T> & args)329 ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
330   Local<Value> data = args.Data();
331   return static_cast<ContextifyContext*>(
332       data.As<Object>()->GetAlignedPointerFromInternalField(
333           ContextifyContext::kSlot));
334 }
335 
336 // static
PropertyGetterCallback(Local<Name> property,const PropertyCallbackInfo<Value> & args)337 void ContextifyContext::PropertyGetterCallback(
338     Local<Name> property,
339     const PropertyCallbackInfo<Value>& args) {
340   ContextifyContext* ctx = ContextifyContext::Get(args);
341 
342   // Still initializing
343   if (ctx->context_.IsEmpty())
344     return;
345 
346   Local<Context> context = ctx->context();
347   Local<Object> sandbox = ctx->sandbox();
348   MaybeLocal<Value> maybe_rv =
349       sandbox->GetRealNamedProperty(context, property);
350   if (maybe_rv.IsEmpty()) {
351     maybe_rv =
352         ctx->global_proxy()->GetRealNamedProperty(context, property);
353   }
354 
355   Local<Value> rv;
356   if (maybe_rv.ToLocal(&rv)) {
357     if (rv == sandbox)
358       rv = ctx->global_proxy();
359 
360     args.GetReturnValue().Set(rv);
361   }
362 }
363 
364 // static
PropertySetterCallback(Local<Name> property,Local<Value> value,const PropertyCallbackInfo<Value> & args)365 void ContextifyContext::PropertySetterCallback(
366     Local<Name> property,
367     Local<Value> value,
368     const PropertyCallbackInfo<Value>& args) {
369   ContextifyContext* ctx = ContextifyContext::Get(args);
370 
371   // Still initializing
372   if (ctx->context_.IsEmpty())
373     return;
374 
375   auto attributes = PropertyAttribute::None;
376   bool is_declared_on_global_proxy = ctx->global_proxy()
377       ->GetRealNamedPropertyAttributes(ctx->context(), property)
378       .To(&attributes);
379   bool read_only =
380       static_cast<int>(attributes) &
381       static_cast<int>(PropertyAttribute::ReadOnly);
382 
383   bool is_declared_on_sandbox = ctx->sandbox()
384       ->GetRealNamedPropertyAttributes(ctx->context(), property)
385       .To(&attributes);
386   read_only = read_only ||
387       (static_cast<int>(attributes) &
388       static_cast<int>(PropertyAttribute::ReadOnly));
389 
390   if (read_only)
391     return;
392 
393   // true for x = 5
394   // false for this.x = 5
395   // false for Object.defineProperty(this, 'foo', ...)
396   // false for vmResult.x = 5 where vmResult = vm.runInContext();
397   bool is_contextual_store = ctx->global_proxy() != args.This();
398 
399   // Indicator to not return before setting (undeclared) function declarations
400   // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
401   // True for 'function f() {}', 'this.f = function() {}',
402   // 'var f = function()'.
403   // In effect only for 'function f() {}' because
404   // var f = function(), is_declared = true
405   // this.f = function() {}, is_contextual_store = false.
406   bool is_function = value->IsFunction();
407 
408   bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
409   if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
410       !is_function)
411     return;
412 
413   if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
414       args.ShouldThrowOnError() && is_contextual_store && !is_function) {
415     // The property exists on the sandbox but not on the global
416     // proxy. Setting it would throw because we are in strict mode.
417     // Don't attempt to set it by signaling that the call was
418     // intercepted. Only change the value on the sandbox.
419     args.GetReturnValue().Set(false);
420   }
421 
422   USE(ctx->sandbox()->Set(ctx->context(), property, value));
423 }
424 
425 // static
PropertyDescriptorCallback(Local<Name> property,const PropertyCallbackInfo<Value> & args)426 void ContextifyContext::PropertyDescriptorCallback(
427     Local<Name> property,
428     const PropertyCallbackInfo<Value>& args) {
429   ContextifyContext* ctx = ContextifyContext::Get(args);
430 
431   // Still initializing
432   if (ctx->context_.IsEmpty())
433     return;
434 
435   Local<Context> context = ctx->context();
436 
437   Local<Object> sandbox = ctx->sandbox();
438 
439   if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
440     Local<Value> desc;
441     if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
442       args.GetReturnValue().Set(desc);
443     }
444   }
445 }
446 
447 // static
PropertyDefinerCallback(Local<Name> property,const PropertyDescriptor & desc,const PropertyCallbackInfo<Value> & args)448 void ContextifyContext::PropertyDefinerCallback(
449     Local<Name> property,
450     const PropertyDescriptor& desc,
451     const PropertyCallbackInfo<Value>& args) {
452   ContextifyContext* ctx = ContextifyContext::Get(args);
453 
454   // Still initializing
455   if (ctx->context_.IsEmpty())
456     return;
457 
458   Local<Context> context = ctx->context();
459   Isolate* isolate = context->GetIsolate();
460 
461   auto attributes = PropertyAttribute::None;
462   bool is_declared =
463       ctx->global_proxy()->GetRealNamedPropertyAttributes(ctx->context(),
464                                                           property)
465           .To(&attributes);
466   bool read_only =
467       static_cast<int>(attributes) &
468           static_cast<int>(PropertyAttribute::ReadOnly);
469 
470   // If the property is set on the global as read_only, don't change it on
471   // the global or sandbox.
472   if (is_declared && read_only)
473     return;
474 
475   Local<Object> sandbox = ctx->sandbox();
476 
477   auto define_prop_on_sandbox =
478       [&] (PropertyDescriptor* desc_for_sandbox) {
479         if (desc.has_enumerable()) {
480           desc_for_sandbox->set_enumerable(desc.enumerable());
481         }
482         if (desc.has_configurable()) {
483           desc_for_sandbox->set_configurable(desc.configurable());
484         }
485         // Set the property on the sandbox.
486         USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
487       };
488 
489   if (desc.has_get() || desc.has_set()) {
490     PropertyDescriptor desc_for_sandbox(
491         desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
492         desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
493 
494     define_prop_on_sandbox(&desc_for_sandbox);
495   } else {
496     Local<Value> value =
497         desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
498 
499     if (desc.has_writable()) {
500       PropertyDescriptor desc_for_sandbox(value, desc.writable());
501       define_prop_on_sandbox(&desc_for_sandbox);
502     } else {
503       PropertyDescriptor desc_for_sandbox(value);
504       define_prop_on_sandbox(&desc_for_sandbox);
505     }
506   }
507 }
508 
509 // static
PropertyDeleterCallback(Local<Name> property,const PropertyCallbackInfo<Boolean> & args)510 void ContextifyContext::PropertyDeleterCallback(
511     Local<Name> property,
512     const PropertyCallbackInfo<Boolean>& args) {
513   ContextifyContext* ctx = ContextifyContext::Get(args);
514 
515   // Still initializing
516   if (ctx->context_.IsEmpty())
517     return;
518 
519   Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
520 
521   if (success.FromMaybe(false))
522     return;
523 
524   // Delete failed on the sandbox, intercept and do not delete on
525   // the global object.
526   args.GetReturnValue().Set(false);
527 }
528 
529 // static
PropertyEnumeratorCallback(const PropertyCallbackInfo<Array> & args)530 void ContextifyContext::PropertyEnumeratorCallback(
531     const PropertyCallbackInfo<Array>& args) {
532   ContextifyContext* ctx = ContextifyContext::Get(args);
533 
534   // Still initializing
535   if (ctx->context_.IsEmpty())
536     return;
537 
538   Local<Array> properties;
539 
540   if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
541     return;
542 
543   args.GetReturnValue().Set(properties);
544 }
545 
546 // static
IndexedPropertyGetterCallback(uint32_t index,const PropertyCallbackInfo<Value> & args)547 void ContextifyContext::IndexedPropertyGetterCallback(
548     uint32_t index,
549     const PropertyCallbackInfo<Value>& args) {
550   ContextifyContext* ctx = ContextifyContext::Get(args);
551 
552   // Still initializing
553   if (ctx->context_.IsEmpty())
554     return;
555 
556   ContextifyContext::PropertyGetterCallback(
557       Uint32ToName(ctx->context(), index), args);
558 }
559 
560 
IndexedPropertySetterCallback(uint32_t index,Local<Value> value,const PropertyCallbackInfo<Value> & args)561 void ContextifyContext::IndexedPropertySetterCallback(
562     uint32_t index,
563     Local<Value> value,
564     const PropertyCallbackInfo<Value>& args) {
565   ContextifyContext* ctx = ContextifyContext::Get(args);
566 
567   // Still initializing
568   if (ctx->context_.IsEmpty())
569     return;
570 
571   ContextifyContext::PropertySetterCallback(
572       Uint32ToName(ctx->context(), index), value, args);
573 }
574 
575 // static
IndexedPropertyDescriptorCallback(uint32_t index,const PropertyCallbackInfo<Value> & args)576 void ContextifyContext::IndexedPropertyDescriptorCallback(
577     uint32_t index,
578     const PropertyCallbackInfo<Value>& args) {
579   ContextifyContext* ctx = ContextifyContext::Get(args);
580 
581   // Still initializing
582   if (ctx->context_.IsEmpty())
583     return;
584 
585   ContextifyContext::PropertyDescriptorCallback(
586       Uint32ToName(ctx->context(), index), args);
587 }
588 
589 
IndexedPropertyDefinerCallback(uint32_t index,const PropertyDescriptor & desc,const PropertyCallbackInfo<Value> & args)590 void ContextifyContext::IndexedPropertyDefinerCallback(
591     uint32_t index,
592     const PropertyDescriptor& desc,
593     const PropertyCallbackInfo<Value>& args) {
594   ContextifyContext* ctx = ContextifyContext::Get(args);
595 
596   // Still initializing
597   if (ctx->context_.IsEmpty())
598     return;
599 
600   ContextifyContext::PropertyDefinerCallback(
601       Uint32ToName(ctx->context(), index), desc, args);
602 }
603 
604 // static
IndexedPropertyDeleterCallback(uint32_t index,const PropertyCallbackInfo<Boolean> & args)605 void ContextifyContext::IndexedPropertyDeleterCallback(
606     uint32_t index,
607     const PropertyCallbackInfo<Boolean>& args) {
608   ContextifyContext* ctx = ContextifyContext::Get(args);
609 
610   // Still initializing
611   if (ctx->context_.IsEmpty())
612     return;
613 
614   Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
615 
616   if (success.FromMaybe(false))
617     return;
618 
619   // Delete failed on the sandbox, intercept and do not delete on
620   // the global object.
621   args.GetReturnValue().Set(false);
622 }
623 
Init(Environment * env,Local<Object> target)624 void ContextifyScript::Init(Environment* env, Local<Object> target) {
625   HandleScope scope(env->isolate());
626   Local<String> class_name =
627       FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
628 
629   Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
630   script_tmpl->InstanceTemplate()->SetInternalFieldCount(
631       ContextifyScript::kInternalFieldCount);
632   script_tmpl->SetClassName(class_name);
633   env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
634   env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
635   env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);
636 
637   target->Set(env->context(), class_name,
638       script_tmpl->GetFunction(env->context()).ToLocalChecked()).Check();
639   env->set_script_context_constructor_template(script_tmpl);
640 }
641 
New(const FunctionCallbackInfo<Value> & args)642 void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
643   Environment* env = Environment::GetCurrent(args);
644   Isolate* isolate = env->isolate();
645   Local<Context> context = env->context();
646 
647   CHECK(args.IsConstructCall());
648 
649   const int argc = args.Length();
650   CHECK_GE(argc, 2);
651 
652   CHECK(args[0]->IsString());
653   Local<String> code = args[0].As<String>();
654 
655   CHECK(args[1]->IsString());
656   Local<String> filename = args[1].As<String>();
657 
658   Local<Integer> line_offset;
659   Local<Integer> column_offset;
660   Local<ArrayBufferView> cached_data_buf;
661   bool produce_cached_data = false;
662   Local<Context> parsing_context = context;
663 
664   if (argc > 2) {
665     // new ContextifyScript(code, filename, lineOffset, columnOffset,
666     //                      cachedData, produceCachedData, parsingContext)
667     CHECK_EQ(argc, 7);
668     CHECK(args[2]->IsNumber());
669     line_offset = args[2].As<Integer>();
670     CHECK(args[3]->IsNumber());
671     column_offset = args[3].As<Integer>();
672     if (!args[4]->IsUndefined()) {
673       CHECK(args[4]->IsArrayBufferView());
674       cached_data_buf = args[4].As<ArrayBufferView>();
675     }
676     CHECK(args[5]->IsBoolean());
677     produce_cached_data = args[5]->IsTrue();
678     if (!args[6]->IsUndefined()) {
679       CHECK(args[6]->IsObject());
680       ContextifyContext* sandbox =
681           ContextifyContext::ContextFromContextifiedSandbox(
682               env, args[6].As<Object>());
683       CHECK_NOT_NULL(sandbox);
684       parsing_context = sandbox->context();
685     }
686   } else {
687     line_offset = Integer::New(isolate, 0);
688     column_offset = Integer::New(isolate, 0);
689   }
690 
691   ContextifyScript* contextify_script =
692       new ContextifyScript(env, args.This());
693 
694   if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
695           TRACING_CATEGORY_NODE2(vm, script)) != 0) {
696     Utf8Value fn(isolate, filename);
697     TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
698         TRACING_CATEGORY_NODE2(vm, script),
699         "ContextifyScript::New",
700         contextify_script,
701         "filename", TRACE_STR_COPY(*fn));
702   }
703 
704   ScriptCompiler::CachedData* cached_data = nullptr;
705   if (!cached_data_buf.IsEmpty()) {
706     ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents();
707     uint8_t* data = static_cast<uint8_t*>(contents.Data());
708     cached_data = new ScriptCompiler::CachedData(
709         data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
710   }
711 
712   Local<PrimitiveArray> host_defined_options =
713       PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
714   host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
715                             Number::New(isolate, loader::ScriptType::kScript));
716   host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
717                             Number::New(isolate, contextify_script->id()));
718 
719   ScriptOrigin origin(filename,
720                       line_offset,                          // line offset
721                       column_offset,                        // column offset
722                       True(isolate),                        // is cross origin
723                       Local<Integer>(),                     // script id
724                       Local<Value>(),                       // source map URL
725                       False(isolate),                       // is opaque (?)
726                       False(isolate),                       // is WASM
727                       False(isolate),                       // is ES Module
728                       host_defined_options);
729   ScriptCompiler::Source source(code, origin, cached_data);
730   ScriptCompiler::CompileOptions compile_options =
731       ScriptCompiler::kNoCompileOptions;
732 
733   if (source.GetCachedData() != nullptr)
734     compile_options = ScriptCompiler::kConsumeCodeCache;
735 
736   TryCatchScope try_catch(env);
737   ShouldNotAbortOnUncaughtScope no_abort_scope(env);
738   Context::Scope scope(parsing_context);
739 
740   MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
741       isolate,
742       &source,
743       compile_options);
744 
745   if (v8_script.IsEmpty()) {
746     errors::DecorateErrorStack(env, try_catch);
747     no_abort_scope.Close();
748     if (!try_catch.HasTerminated())
749       try_catch.ReThrow();
750     TRACE_EVENT_NESTABLE_ASYNC_END0(
751         TRACING_CATEGORY_NODE2(vm, script),
752         "ContextifyScript::New",
753         contextify_script);
754     return;
755   }
756   contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
757 
758   if (compile_options == ScriptCompiler::kConsumeCodeCache) {
759     args.This()->Set(
760         env->context(),
761         env->cached_data_rejected_string(),
762         Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
763   } else if (produce_cached_data) {
764     std::unique_ptr<ScriptCompiler::CachedData> cached_data {
765       ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
766     bool cached_data_produced = cached_data != nullptr;
767     if (cached_data_produced) {
768       MaybeLocal<Object> buf = Buffer::Copy(
769           env,
770           reinterpret_cast<const char*>(cached_data->data),
771           cached_data->length);
772       args.This()->Set(env->context(),
773                        env->cached_data_string(),
774                        buf.ToLocalChecked()).Check();
775     }
776     args.This()->Set(
777         env->context(),
778         env->cached_data_produced_string(),
779         Boolean::New(isolate, cached_data_produced)).Check();
780   }
781   TRACE_EVENT_NESTABLE_ASYNC_END0(
782       TRACING_CATEGORY_NODE2(vm, script),
783       "ContextifyScript::New",
784       contextify_script);
785 }
786 
InstanceOf(Environment * env,const Local<Value> & value)787 bool ContextifyScript::InstanceOf(Environment* env,
788                                   const Local<Value>& value) {
789   return !value.IsEmpty() &&
790          env->script_context_constructor_template()->HasInstance(value);
791 }
792 
CreateCachedData(const FunctionCallbackInfo<Value> & args)793 void ContextifyScript::CreateCachedData(
794     const FunctionCallbackInfo<Value>& args) {
795   Environment* env = Environment::GetCurrent(args);
796   ContextifyScript* wrapped_script;
797   ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
798   Local<UnboundScript> unbound_script =
799       PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
800   std::unique_ptr<ScriptCompiler::CachedData> cached_data(
801       ScriptCompiler::CreateCodeCache(unbound_script));
802   if (!cached_data) {
803     args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
804   } else {
805     MaybeLocal<Object> buf = Buffer::Copy(
806         env,
807         reinterpret_cast<const char*>(cached_data->data),
808         cached_data->length);
809     args.GetReturnValue().Set(buf.ToLocalChecked());
810   }
811 }
812 
RunInThisContext(const FunctionCallbackInfo<Value> & args)813 void ContextifyScript::RunInThisContext(
814     const FunctionCallbackInfo<Value>& args) {
815   Environment* env = Environment::GetCurrent(args);
816 
817   ContextifyScript* wrapped_script;
818   ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
819 
820   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
821       TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
822 
823   // TODO(addaleax): Use an options object or otherwise merge this with
824   // RunInContext().
825   CHECK_EQ(args.Length(), 4);
826 
827   CHECK(args[0]->IsNumber());
828   int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
829 
830   CHECK(args[1]->IsBoolean());
831   bool display_errors = args[1]->IsTrue();
832 
833   CHECK(args[2]->IsBoolean());
834   bool break_on_sigint = args[2]->IsTrue();
835 
836   CHECK(args[3]->IsBoolean());
837   bool break_on_first_line = args[3]->IsTrue();
838 
839   // Do the eval within this context
840   EvalMachine(env,
841               timeout,
842               display_errors,
843               break_on_sigint,
844               break_on_first_line,
845               args);
846 
847   TRACE_EVENT_NESTABLE_ASYNC_END0(
848       TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
849 }
850 
RunInContext(const FunctionCallbackInfo<Value> & args)851 void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
852   Environment* env = Environment::GetCurrent(args);
853 
854   ContextifyScript* wrapped_script;
855   ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
856 
857   CHECK_EQ(args.Length(), 5);
858 
859   CHECK(args[0]->IsObject());
860   Local<Object> sandbox = args[0].As<Object>();
861   // Get the context from the sandbox
862   ContextifyContext* contextify_context =
863       ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
864   CHECK_NOT_NULL(contextify_context);
865 
866   if (contextify_context->context().IsEmpty())
867     return;
868 
869   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
870       TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
871 
872   CHECK(args[1]->IsNumber());
873   int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
874 
875   CHECK(args[2]->IsBoolean());
876   bool display_errors = args[2]->IsTrue();
877 
878   CHECK(args[3]->IsBoolean());
879   bool break_on_sigint = args[3]->IsTrue();
880 
881   CHECK(args[4]->IsBoolean());
882   bool break_on_first_line = args[4]->IsTrue();
883 
884   // Do the eval within the context
885   Context::Scope context_scope(contextify_context->context());
886   EvalMachine(contextify_context->env(),
887               timeout,
888               display_errors,
889               break_on_sigint,
890               break_on_first_line,
891               args);
892 
893   TRACE_EVENT_NESTABLE_ASYNC_END0(
894       TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
895 }
896 
EvalMachine(Environment * env,const int64_t timeout,const bool display_errors,const bool break_on_sigint,const bool break_on_first_line,const FunctionCallbackInfo<Value> & args)897 bool ContextifyScript::EvalMachine(Environment* env,
898                                    const int64_t timeout,
899                                    const bool display_errors,
900                                    const bool break_on_sigint,
901                                    const bool break_on_first_line,
902                                    const FunctionCallbackInfo<Value>& args) {
903   if (!env->can_call_into_js())
904     return false;
905   if (!ContextifyScript::InstanceOf(env, args.Holder())) {
906     THROW_ERR_INVALID_THIS(
907         env,
908         "Script methods can only be called on script instances.");
909     return false;
910   }
911   TryCatchScope try_catch(env);
912   ContextifyScript* wrapped_script;
913   ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
914   Local<UnboundScript> unbound_script =
915       PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
916   Local<Script> script = unbound_script->BindToCurrentContext();
917 
918 #if HAVE_INSPECTOR
919   if (break_on_first_line) {
920     env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
921   }
922 #endif
923 
924   MaybeLocal<Value> result;
925   bool timed_out = false;
926   bool received_signal = false;
927   if (break_on_sigint && timeout != -1) {
928     Watchdog wd(env->isolate(), timeout, &timed_out);
929     SigintWatchdog swd(env->isolate(), &received_signal);
930     result = script->Run(env->context());
931   } else if (break_on_sigint) {
932     SigintWatchdog swd(env->isolate(), &received_signal);
933     result = script->Run(env->context());
934   } else if (timeout != -1) {
935     Watchdog wd(env->isolate(), timeout, &timed_out);
936     result = script->Run(env->context());
937   } else {
938     result = script->Run(env->context());
939   }
940 
941   // Convert the termination exception into a regular exception.
942   if (timed_out || received_signal) {
943     if (!env->is_main_thread() && env->is_stopping())
944       return false;
945     env->isolate()->CancelTerminateExecution();
946     // It is possible that execution was terminated by another timeout in
947     // which this timeout is nested, so check whether one of the watchdogs
948     // from this invocation is responsible for termination.
949     if (timed_out) {
950       node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
951     } else if (received_signal) {
952       node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
953     }
954   }
955 
956   if (try_catch.HasCaught()) {
957     if (!timed_out && !received_signal && display_errors) {
958       // We should decorate non-termination exceptions
959       errors::DecorateErrorStack(env, try_catch);
960     }
961 
962     // If there was an exception thrown during script execution, re-throw it.
963     // If one of the above checks threw, re-throw the exception instead of
964     // letting try_catch catch it.
965     // If execution has been terminated, but not by one of the watchdogs from
966     // this invocation, this will re-throw a `null` value.
967     if (!try_catch.HasTerminated())
968       try_catch.ReThrow();
969 
970     return false;
971   }
972 
973   args.GetReturnValue().Set(result.ToLocalChecked());
974   return true;
975 }
976 
977 
ContextifyScript(Environment * env,Local<Object> object)978 ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
979     : BaseObject(env, object),
980       id_(env->get_next_script_id()) {
981   MakeWeak();
982   env->id_to_script_map.emplace(id_, this);
983 }
984 
985 
~ContextifyScript()986 ContextifyScript::~ContextifyScript() {
987   env()->id_to_script_map.erase(id_);
988 }
989 
990 
CompileFunction(const FunctionCallbackInfo<Value> & args)991 void ContextifyContext::CompileFunction(
992     const FunctionCallbackInfo<Value>& args) {
993   Environment* env = Environment::GetCurrent(args);
994   Isolate* isolate = env->isolate();
995   Local<Context> context = env->context();
996 
997   // Argument 1: source code
998   CHECK(args[0]->IsString());
999   Local<String> code = args[0].As<String>();
1000 
1001   // Argument 2: filename
1002   CHECK(args[1]->IsString());
1003   Local<String> filename = args[1].As<String>();
1004 
1005   // Argument 3: line offset
1006   CHECK(args[2]->IsNumber());
1007   Local<Integer> line_offset = args[2].As<Integer>();
1008 
1009   // Argument 4: column offset
1010   CHECK(args[3]->IsNumber());
1011   Local<Integer> column_offset = args[3].As<Integer>();
1012 
1013   // Argument 5: cached data (optional)
1014   Local<ArrayBufferView> cached_data_buf;
1015   if (!args[4]->IsUndefined()) {
1016     CHECK(args[4]->IsArrayBufferView());
1017     cached_data_buf = args[4].As<ArrayBufferView>();
1018   }
1019 
1020   // Argument 6: produce cache data
1021   CHECK(args[5]->IsBoolean());
1022   bool produce_cached_data = args[5]->IsTrue();
1023 
1024   // Argument 7: parsing context (optional)
1025   Local<Context> parsing_context;
1026   if (!args[6]->IsUndefined()) {
1027     CHECK(args[6]->IsObject());
1028     ContextifyContext* sandbox =
1029         ContextifyContext::ContextFromContextifiedSandbox(
1030             env, args[6].As<Object>());
1031     CHECK_NOT_NULL(sandbox);
1032     parsing_context = sandbox->context();
1033   } else {
1034     parsing_context = context;
1035   }
1036 
1037   // Argument 8: context extensions (optional)
1038   Local<Array> context_extensions_buf;
1039   if (!args[7]->IsUndefined()) {
1040     CHECK(args[7]->IsArray());
1041     context_extensions_buf = args[7].As<Array>();
1042   }
1043 
1044   // Argument 9: params for the function (optional)
1045   Local<Array> params_buf;
1046   if (!args[8]->IsUndefined()) {
1047     CHECK(args[8]->IsArray());
1048     params_buf = args[8].As<Array>();
1049   }
1050 
1051   // Read cache from cached data buffer
1052   ScriptCompiler::CachedData* cached_data = nullptr;
1053   if (!cached_data_buf.IsEmpty()) {
1054     ArrayBuffer::Contents contents = cached_data_buf->Buffer()->GetContents();
1055     uint8_t* data = static_cast<uint8_t*>(contents.Data());
1056     cached_data = new ScriptCompiler::CachedData(
1057       data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1058   }
1059 
1060   // Get the function id
1061   uint32_t id = env->get_next_function_id();
1062 
1063   // Set host_defined_options
1064   Local<PrimitiveArray> host_defined_options =
1065       PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1066   host_defined_options->Set(
1067       isolate,
1068       loader::HostDefinedOptions::kType,
1069       Number::New(isolate, loader::ScriptType::kFunction));
1070   host_defined_options->Set(
1071       isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1072 
1073   ScriptOrigin origin(filename,
1074                       line_offset,       // line offset
1075                       column_offset,     // column offset
1076                       True(isolate),     // is cross origin
1077                       Local<Integer>(),  // script id
1078                       Local<Value>(),    // source map URL
1079                       False(isolate),    // is opaque (?)
1080                       False(isolate),    // is WASM
1081                       False(isolate),    // is ES Module
1082                       host_defined_options);
1083 
1084   ScriptCompiler::Source source(code, origin, cached_data);
1085   ScriptCompiler::CompileOptions options;
1086   if (source.GetCachedData() == nullptr) {
1087     options = ScriptCompiler::kNoCompileOptions;
1088   } else {
1089     options = ScriptCompiler::kConsumeCodeCache;
1090   }
1091 
1092   TryCatchScope try_catch(env);
1093   Context::Scope scope(parsing_context);
1094 
1095   // Read context extensions from buffer
1096   std::vector<Local<Object>> context_extensions;
1097   if (!context_extensions_buf.IsEmpty()) {
1098     for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1099       Local<Value> val;
1100       if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1101       CHECK(val->IsObject());
1102       context_extensions.push_back(val.As<Object>());
1103     }
1104   }
1105 
1106   // Read params from params buffer
1107   std::vector<Local<String>> params;
1108   if (!params_buf.IsEmpty()) {
1109     for (uint32_t n = 0; n < params_buf->Length(); n++) {
1110       Local<Value> val;
1111       if (!params_buf->Get(context, n).ToLocal(&val)) return;
1112       CHECK(val->IsString());
1113       params.push_back(val.As<String>());
1114     }
1115   }
1116 
1117   Local<ScriptOrModule> script;
1118   MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext(
1119       parsing_context, &source, params.size(), params.data(),
1120       context_extensions.size(), context_extensions.data(), options,
1121       v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1122 
1123   Local<Function> fn;
1124   if (!maybe_fn.ToLocal(&fn)) {
1125     if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1126       errors::DecorateErrorStack(env, try_catch);
1127       try_catch.ReThrow();
1128     }
1129     return;
1130   }
1131 
1132   Local<Object> cache_key;
1133   if (!env->compiled_fn_entry_template()->NewInstance(
1134            context).ToLocal(&cache_key)) {
1135     return;
1136   }
1137   CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1138   env->id_to_function_map.emplace(id, entry);
1139 
1140   Local<Object> result = Object::New(isolate);
1141   if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1142     return;
1143   if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1144           .IsNothing())
1145     return;
1146 
1147   if (produce_cached_data) {
1148     const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1149         ScriptCompiler::CreateCodeCacheForFunction(fn));
1150     bool cached_data_produced = cached_data != nullptr;
1151     if (cached_data_produced) {
1152       MaybeLocal<Object> buf = Buffer::Copy(
1153           env,
1154           reinterpret_cast<const char*>(cached_data->data),
1155           cached_data->length);
1156       if (result
1157               ->Set(parsing_context,
1158                     env->cached_data_string(),
1159                     buf.ToLocalChecked())
1160               .IsNothing())
1161         return;
1162     }
1163     if (result
1164             ->Set(parsing_context,
1165                   env->cached_data_produced_string(),
1166                   Boolean::New(isolate, cached_data_produced))
1167             .IsNothing())
1168       return;
1169   }
1170 
1171   args.GetReturnValue().Set(result);
1172 }
1173 
WeakCallback(const WeakCallbackInfo<CompiledFnEntry> & data)1174 void CompiledFnEntry::WeakCallback(
1175     const WeakCallbackInfo<CompiledFnEntry>& data) {
1176   CompiledFnEntry* entry = data.GetParameter();
1177   delete entry;
1178 }
1179 
CompiledFnEntry(Environment * env,Local<Object> object,uint32_t id,Local<ScriptOrModule> script)1180 CompiledFnEntry::CompiledFnEntry(Environment* env,
1181                                  Local<Object> object,
1182                                  uint32_t id,
1183                                  Local<ScriptOrModule> script)
1184     : BaseObject(env, object),
1185       id_(id),
1186       script_(env->isolate(), script) {
1187   script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1188 }
1189 
~CompiledFnEntry()1190 CompiledFnEntry::~CompiledFnEntry() {
1191   env()->id_to_function_map.erase(id_);
1192   script_.ClearWeak();
1193 }
1194 
StartSigintWatchdog(const FunctionCallbackInfo<Value> & args)1195 static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1196   int ret = SigintWatchdogHelper::GetInstance()->Start();
1197   args.GetReturnValue().Set(ret == 0);
1198 }
1199 
StopSigintWatchdog(const FunctionCallbackInfo<Value> & args)1200 static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1201   bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1202   args.GetReturnValue().Set(had_pending_signals);
1203 }
1204 
WatchdogHasPendingSigint(const FunctionCallbackInfo<Value> & args)1205 static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1206   bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1207   args.GetReturnValue().Set(ret);
1208 }
1209 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)1210 void Initialize(Local<Object> target,
1211                 Local<Value> unused,
1212                 Local<Context> context,
1213                 void* priv) {
1214   Environment* env = Environment::GetCurrent(context);
1215   ContextifyContext::Init(env, target);
1216   ContextifyScript::Init(env, target);
1217 
1218   env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1219   env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1220   // Used in tests.
1221   env->SetMethodNoSideEffect(
1222       target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1223 
1224   {
1225     Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1226     tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1227     tpl->InstanceTemplate()->SetInternalFieldCount(
1228         CompiledFnEntry::kInternalFieldCount);
1229 
1230     env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1231   }
1232 }
1233 
1234 }  // namespace contextify
1235 }  // namespace node
1236 
1237 NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)
1238