src: refactor Environment::GetCurrent() usage

Make `Environment::GetCurrent()` return `nullptr` if the current
`Context` is not a Node.js context, and for the relevant usage of
this function, either:

- Switch to the better `GetCurrent(args)` variant
- Turn functions in to no-ops where it makes sense
- Make it a `CHECK`, i.e. an API requirement, where it make sense
- Leave a `TODO` comment for verifying what, if anything, is to be done

PR-URL: https://github.com/nodejs/node/pull/22819
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
This commit is contained in:
Anna Henningsen 2018-09-12 15:01:50 +02:00
parent c33e27dc3c
commit 4286dcf17f
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
15 changed files with 81 additions and 37 deletions

View File

@ -687,12 +687,16 @@ MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
return Environment::GetCurrent(isolate)->execution_async_id(); Environment* env = Environment::GetCurrent(isolate);
if (env == nullptr) return -1;
return env->execution_async_id();
} }
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) { async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
return Environment::GetCurrent(isolate)->trigger_async_id(); Environment* env = Environment::GetCurrent(isolate);
if (env == nullptr) return -1;
return env->trigger_async_id();
} }
@ -711,6 +715,7 @@ async_context EmitAsyncInit(Isolate* isolate,
v8::Local<v8::String> name, v8::Local<v8::String> name,
async_id trigger_async_id) { async_id trigger_async_id) {
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env);
// Initialize async context struct // Initialize async context struct
if (trigger_async_id == -1) if (trigger_async_id == -1)

View File

@ -67,6 +67,7 @@ void PromiseRejectCallback(PromiseRejectMessage message) {
PromiseRejectEvent event = message.GetEvent(); PromiseRejectEvent event = message.GetEvent();
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
if (env == nullptr) return;
Local<Function> callback; Local<Function> callback;
Local<Value> value; Local<Value> value;

View File

@ -43,6 +43,7 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
object_(object), object_(object),
callback_scope_(env) { callback_scope_(env) {
CHECK_IMPLIES(expect == kRequireResource, !object.IsEmpty()); CHECK_IMPLIES(expect == kRequireResource, !object.IsEmpty());
CHECK_NOT_NULL(env);
if (!env->can_call_into_js()) { if (!env->can_call_into_js()) {
failed_ = true; failed_ = true;

View File

@ -294,6 +294,15 @@ inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {
} }
inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) { inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
if (UNLIKELY(context.IsEmpty() ||
context->GetNumberOfEmbedderDataFields() <
ContextEmbedderIndex::kContextTag ||
context->GetAlignedPointerFromEmbedderData(
ContextEmbedderIndex::kContextTag) !=
Environment::kNodeContextTagPtr)) {
return nullptr;
}
return static_cast<Environment*>( return static_cast<Environment*>(
context->GetAlignedPointerFromEmbedderData( context->GetAlignedPointerFromEmbedderData(
ContextEmbedderIndex::kEnvironment)); ContextEmbedderIndex::kEnvironment));

View File

@ -491,18 +491,9 @@ void Environment::EnvPromiseHook(v8::PromiseHookType type,
v8::Local<v8::Value> parent) { v8::Local<v8::Value> parent) {
Local<v8::Context> context = promise->CreationContext(); Local<v8::Context> context = promise->CreationContext();
// Grow the embedder data if necessary to make sure we are not out of bounds
// when reading the magic number.
context->SetAlignedPointerInEmbedderData(
ContextEmbedderIndex::kContextTagBoundary, nullptr);
int* magicNumberPtr = reinterpret_cast<int*>(
context->GetAlignedPointerFromEmbedderData(
ContextEmbedderIndex::kContextTag));
if (magicNumberPtr != Environment::kNodeContextTagPtr) {
return;
}
Environment* env = Environment::GetCurrent(context); Environment* env = Environment::GetCurrent(context);
if (env == nullptr) return;
for (const PromiseHookCallback& hook : env->promise_hooks_) { for (const PromiseHookCallback& hook : env->promise_hooks_) {
hook.cb_(type, promise, parent, hook.arg_); hook.cb_(type, promise, parent, hook.arg_);
} }

View File

@ -149,12 +149,11 @@ void CallAndPauseOnStart(const FunctionCallbackInfo<v8::Value>& args) {
} }
void InspectorConsoleCall(const FunctionCallbackInfo<Value>& info) { void InspectorConsoleCall(const FunctionCallbackInfo<Value>& info) {
Isolate* isolate = info.GetIsolate(); Environment* env = Environment::GetCurrent(info);
HandleScope handle_scope(isolate); Isolate* isolate = env->isolate();
Local<Context> context = isolate->GetCurrentContext(); Local<Context> context = isolate->GetCurrentContext();
CHECK_LT(2, info.Length()); CHECK_LT(2, info.Length());
SlicedArguments call_args(info, /* start */ 3); SlicedArguments call_args(info, /* start */ 3);
Environment* env = Environment::GetCurrent(isolate);
if (InspectorEnabled(env)) { if (InspectorEnabled(env)) {
Local<Value> inspector_method = info[0]; Local<Value> inspector_method = info[0];
CHECK(inspector_method->IsFunction()); CHECK(inspector_method->IsFunction());

View File

@ -362,6 +362,7 @@ MaybeLocal<Module> ModuleWrap::ResolveCallback(Local<Context> context,
Local<String> specifier, Local<String> specifier,
Local<Module> referrer) { Local<Module> referrer) {
Environment* env = Environment::GetCurrent(context); Environment* env = Environment::GetCurrent(context);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
Isolate* isolate = env->isolate(); Isolate* isolate = env->isolate();
if (env->module_map.count(referrer->GetIdentityHash()) == 0) { if (env->module_map.count(referrer->GetIdentityHash()) == 0) {
env->ThrowError("linking error, unknown module"); env->ThrowError("linking error, unknown module");
@ -700,6 +701,7 @@ static MaybeLocal<Promise> ImportModuleDynamically(
Local<String> specifier) { Local<String> specifier) {
Isolate* iso = context->GetIsolate(); Isolate* iso = context->GetIsolate();
Environment* env = Environment::GetCurrent(context); Environment* env = Environment::GetCurrent(context);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
v8::EscapableHandleScope handle_scope(iso); v8::EscapableHandleScope handle_scope(iso);
if (env->context() != context) { if (env->context() != context) {
@ -750,8 +752,8 @@ void ModuleWrap::SetImportModuleDynamicallyCallback(
void ModuleWrap::HostInitializeImportMetaObjectCallback( void ModuleWrap::HostInitializeImportMetaObjectCallback(
Local<Context> context, Local<Module> module, Local<Object> meta) { Local<Context> context, Local<Module> module, Local<Object> meta) {
Isolate* isolate = context->GetIsolate();
Environment* env = Environment::GetCurrent(context); Environment* env = Environment::GetCurrent(context);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
ModuleWrap* module_wrap = GetFromModule(env, module); ModuleWrap* module_wrap = GetFromModule(env, module);
if (module_wrap == nullptr) { if (module_wrap == nullptr) {
@ -762,7 +764,7 @@ void ModuleWrap::HostInitializeImportMetaObjectCallback(
Local<Function> callback = Local<Function> callback =
env->host_initialize_import_meta_object_callback(); env->host_initialize_import_meta_object_callback();
Local<Value> args[] = { wrap, meta }; Local<Value> args[] = { wrap, meta };
callback->Call(context, Undefined(isolate), arraysize(args), args) callback->Call(context, Undefined(env->isolate()), arraysize(args), args)
.ToLocalChecked(); .ToLocalChecked();
} }

View File

@ -630,7 +630,8 @@ namespace {
bool ShouldAbortOnUncaughtException(Isolate* isolate) { bool ShouldAbortOnUncaughtException(Isolate* isolate) {
HandleScope scope(isolate); HandleScope scope(isolate);
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
return env->should_abort_on_uncaught_toggle()[0] && return env != nullptr &&
env->should_abort_on_uncaught_toggle()[0] &&
!env->inside_should_not_abort_on_uncaught_scope(); !env->inside_should_not_abort_on_uncaught_scope();
} }
@ -639,6 +640,7 @@ bool ShouldAbortOnUncaughtException(Isolate* isolate) {
void AddPromiseHook(Isolate* isolate, promise_hook_func fn, void* arg) { void AddPromiseHook(Isolate* isolate, promise_hook_func fn, void* arg) {
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env);
env->AddPromiseHook(fn, arg); env->AddPromiseHook(fn, arg);
} }
@ -646,6 +648,7 @@ void AddEnvironmentCleanupHook(Isolate* isolate,
void (*fun)(void* arg), void (*fun)(void* arg),
void* arg) { void* arg) {
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env);
env->AddCleanupHook(fun, arg); env->AddCleanupHook(fun, arg);
} }
@ -654,6 +657,7 @@ void RemoveEnvironmentCleanupHook(Isolate* isolate,
void (*fun)(void* arg), void (*fun)(void* arg),
void* arg) { void* arg) {
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env);
env->RemoveCleanupHook(fun, arg); env->RemoveCleanupHook(fun, arg);
} }
@ -738,6 +742,7 @@ MaybeLocal<Value> MakeCallback(Isolate* isolate,
// Because of the AssignToContext() call in src/node_contextify.cc, // Because of the AssignToContext() call in src/node_contextify.cc,
// the two contexts need not be the same. // the two contexts need not be the same.
Environment* env = Environment::GetCurrent(callback->CreationContext()); Environment* env = Environment::GetCurrent(callback->CreationContext());
CHECK_NOT_NULL(env);
Context::Scope context_scope(env->context()); Context::Scope context_scope(env->context());
MaybeLocal<Value> ret = InternalMakeCallback(env, recv, callback, MaybeLocal<Value> ret = InternalMakeCallback(env, recv, callback,
argc, argv, asyncContext); argc, argv, asyncContext);
@ -1377,6 +1382,7 @@ void FatalException(Isolate* isolate,
HandleScope scope(isolate); HandleScope scope(isolate);
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
Local<Object> process_object = env->process_object(); Local<Object> process_object = env->process_object();
Local<String> fatal_exception_string = env->fatal_exception_string(); Local<String> fatal_exception_string = env->fatal_exception_string();
Local<Value> fatal_exception_function = Local<Value> fatal_exception_function =
@ -1602,7 +1608,7 @@ static void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
} }
static void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) { static void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsString()); CHECK(args[0]->IsString());
@ -2706,10 +2712,13 @@ void RunAtExit(Environment* env) {
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) { uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
auto context = isolate->GetCurrentContext(); Local<Context> context = isolate->GetCurrentContext();
if (context.IsEmpty()) if (context.IsEmpty())
return nullptr; return nullptr;
return Environment::GetCurrent(context)->event_loop(); Environment* env = Environment::GetCurrent(context);
if (env == nullptr)
return nullptr;
return env->event_loop();
} }

View File

@ -946,7 +946,7 @@ class ThreadSafeFunction : public node::AsyncResource {
return napi_ok; return napi_ok;
} }
node::Environment::GetCurrent(env->isolate)->CloseHandle( NodeEnv()->CloseHandle(
reinterpret_cast<uv_handle_t*>(&async), reinterpret_cast<uv_handle_t*>(&async),
[](uv_handle_t* handle) -> void { [](uv_handle_t* handle) -> void {
ThreadSafeFunction* ts_fn = ThreadSafeFunction* ts_fn =
@ -1036,9 +1036,12 @@ class ThreadSafeFunction : public node::AsyncResource {
} }
node::Environment* NodeEnv() { node::Environment* NodeEnv() {
// For some reason grabbing the Node.js environment requires a handle scope. // Grabbing the Node.js environment requires a handle scope because it
// looks up fields on the current context.
v8::HandleScope scope(env->isolate); v8::HandleScope scope(env->isolate);
return node::Environment::GetCurrent(env->isolate); node::Environment* node_env = node::Environment::GetCurrent(env->isolate);
CHECK_NOT_NULL(node_env);
return node_env;
} }
void MaybeStartIdle() { void MaybeStartIdle() {
@ -1234,7 +1237,9 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
v8::Local<v8::Context> context, v8::Local<v8::Context> context,
napi_addon_register_func init) { napi_addon_register_func init) {
if (init == nullptr) { if (init == nullptr) {
node::Environment::GetCurrent(context)->ThrowError( node::Environment* node_env = node::Environment::GetCurrent(context);
CHECK_NOT_NULL(node_env);
node_env->ThrowError(
"Module has no declared entry point."); "Module has no declared entry point.");
return; return;
} }

View File

@ -274,7 +274,9 @@ MaybeLocal<Object> New(Isolate* isolate,
MaybeLocal<Object> New(Isolate* isolate, size_t length) { MaybeLocal<Object> New(Isolate* isolate, size_t length) {
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Local<Object> obj; Local<Object> obj;
if (Buffer::New(Environment::GetCurrent(isolate), length).ToLocal(&obj)) Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
if (Buffer::New(env, length).ToLocal(&obj))
return handle_scope.Escape(obj); return handle_scope.Escape(obj);
return Local<Object>(); return Local<Object>();
} }
@ -316,6 +318,7 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) { MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
Local<Object> obj; Local<Object> obj;
if (Buffer::Copy(env, data, length).ToLocal(&obj)) if (Buffer::Copy(env, data, length).ToLocal(&obj))
return handle_scope.Escape(obj); return handle_scope.Escape(obj);
@ -365,6 +368,7 @@ MaybeLocal<Object> New(Isolate* isolate,
void* hint) { void* hint) {
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
Local<Object> obj; Local<Object> obj;
if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj)) if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
return handle_scope.Escape(obj); return handle_scope.Escape(obj);
@ -403,6 +407,7 @@ MaybeLocal<Object> New(Environment* env,
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) { MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
EscapableHandleScope handle_scope(isolate); EscapableHandleScope handle_scope(isolate);
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here.
Local<Object> obj; Local<Object> obj;
if (Buffer::New(env, data, length).ToLocal(&obj)) if (Buffer::New(env, data, length).ToLocal(&obj))
return handle_scope.Escape(obj); return handle_scope.Escape(obj);

View File

@ -25,16 +25,11 @@ namespace node {
#define NODE_CONTEXT_TAG 35 #define NODE_CONTEXT_TAG 35
#endif #endif
#ifndef NODE_CONTEXT_TAG_BOUNDARY
#define NODE_CONTEXT_TAG_BOUNDARY 36
#endif
enum ContextEmbedderIndex { enum ContextEmbedderIndex {
kEnvironment = NODE_CONTEXT_EMBEDDER_DATA_INDEX, kEnvironment = NODE_CONTEXT_EMBEDDER_DATA_INDEX,
kSandboxObject = NODE_CONTEXT_SANDBOX_OBJECT_INDEX, kSandboxObject = NODE_CONTEXT_SANDBOX_OBJECT_INDEX,
kAllowWasmCodeGeneration = NODE_CONTEXT_ALLOW_WASM_CODE_GENERATION_INDEX, kAllowWasmCodeGeneration = NODE_CONTEXT_ALLOW_WASM_CODE_GENERATION_INDEX,
kContextTag = NODE_CONTEXT_TAG, kContextTag = NODE_CONTEXT_TAG,
kContextTagBoundary = NODE_CONTEXT_TAG_BOUNDARY,
}; };
} // namespace node } // namespace node

View File

@ -441,7 +441,7 @@ void FSReqCallback::SetReturnValue(const FunctionCallbackInfo<Value>& args) {
void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) { void NewFSReqCallback(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall()); CHECK(args.IsConstructCall());
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args);
new FSReqCallback(env, args.This(), args[0]->IsTrue()); new FSReqCallback(env, args.This(), args[0]->IsTrue());
} }
@ -782,7 +782,7 @@ inline FSReqBase* GetReqWrap(Environment* env, Local<Value> value,
} }
void Access(const FunctionCallbackInfo<Value>& args) { void Access(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args);
HandleScope scope(env->isolate()); HandleScope scope(env->isolate());
const int argc = args.Length(); const int argc = args.Length();
@ -2234,8 +2234,7 @@ void Initialize(Local<Object> target,
StatWatcher::Initialize(env, target); StatWatcher::Initialize(env, target);
// Create FunctionTemplate for FSReqCallback // Create FunctionTemplate for FSReqCallback
Local<FunctionTemplate> fst = Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
FunctionTemplate::New(env->isolate(), NewFSReqCallback);
fst->InstanceTemplate()->SetInternalFieldCount(1); fst->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, fst); AsyncWrap::AddWrapMethods(env, fst);
Local<String> wrapString = Local<String> wrapString =

View File

@ -501,7 +501,9 @@ class InternalCallbackScope {
class ThreadPoolWork { class ThreadPoolWork {
public: public:
explicit inline ThreadPoolWork(Environment* env) : env_(env) {} explicit inline ThreadPoolWork(Environment* env) : env_(env) {
CHECK_NOT_NULL(env);
}
inline virtual ~ThreadPoolWork() = default; inline virtual ~ThreadPoolWork() = default;
inline void ScheduleWork(); inline void ScheduleWork();

View File

@ -310,6 +310,7 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate(); Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate); HandleScope scope(isolate);
Environment* env = Environment::GetCurrent(isolate); Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env); // TODO(addaleax): Verify that this is correct.
Local<Context> context = env->context(); Local<Context> context = env->context();
Local<Function> fn = args.Data().As<Function>(); Local<Function> fn = args.Data().As<Function>();
size_t count = args.Length(); size_t count = args.Length();

View File

@ -70,6 +70,26 @@ TEST_F(EnvironmentTest, MultipleEnvironmentsPerIsolate) {
EXPECT_TRUE(called_cb_2); EXPECT_TRUE(called_cb_2);
} }
TEST_F(EnvironmentTest, NonNodeJSContext) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
Env test_env {handle_scope, argv};
EXPECT_EQ(node::Environment::GetCurrent(v8::Local<v8::Context>()), nullptr);
node::Environment* env = *test_env;
EXPECT_EQ(node::Environment::GetCurrent(isolate_), env);
EXPECT_EQ(node::Environment::GetCurrent(env->context()), env);
v8::Local<v8::Context> context = v8::Context::New(isolate_);
EXPECT_EQ(node::Environment::GetCurrent(context), nullptr);
EXPECT_EQ(node::Environment::GetCurrent(isolate_), env);
v8::Context::Scope context_scope(context);
EXPECT_EQ(node::Environment::GetCurrent(context), nullptr);
EXPECT_EQ(node::Environment::GetCurrent(isolate_), nullptr);
}
static void at_exit_callback1(void* arg) { static void at_exit_callback1(void* arg) {
called_cb_1 = true; called_cb_1 = true;
if (arg) { if (arg) {