• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "node_buffer.h"
2 #include "node_internals.h"
3 #include "libplatform/libplatform.h"
4 #include "util.h"
5 
6 #include <string>
7 #include "gtest/gtest.h"
8 #include "node_test_fixture.h"
9 #include <stdio.h>
10 #include <cstdio>
11 
12 using node::AtExit;
13 using node::RunAtExit;
14 using node::USE;
15 
16 static bool called_cb_1 = false;
17 static bool called_cb_2 = false;
18 static bool called_cb_ordered_1 = false;
19 static bool called_cb_ordered_2 = false;
20 static bool called_at_exit_js = false;
21 static void at_exit_callback1(void* arg);
22 static void at_exit_callback2(void* arg);
23 static void at_exit_callback_ordered1(void* arg);
24 static void at_exit_callback_ordered2(void* arg);
25 static void at_exit_js(void* arg);
26 static std::string cb_1_arg;  // NOLINT(runtime/string)
27 
28 class EnvironmentTest : public EnvironmentTestFixture {
29  private:
TearDown()30   void TearDown() override {
31     NodeTestFixture::TearDown();
32     called_cb_1 = false;
33     called_cb_2 = false;
34     called_cb_ordered_1 = false;
35     called_cb_ordered_2 = false;
36   }
37 };
38 
TEST_F(EnvironmentTest,EnvironmentWithESMLoader)39 TEST_F(EnvironmentTest, EnvironmentWithESMLoader) {
40   const v8::HandleScope handle_scope(isolate_);
41   Argv argv;
42   Env env {handle_scope, argv};
43 
44   node::Environment* envi = *env;
45   envi->options()->experimental_vm_modules = true;
46 
47   SetProcessExitHandler(*env, [&](node::Environment* env_, int exit_code) {
48     EXPECT_EQ(*env, env_);
49     EXPECT_EQ(exit_code, 0);
50     node::Stop(*env);
51   });
52 
53   node::LoadEnvironment(
54       *env,
55       "const { SourceTextModule } = require('vm');"
56       "(async () => {"
57         "const stmString = 'globalThis.importResult = import(\"\")';"
58         "const m = new SourceTextModule(stmString, {"
59           "importModuleDynamically: (async () => {"
60             "const m = new SourceTextModule('');"
61             "await m.link(() => 0);"
62             "await m.evaluate();"
63             "return m.namespace;"
64           "}),"
65         "});"
66         "await m.link(() => 0);"
67         "await m.evaluate();"
68         "delete globalThis.importResult;"
69         "process.exit(0);"
70       "})()");
71 }
72 
73 class RedirectStdErr {
74  public:
RedirectStdErr(const char * filename)75   explicit RedirectStdErr(const char* filename) : filename_(filename) {
76     fflush(stderr);
77     fgetpos(stderr, &pos_);
78     fd_ = dup(fileno(stderr));
79     USE(freopen(filename_, "w", stderr));
80   }
81 
~RedirectStdErr()82   ~RedirectStdErr() {
83     fflush(stderr);
84     dup2(fd_, fileno(stderr));
85     close(fd_);
86     remove(filename_);
87     clearerr(stderr);
88     fsetpos(stderr, &pos_);
89   }
90 
91  private:
92   int fd_;
93   fpos_t pos_;
94   const char* filename_;
95 };
96 
TEST_F(EnvironmentTest,EnvironmentWithNoESMLoader)97 TEST_F(EnvironmentTest, EnvironmentWithNoESMLoader) {
98   // The following line will cause stderr to get redirected to avoid the
99   // error that would otherwise be printed to the console by this test.
100   RedirectStdErr redirect_scope("environment_test.log");
101   const v8::HandleScope handle_scope(isolate_);
102   Argv argv;
103   Env env {handle_scope, argv, node::EnvironmentFlags::kNoRegisterESMLoader};
104 
105   node::Environment* envi = *env;
106   envi->options()->experimental_vm_modules = true;
107 
108   SetProcessExitHandler(*env, [&](node::Environment* env_, int exit_code) {
109     EXPECT_EQ(*env, env_);
110     EXPECT_EQ(exit_code, 1);
111     node::Stop(*env);
112   });
113 
114   node::LoadEnvironment(
115       *env,
116       "const { SourceTextModule } = require('vm');"
117       "(async () => {"
118         "const stmString = 'globalThis.importResult = import(\"\")';"
119         "const m = new SourceTextModule(stmString, {"
120           "importModuleDynamically: (async () => {"
121             "const m = new SourceTextModule('');"
122             "await m.link(() => 0);"
123             "await m.evaluate();"
124             "return m.namespace;"
125           "}),"
126         "});"
127         "await m.link(() => 0);"
128         "await m.evaluate();"
129         "delete globalThis.importResult;"
130       "})()");
131 }
132 
TEST_F(EnvironmentTest,PreExecutionPreparation)133 TEST_F(EnvironmentTest, PreExecutionPreparation) {
134   const v8::HandleScope handle_scope(isolate_);
135   const Argv argv;
136   Env env {handle_scope, argv};
137 
138   node::LoadEnvironment(*env, [&](const node::StartExecutionCallbackInfo& info)
139                                   -> v8::MaybeLocal<v8::Value> {
140     return v8::Null(isolate_);
141   });
142 
143   v8::Local<v8::Context> context = isolate_->GetCurrentContext();
144   const char* run_script = "process.argv0";
145   v8::Local<v8::Script> script = v8::Script::Compile(
146       context,
147       v8::String::NewFromOneByte(isolate_,
148                                  reinterpret_cast<const uint8_t*>(run_script))
149                                  .ToLocalChecked())
150       .ToLocalChecked();
151   v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
152   CHECK(result->IsString());
153 }
154 
TEST_F(EnvironmentTest,LoadEnvironmentWithCallback)155 TEST_F(EnvironmentTest, LoadEnvironmentWithCallback) {
156   const v8::HandleScope handle_scope(isolate_);
157   const Argv argv;
158   Env env {handle_scope, argv};
159 
160   v8::Local<v8::Context> context = isolate_->GetCurrentContext();
161   bool called_cb = false;
162   node::LoadEnvironment(*env,
163                         [&](const node::StartExecutionCallbackInfo& info)
164                             -> v8::MaybeLocal<v8::Value> {
165     called_cb = true;
166 
167     CHECK(info.process_object->IsObject());
168     CHECK(info.native_require->IsFunction());
169 
170     v8::Local<v8::Value> argv0 = info.process_object->Get(
171         context,
172         v8::String::NewFromOneByte(
173             isolate_,
174             reinterpret_cast<const uint8_t*>("argv0"))
175             .ToLocalChecked()).ToLocalChecked();
176     CHECK(argv0->IsString());
177 
178     return info.process_object;
179   });
180 
181   CHECK(called_cb);
182 }
183 
TEST_F(EnvironmentTest,LoadEnvironmentWithSource)184 TEST_F(EnvironmentTest, LoadEnvironmentWithSource) {
185   const v8::HandleScope handle_scope(isolate_);
186   const Argv argv;
187   Env env {handle_scope, argv};
188 
189   v8::Local<v8::Context> context = isolate_->GetCurrentContext();
190   v8::Local<v8::Value> main_ret =
191       node::LoadEnvironment(*env,
192                             "return { process, require };").ToLocalChecked();
193 
194   CHECK(main_ret->IsObject());
195   CHECK(main_ret.As<v8::Object>()->Get(
196       context,
197       v8::String::NewFromOneByte(
198           isolate_,
199           reinterpret_cast<const uint8_t*>("process"))
200           .ToLocalChecked())
201           .ToLocalChecked()->IsObject());
202   CHECK(main_ret.As<v8::Object>()->Get(
203       context,
204       v8::String::NewFromOneByte(
205           isolate_,
206           reinterpret_cast<const uint8_t*>("require"))
207           .ToLocalChecked())
208           .ToLocalChecked()->IsFunction());
209 }
210 
TEST_F(EnvironmentTest,AtExitWithEnvironment)211 TEST_F(EnvironmentTest, AtExitWithEnvironment) {
212   const v8::HandleScope handle_scope(isolate_);
213   const Argv argv;
214   Env env {handle_scope, argv};
215 
216   AtExit(*env, at_exit_callback1);
217   RunAtExit(*env);
218   EXPECT_TRUE(called_cb_1);
219 }
220 
TEST_F(EnvironmentTest,AtExitWithoutEnvironment)221 TEST_F(EnvironmentTest, AtExitWithoutEnvironment) {
222   const v8::HandleScope handle_scope(isolate_);
223   const Argv argv;
224   Env env {handle_scope, argv};
225 
226   AtExit(at_exit_callback1);  // No Environment is passed to AtExit.
227   RunAtExit(*env);
228   EXPECT_TRUE(called_cb_1);
229 }
230 
TEST_F(EnvironmentTest,AtExitOrder)231 TEST_F(EnvironmentTest, AtExitOrder) {
232   const v8::HandleScope handle_scope(isolate_);
233   const Argv argv;
234   Env env {handle_scope, argv};
235 
236   // Test that callbacks are run in reverse order.
237   AtExit(*env, at_exit_callback_ordered1);
238   AtExit(*env, at_exit_callback_ordered2);
239   RunAtExit(*env);
240   EXPECT_TRUE(called_cb_ordered_1);
241   EXPECT_TRUE(called_cb_ordered_2);
242 }
243 
TEST_F(EnvironmentTest,AtExitWithArgument)244 TEST_F(EnvironmentTest, AtExitWithArgument) {
245   const v8::HandleScope handle_scope(isolate_);
246   const Argv argv;
247   Env env {handle_scope, argv};
248 
249   std::string arg{"some args"};
250   AtExit(*env, at_exit_callback1, static_cast<void*>(&arg));
251   RunAtExit(*env);
252   EXPECT_EQ(arg, cb_1_arg);
253 }
254 
TEST_F(EnvironmentTest,AtExitRunsJS)255 TEST_F(EnvironmentTest, AtExitRunsJS) {
256   const v8::HandleScope handle_scope(isolate_);
257   const Argv argv;
258   Env env {handle_scope, argv};
259 
260   AtExit(*env, at_exit_js, static_cast<void*>(isolate_));
261   EXPECT_FALSE(called_at_exit_js);
262   RunAtExit(*env);
263   EXPECT_TRUE(called_at_exit_js);
264 }
265 
TEST_F(EnvironmentTest,MultipleEnvironmentsPerIsolate)266 TEST_F(EnvironmentTest, MultipleEnvironmentsPerIsolate) {
267   const v8::HandleScope handle_scope(isolate_);
268   const Argv argv;
269   // Only one of the Environments can have default flags and own the inspector.
270   Env env1 {handle_scope, argv};
271   Env env2 {handle_scope, argv, node::EnvironmentFlags::kNoFlags};
272 
273   AtExit(*env1, at_exit_callback1);
274   AtExit(*env2, at_exit_callback2);
275   RunAtExit(*env1);
276   EXPECT_TRUE(called_cb_1);
277   EXPECT_FALSE(called_cb_2);
278 
279   RunAtExit(*env2);
280   EXPECT_TRUE(called_cb_2);
281 }
282 
TEST_F(EnvironmentTest,NoEnvironmentSanity)283 TEST_F(EnvironmentTest, NoEnvironmentSanity) {
284   const v8::HandleScope handle_scope(isolate_);
285   v8::Local<v8::Context> context = v8::Context::New(isolate_);
286   EXPECT_EQ(node::Environment::GetCurrent(context), nullptr);
287   EXPECT_EQ(node::GetCurrentEnvironment(context), nullptr);
288   EXPECT_EQ(node::Environment::GetCurrent(isolate_), nullptr);
289 
290   v8::Context::Scope context_scope(context);
291   EXPECT_EQ(node::Environment::GetCurrent(context), nullptr);
292   EXPECT_EQ(node::GetCurrentEnvironment(context), nullptr);
293   EXPECT_EQ(node::Environment::GetCurrent(isolate_), nullptr);
294 }
295 
TEST_F(EnvironmentTest,NonNodeJSContext)296 TEST_F(EnvironmentTest, NonNodeJSContext) {
297   const v8::HandleScope handle_scope(isolate_);
298   const Argv argv;
299   Env test_env {handle_scope, argv};
300 
301   EXPECT_EQ(node::Environment::GetCurrent(v8::Local<v8::Context>()), nullptr);
302 
303   node::Environment* env = *test_env;
304   EXPECT_EQ(node::Environment::GetCurrent(isolate_), env);
305   EXPECT_EQ(node::Environment::GetCurrent(env->context()), env);
306   EXPECT_EQ(node::GetCurrentEnvironment(env->context()), env);
307 
308   v8::Local<v8::Context> context = v8::Context::New(isolate_);
309   EXPECT_EQ(node::Environment::GetCurrent(context), nullptr);
310   EXPECT_EQ(node::GetCurrentEnvironment(context), nullptr);
311   EXPECT_EQ(node::Environment::GetCurrent(isolate_), env);
312 
313   v8::Context::Scope context_scope(context);
314   EXPECT_EQ(node::Environment::GetCurrent(context), nullptr);
315   EXPECT_EQ(node::GetCurrentEnvironment(context), nullptr);
316   EXPECT_EQ(node::Environment::GetCurrent(isolate_), nullptr);
317 }
318 
at_exit_callback1(void * arg)319 static void at_exit_callback1(void* arg) {
320   called_cb_1 = true;
321   if (arg) {
322     cb_1_arg = *static_cast<std::string*>(arg);
323   }
324 }
325 
at_exit_callback2(void * arg)326 static void at_exit_callback2(void* arg) {
327   called_cb_2 = true;
328 }
329 
at_exit_callback_ordered1(void * arg)330 static void at_exit_callback_ordered1(void* arg) {
331   EXPECT_TRUE(called_cb_ordered_2);
332   called_cb_ordered_1 = true;
333 }
334 
at_exit_callback_ordered2(void * arg)335 static void at_exit_callback_ordered2(void* arg) {
336   EXPECT_FALSE(called_cb_ordered_1);
337   called_cb_ordered_2 = true;
338 }
339 
at_exit_js(void * arg)340 static void at_exit_js(void* arg) {
341   v8::Isolate* isolate = static_cast<v8::Isolate*>(arg);
342   v8::HandleScope handle_scope(isolate);
343   v8::Local<v8::Object> obj = v8::Object::New(isolate);
344   EXPECT_FALSE(obj.IsEmpty());  // Assert VM is still alive.
345   EXPECT_TRUE(obj->IsObject());
346   called_at_exit_js = true;
347 }
348 
TEST_F(EnvironmentTest,SetImmediateCleanup)349 TEST_F(EnvironmentTest, SetImmediateCleanup) {
350   int called = 0;
351   int called_unref = 0;
352 
353   {
354     const v8::HandleScope handle_scope(isolate_);
355     const Argv argv;
356     Env env {handle_scope, argv};
357 
358     node::LoadEnvironment(*env,
359                           [&](const node::StartExecutionCallbackInfo& info)
360                               -> v8::MaybeLocal<v8::Value> {
361       return v8::Object::New(isolate_);
362     });
363 
364     (*env)->SetImmediate([&](node::Environment* env_arg) {
365       EXPECT_EQ(env_arg, *env);
366       called++;
367     }, node::CallbackFlags::kRefed);
368     (*env)->SetImmediate([&](node::Environment* env_arg) {
369       EXPECT_EQ(env_arg, *env);
370       called_unref++;
371     }, node::CallbackFlags::kUnrefed);
372   }
373 
374   EXPECT_EQ(called, 1);
375   EXPECT_EQ(called_unref, 0);
376 }
377 
378 static char hello[] = "hello";
379 
TEST_F(EnvironmentTest,BufferWithFreeCallbackIsDetached)380 TEST_F(EnvironmentTest, BufferWithFreeCallbackIsDetached) {
381   // Test that a Buffer allocated with a free callback is detached after
382   // its callback has been called.
383   const v8::HandleScope handle_scope(isolate_);
384   const Argv argv;
385 
386   int callback_calls = 0;
387 
388   v8::Local<v8::ArrayBuffer> ab;
389   {
390     Env env {handle_scope, argv};
391     v8::Local<v8::Object> buf_obj = node::Buffer::New(
392         isolate_,
393         hello,
394         sizeof(hello),
395         [](char* data, void* hint) {
396           CHECK_EQ(data, hello);
397           ++*static_cast<int*>(hint);
398         },
399         &callback_calls).ToLocalChecked();
400     CHECK(buf_obj->IsUint8Array());
401     ab = buf_obj.As<v8::Uint8Array>()->Buffer();
402     CHECK_EQ(ab->ByteLength(), sizeof(hello));
403   }
404 
405   CHECK_EQ(callback_calls, 1);
406   CHECK_EQ(ab->ByteLength(), 0);
407 }
408 
409 #if HAVE_INSPECTOR
TEST_F(EnvironmentTest,InspectorMultipleEmbeddedEnvironments)410 TEST_F(EnvironmentTest, InspectorMultipleEmbeddedEnvironments) {
411   // Tests that child Environments can be created through the public API
412   // that are accessible by the inspector.
413   // This test sets a global variable in the child Environment, and reads it
414   // back both through the inspector and inside the child Environment, and
415   // makes sure that those correspond to the value that was originally set.
416   const v8::HandleScope handle_scope(isolate_);
417   const Argv argv;
418   Env env {handle_scope, argv};
419 
420   v8::Local<v8::Context> context = isolate_->GetCurrentContext();
421   node::LoadEnvironment(*env,
422       "'use strict';\n"
423       "const { Worker } = require('worker_threads');\n"
424       "const { Session } = require('inspector');\n"
425 
426       "const session = new Session();\n"
427       "session.connect();\n"
428       "session.on('NodeWorker.attachedToWorker', (\n"
429       "  ({ params: { workerInfo, sessionId } }) => {\n"
430       "    session.post('NodeWorker.sendMessageToWorker', {\n"
431       "      sessionId,\n"
432       "      message: JSON.stringify({\n"
433       "        id: 1,\n"
434       "        method: 'Runtime.evaluate',\n"
435       "        params: {\n"
436       "          expression: 'globalThis.variableFromParent = 42;'\n"
437       "        }\n"
438       "      })\n"
439       "    });\n"
440       "    session.on('NodeWorker.receivedMessageFromWorker',\n"
441       "      ({ params: { message } }) => {\n"
442       "        global.messageFromWorker = \n"
443       "          JSON.parse(message).result.result.value;\n"
444       "      });\n"
445       "  }));\n"
446       "session.post('NodeWorker.enable', { waitForDebuggerOnStart: false });\n")
447           .ToLocalChecked();
448 
449   struct ChildEnvironmentData {
450     node::ThreadId thread_id;
451     std::unique_ptr<node::InspectorParentHandle> inspector_parent_handle;
452     node::MultiIsolatePlatform* platform;
453     int32_t extracted_value = -1;
454     uv_async_t thread_stopped_async;
455   };
456 
457   ChildEnvironmentData data;
458   data.thread_id = node::AllocateEnvironmentThreadId();
459   data.inspector_parent_handle =
460       GetInspectorParentHandle(*env, data.thread_id, "file:///embedded.js");
461   CHECK(data.inspector_parent_handle);
462   data.platform = GetMultiIsolatePlatform(*env);
463   CHECK_NOT_NULL(data.platform);
464 
465   bool thread_stopped = false;
466   int err = uv_async_init(
467       &current_loop, &data.thread_stopped_async, [](uv_async_t* async) {
468         *static_cast<bool*>(async->data) = true;
469         uv_close(reinterpret_cast<uv_handle_t*>(async), nullptr);
470       });
471   CHECK_EQ(err, 0);
472   data.thread_stopped_async.data = &thread_stopped;
473 
474   uv_thread_t thread;
475   err = uv_thread_create(&thread, [](void* arg) {
476     ChildEnvironmentData* data = static_cast<ChildEnvironmentData*>(arg);
477     std::shared_ptr<node::ArrayBufferAllocator> aba =
478         node::ArrayBufferAllocator::Create();
479     uv_loop_t loop;
480     uv_loop_init(&loop);
481     v8::Isolate* isolate = NewIsolate(aba, &loop, data->platform);
482     CHECK_NOT_NULL(isolate);
483 
484     {
485       v8::Isolate::Scope isolate_scope(isolate);
486       v8::HandleScope handle_scope(isolate);
487 
488       v8::Local<v8::Context> context = node::NewContext(isolate);
489       CHECK(!context.IsEmpty());
490       v8::Context::Scope context_scope(context);
491 
492       node::IsolateData* isolate_data = node::CreateIsolateData(
493           isolate,
494           &loop,
495           data->platform);
496       CHECK_NOT_NULL(isolate_data);
497       node::Environment* environment = node::CreateEnvironment(
498           isolate_data,
499           context,
500           { "dummy" },
501           {},
502           node::EnvironmentFlags::kNoFlags,
503           data->thread_id,
504           std::move(data->inspector_parent_handle));
505       CHECK_NOT_NULL(environment);
506 
507       v8::Local<v8::Value> extracted_value = LoadEnvironment(
508           environment,
509           "while (!global.variableFromParent) {}\n"
510           "return global.variableFromParent;").ToLocalChecked();
511 
512       uv_run(&loop, UV_RUN_DEFAULT);
513       CHECK(extracted_value->IsInt32());
514       data->extracted_value = extracted_value.As<v8::Int32>()->Value();
515 
516       node::FreeEnvironment(environment);
517       node::FreeIsolateData(isolate_data);
518     }
519 
520     data->platform->UnregisterIsolate(isolate);
521     isolate->Dispose();
522     uv_run(&loop, UV_RUN_DEFAULT);
523     CHECK_EQ(uv_loop_close(&loop), 0);
524 
525     uv_async_send(&data->thread_stopped_async);
526   }, &data);
527   CHECK_EQ(err, 0);
528 
529   bool more;
530   do {
531     uv_run(&current_loop, UV_RUN_DEFAULT);
532     data.platform->DrainTasks(isolate_);
533     more = uv_loop_alive(&current_loop);
534   } while (!thread_stopped || more);
535 
536   uv_thread_join(&thread);
537 
538   v8::Local<v8::Value> from_inspector =
539       context->Global()->Get(
540           context,
541           v8::String::NewFromOneByte(
542               isolate_,
543               reinterpret_cast<const uint8_t*>("messageFromWorker"))
544               .ToLocalChecked())
545               .ToLocalChecked();
546   CHECK_EQ(data.extracted_value, 42);
547   CHECK_EQ(from_inspector->IntegerValue(context).FromJust(), 42);
548 }
549 #endif  // HAVE_INSPECTOR
550 
TEST_F(EnvironmentTest,ExitHandlerTest)551 TEST_F(EnvironmentTest, ExitHandlerTest) {
552   const v8::HandleScope handle_scope(isolate_);
553   const Argv argv;
554 
555   int callback_calls = 0;
556 
557   Env env {handle_scope, argv};
558   SetProcessExitHandler(*env, [&](node::Environment* env_, int exit_code) {
559     EXPECT_EQ(*env, env_);
560     EXPECT_EQ(exit_code, 42);
561     callback_calls++;
562     node::Stop(*env);
563   });
564   node::LoadEnvironment(*env, "process.exit(42)").ToLocalChecked();
565   EXPECT_EQ(callback_calls, 1);
566 }
567 
TEST_F(EnvironmentTest,SetImmediateMicrotasks)568 TEST_F(EnvironmentTest, SetImmediateMicrotasks) {
569   int called = 0;
570 
571   {
572     const v8::HandleScope handle_scope(isolate_);
573     const Argv argv;
574     Env env {handle_scope, argv};
575 
576     node::LoadEnvironment(*env,
577                           [&](const node::StartExecutionCallbackInfo& info)
578                               -> v8::MaybeLocal<v8::Value> {
579       return v8::Object::New(isolate_);
580     });
581 
582     (*env)->SetImmediate([&](node::Environment* env_arg) {
583       EXPECT_EQ(env_arg, *env);
584       isolate_->EnqueueMicrotask([](void* arg) {
585         ++*static_cast<int*>(arg);
586       }, &called);
587     }, node::CallbackFlags::kRefed);
588     uv_run(&current_loop, UV_RUN_DEFAULT);
589   }
590 
591   EXPECT_EQ(called, 1);
592 }
593 
594 #ifndef _WIN32  // No SIGINT on Windows.
TEST_F(NodeZeroIsolateTestFixture,CtrlCWithOnlySafeTerminationTest)595 TEST_F(NodeZeroIsolateTestFixture, CtrlCWithOnlySafeTerminationTest) {
596   // We need to go through the whole setup dance here because we want to
597   // set only_terminate_in_safe_scope.
598   // Allocate and initialize Isolate.
599   v8::Isolate::CreateParams create_params;
600   create_params.array_buffer_allocator = allocator.get();
601   create_params.only_terminate_in_safe_scope = true;
602   v8::Isolate* isolate = v8::Isolate::Allocate();
603   CHECK_NOT_NULL(isolate);
604   platform->RegisterIsolate(isolate, &current_loop);
605   v8::Isolate::Initialize(isolate, create_params);
606 
607   // Try creating Context + IsolateData + Environment.
608   {
609     v8::Isolate::Scope isolate_scope(isolate);
610     v8::HandleScope handle_scope(isolate);
611 
612     auto context = node::NewContext(isolate);
613     CHECK(!context.IsEmpty());
614     v8::Context::Scope context_scope(context);
615 
616     std::unique_ptr<node::IsolateData, decltype(&node::FreeIsolateData)>
617       isolate_data{node::CreateIsolateData(isolate,
618                                            &current_loop,
619                                            platform.get()),
620                    node::FreeIsolateData};
621     CHECK(isolate_data);
622 
623     std::unique_ptr<node::Environment, decltype(&node::FreeEnvironment)>
624       environment{node::CreateEnvironment(isolate_data.get(),
625                                           context,
626                                           {},
627                                           {}),
628                   node::FreeEnvironment};
629     CHECK(environment);
630     EXPECT_EQ(node::GetEnvironmentIsolateData(environment.get()),
631               isolate_data.get());
632     EXPECT_EQ(node::GetArrayBufferAllocator(isolate_data.get()), nullptr);
633 
634     v8::Local<v8::Value> main_ret =
635         node::LoadEnvironment(environment.get(),
636             "'use strict';\n"
637             "const { runInThisContext } = require('vm');\n"
638             "try {\n"
639             "  runInThisContext("
640             "    `process.kill(process.pid, 'SIGINT'); while(true){}`, "
641             "    { breakOnSigint: true });\n"
642             "  return 'unreachable';\n"
643             "} catch (err) {\n"
644             "  return err.code;\n"
645             "}").ToLocalChecked();
646     node::Utf8Value main_ret_str(isolate, main_ret);
647     EXPECT_EQ(std::string(*main_ret_str), "ERR_SCRIPT_EXECUTION_INTERRUPTED");
648   }
649 
650   // Cleanup.
651   platform->UnregisterIsolate(isolate);
652   isolate->Dispose();
653 }
654 #endif  // _WIN32
655