Skip to content

Commit 42c14c5

Browse files
committed
src: set thread local env in CreateEnvironment
This commit set the Environment as a thread local when CreateEnvironment is called which is currently not being done. This would lead to a segment fault if later node::AtExit is called without specifying the environment parameter. This specific issue was reported by Electron. If I recall correctly, back when this was implemented the motivation was that if embedders have multiple environments per isolate they should be using the AtExit functions that take an environment. This is not the case with Electron which only create a single environment (as far as I know), and if a native module calls AtExit this would lead to the segment fault. I was able to reproduce Electron issue and the provided test simulates it. I was also able to use this patch and verify that it works for the Electron issue as well. PR-URL: nodejs#18573 Refs: nodejs#9163 Refs: electron/electron#11299 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Matheus Marchini <matheus@sthima.com>
1 parent efb3259 commit 42c14c5

File tree

5 files changed

+29
-7
lines changed

5 files changed

+29
-7
lines changed

src/env-inl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ inline Environment* Environment::GetCurrent(
311311
info.Data().template As<v8::External>()->Value());
312312
}
313313

314+
inline Environment* Environment::GetThreadLocalEnv() {
315+
return static_cast<Environment*>(uv_key_get(&thread_local_env));
316+
}
317+
314318
inline Environment::Environment(IsolateData* isolate_data,
315319
v8::Local<v8::Context> context)
316320
: isolate_(context->GetIsolate()),

src/env.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ v8::CpuProfiler* IsolateData::GetCpuProfiler() {
8080
return cpu_profiler_;
8181
}
8282

83+
84+
void InitThreadLocalOnce() {
85+
CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
86+
}
87+
8388
void Environment::Start(int argc,
8489
const char* const* argv,
8590
int exec_argc,
@@ -147,6 +152,10 @@ void Environment::Start(int argc,
147152

148153
SetupProcessObject(this, argc, argv, exec_argc, exec_argv);
149154
LoadAsyncWrapperInfo(this);
155+
156+
static uv_once_t init_once = UV_ONCE_INIT;
157+
uv_once(&init_once, InitThreadLocalOnce);
158+
uv_key_set(&thread_local_env, this);
150159
}
151160

152161
void Environment::CleanupHandles() {
@@ -471,4 +480,6 @@ void Environment::AsyncHooks::grow_async_ids_stack() {
471480
async_ids_stack_.GetJSArray()).FromJust();
472481
}
473482

483+
uv_key_t Environment::thread_local_env = {};
484+
474485
} // namespace node

src/env.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,9 @@ class Environment {
564564
static inline Environment* GetCurrent(
565565
const v8::PropertyCallbackInfo<T>& info);
566566

567+
static uv_key_t thread_local_env;
568+
static inline Environment* GetThreadLocalEnv();
569+
567570
inline Environment(IsolateData* isolate_data, v8::Local<v8::Context> context);
568571
inline ~Environment();
569572

src/node.cc

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4207,11 +4207,8 @@ uv_loop_t* GetCurrentEventLoop(v8::Isolate* isolate) {
42074207
}
42084208

42094209

4210-
static uv_key_t thread_local_env;
4211-
4212-
42134210
void AtExit(void (*cb)(void* arg), void* arg) {
4214-
auto env = static_cast<Environment*>(uv_key_get(&thread_local_env));
4211+
auto env = Environment::GetThreadLocalEnv();
42154212
AtExit(env, cb, arg);
42164213
}
42174214

@@ -4342,8 +4339,6 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
43424339
Local<Context> context = NewContext(isolate);
43434340
Context::Scope context_scope(context);
43444341
Environment env(isolate_data, context);
4345-
CHECK_EQ(0, uv_key_create(&thread_local_env));
4346-
uv_key_set(&thread_local_env, &env);
43474342
env.Start(argc, argv, exec_argc, exec_argv, v8_is_profiling);
43484343

43494344
const char* path = argc > 1 ? argv[1] : nullptr;
@@ -4393,7 +4388,6 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data,
43934388

43944389
const int exit_code = EmitExit(&env);
43954390
RunAtExit(&env);
4396-
uv_key_delete(&thread_local_env);
43974391

43984392
v8_platform.DrainVMTasks(isolate);
43994393
v8_platform.CancelVMTasks(isolate);

test/cctest/test_environment.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ TEST_F(EnvironmentTest, AtExitWithEnvironment) {
3333
EXPECT_TRUE(called_cb_1);
3434
}
3535

36+
TEST_F(EnvironmentTest, AtExitWithoutEnvironment) {
37+
const v8::HandleScope handle_scope(isolate_);
38+
const Argv argv;
39+
Env env {handle_scope, argv};
40+
41+
AtExit(at_exit_callback1); // No Environment is passed to AtExit.
42+
RunAtExit(*env);
43+
EXPECT_TRUE(called_cb_1);
44+
}
45+
3646
TEST_F(EnvironmentTest, AtExitWithArgument) {
3747
const v8::HandleScope handle_scope(isolate_);
3848
const Argv argv;

0 commit comments

Comments
 (0)