Skip to content

Commit

Permalink
src: improve handling of internal field counting
Browse files Browse the repository at this point in the history
Change suggested by bnoordhuis.

Improve handing of internal field counting by using enums.
Helps protect against future possible breakage if field
indexes are ever changed or added to.

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: #31960
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
jasnell committed Mar 2, 2020
1 parent 68e36ad commit 0fac393
Show file tree
Hide file tree
Showing 40 changed files with 151 additions and 92 deletions.
22 changes: 12 additions & 10 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ void AsyncWrap::EmitAfter(Environment* env, double async_id) {

class PromiseWrap : public AsyncWrap {
public:
enum InternalFields {
kIsChainedPromiseField = AsyncWrap::kInternalFieldCount,
kInternalFieldCount
};
PromiseWrap(Environment* env, Local<Object> object, bool silent)
: AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) {
MakeWeak();
Expand All @@ -185,9 +189,6 @@ class PromiseWrap : public AsyncWrap {
SET_MEMORY_INFO_NAME(PromiseWrap)
SET_SELF_SIZE(PromiseWrap)

static constexpr int kIsChainedPromiseField = 1;
static constexpr int kInternalFieldCount = 2;

static PromiseWrap* New(Environment* env,
Local<Promise> promise,
PromiseWrap* parent_wrap,
Expand All @@ -214,15 +215,16 @@ PromiseWrap* PromiseWrap::New(Environment* env,
void PromiseWrap::getIsChainedPromise(Local<String> property,
const PropertyCallbackInfo<Value>& info) {
info.GetReturnValue().Set(
info.Holder()->GetInternalField(kIsChainedPromiseField));
info.Holder()->GetInternalField(PromiseWrap::kIsChainedPromiseField));
}

static PromiseWrap* extractPromiseWrap(Local<Promise> promise) {
Local<Value> resource_object_value = promise->GetInternalField(0);
if (resource_object_value->IsObject()) {
return Unwrap<PromiseWrap>(resource_object_value.As<Object>());
}
return nullptr;
// This check is imperfect. If the internal field is set, it should
// be an object. If it's not, we just ignore it. Ideally v8 would
// have had GetInternalField returning a MaybeLocal but this works
// for now.
Local<Value> obj = promise->GetInternalField(0);
return obj->IsObject() ? Unwrap<PromiseWrap>(obj.As<Object>()) : nullptr;
}

static void PromiseHook(PromiseHookType type, Local<Promise> promise,
Expand Down Expand Up @@ -560,7 +562,7 @@ void AsyncWrap::Initialize(Local<Object> target,
function_template->SetClassName(class_name);
function_template->Inherit(AsyncWrap::GetConstructorTemplate(env));
auto instance_template = function_template->InstanceTemplate();
instance_template->SetInternalFieldCount(1);
instance_template->SetInternalFieldCount(AsyncWrap::kInternalFieldCount);
auto function =
function_template->GetFunction(env->context()).ToLocalChecked();
target->Set(env->context(), class_name, function).Check();
Expand Down
14 changes: 9 additions & 5 deletions src/base_object-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> object)
: persistent_handle_(env->isolate(), object), env_(env) {
CHECK_EQ(false, object.IsEmpty());
CHECK_GT(object->InternalFieldCount(), 0);
object->SetAlignedPointerInInternalField(0, static_cast<void*>(this));
object->SetAlignedPointerInInternalField(
BaseObject::kSlot,
static_cast<void*>(this));
env->AddCleanupHook(DeleteMe, static_cast<void*>(this));
env->modify_base_object_count(1);
}
Expand All @@ -67,7 +69,7 @@ BaseObject::~BaseObject() {

{
v8::HandleScope handle_scope(env()->isolate());
object()->SetAlignedPointerInInternalField(0, nullptr);
object()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr);
}
}

Expand Down Expand Up @@ -100,7 +102,8 @@ Environment* BaseObject::env() const {

BaseObject* BaseObject::FromJSObject(v8::Local<v8::Object> obj) {
CHECK_GT(obj->InternalFieldCount(), 0);
return static_cast<BaseObject*>(obj->GetAlignedPointerFromInternalField(0));
return static_cast<BaseObject*>(
obj->GetAlignedPointerFromInternalField(BaseObject::kSlot));
}


Expand Down Expand Up @@ -148,11 +151,12 @@ BaseObject::MakeLazilyInitializedJSTemplate(Environment* env) {
auto constructor = [](const v8::FunctionCallbackInfo<v8::Value>& args) {
DCHECK(args.IsConstructCall());
DCHECK_GT(args.This()->InternalFieldCount(), 0);
args.This()->SetAlignedPointerInInternalField(0, nullptr);
args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr);
};

v8::Local<v8::FunctionTemplate> t = env->NewFunctionTemplate(constructor);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
BaseObject::kInternalFieldCount);
return t;
}

Expand Down
2 changes: 2 additions & 0 deletions src/base_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BaseObjectPtrImpl;

class BaseObject : public MemoryRetainer {
public:
enum InternalFields { kSlot, kInternalFieldCount };

// Associates this object with `object`. It uses the 0th internal field for
// that, and in particular aborts if there is no such field.
inline BaseObject(Environment* env, v8::Local<v8::Object> object);
Expand Down
3 changes: 2 additions & 1 deletion src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2223,7 +2223,8 @@ void Initialize(Local<Object> target,

Local<FunctionTemplate> channel_wrap =
env->NewFunctionTemplate(ChannelWrap::New);
channel_wrap->InstanceTemplate()->SetInternalFieldCount(1);
channel_wrap->InstanceTemplate()->SetInternalFieldCount(
ChannelWrap::kInternalFieldCount);
channel_wrap->Inherit(AsyncWrap::GetConstructorTemplate(env));

env->SetProtoMethod(channel_wrap, "queryAny", Query<QueryAnyWrap>);
Expand Down
3 changes: 2 additions & 1 deletion src/fs_event_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ void FSEventWrap::Initialize(Local<Object> target,

auto fsevent_string = FIXED_ONE_BYTE_STRING(env->isolate(), "FSEvent");
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
FSEventWrap::kInternalFieldCount);
t->SetClassName(fsevent_string);

t->Inherit(AsyncWrap::GetConstructorTemplate(env));
Expand Down
2 changes: 1 addition & 1 deletion src/heap_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ BaseObjectPtr<AsyncWrap> CreateHeapSnapshotStream(
Local<FunctionTemplate> os = FunctionTemplate::New(env->isolate());
os->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<ObjectTemplate> ost = os->InstanceTemplate();
ost->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
ost->SetInternalFieldCount(StreamBase::kInternalFieldCount);
os->SetClassName(
FIXED_ONE_BYTE_STRING(env->isolate(), "HeapSnapshotStream"));
StreamBase::AddMethods(env, os);
Expand Down
3 changes: 2 additions & 1 deletion src/inspector_js_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ class JSBindingsConnection : public AsyncWrap {
Local<String> class_name = ConnectionType::GetClassName(env);
Local<FunctionTemplate> tmpl =
env->NewFunctionTemplate(JSBindingsConnection::New);
tmpl->InstanceTemplate()->SetInternalFieldCount(1);
tmpl->InstanceTemplate()->SetInternalFieldCount(
JSBindingsConnection::kInternalFieldCount);
tmpl->SetClassName(class_name);
tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
env->SetProtoMethod(tmpl, "dispatch", JSBindingsConnection::Dispatch);
Expand Down
2 changes: 1 addition & 1 deletion src/js_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ void JSStream::Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "JSStream");
t->SetClassName(jsStreamString);
t->InstanceTemplate()
->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
->SetInternalFieldCount(StreamBase::kInternalFieldCount);
t->Inherit(AsyncWrap::GetConstructorTemplate(env));

env->SetProtoMethod(t, "finishWrite", Finish<WriteWrap>);
Expand Down
3 changes: 2 additions & 1 deletion src/module_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1636,7 +1636,8 @@ void ModuleWrap::Initialize(Local<Object> target,

Local<FunctionTemplate> tpl = env->NewFunctionTemplate(New);
tpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->InstanceTemplate()->SetInternalFieldCount(
ModuleWrap::kInternalFieldCount);

env->SetProtoMethod(tpl, "link", Link);
env->SetProtoMethod(tpl, "instantiate", Instantiate);
Expand Down
14 changes: 9 additions & 5 deletions src/node_contextify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
return MaybeLocal<Object>();
}

wrapper->SetAlignedPointerInInternalField(0, this);
wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
return wrapper;
}

Expand Down Expand Up @@ -232,7 +232,8 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
void ContextifyContext::Init(Environment* env, Local<Object> target) {
Local<FunctionTemplate> function_template =
FunctionTemplate::New(env->isolate());
function_template->InstanceTemplate()->SetInternalFieldCount(1);
function_template->InstanceTemplate()->SetInternalFieldCount(
ContextifyContext::kInternalFieldCount);
env->set_script_data_constructor_function(
function_template->GetFunction(env->context()).ToLocalChecked());

Expand Down Expand Up @@ -331,7 +332,8 @@ template <typename T>
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
Local<Value> data = args.Data();
return static_cast<ContextifyContext*>(
data.As<Object>()->GetAlignedPointerFromInternalField(0));
data.As<Object>()->GetAlignedPointerFromInternalField(
ContextifyContext::kSlot));
}

// static
Expand Down Expand Up @@ -628,7 +630,8 @@ void ContextifyScript::Init(Environment* env, Local<Object> target) {
FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");

Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
script_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
script_tmpl->InstanceTemplate()->SetInternalFieldCount(
ContextifyScript::kInternalFieldCount);
script_tmpl->SetClassName(class_name);
env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
Expand Down Expand Up @@ -1251,7 +1254,8 @@ void Initialize(Local<Object> target,
{
Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
tpl->InstanceTemplate()->SetInternalFieldCount(
CompiledFnEntry::kInternalFieldCount);

env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
}
Expand Down
1 change: 1 addition & 0 deletions src/node_contextify.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct ContextOptions {

class ContextifyContext {
public:
enum InternalFields { kSlot, kInternalFieldCount };
ContextifyContext(Environment* env,
v8::Local<v8::Object> sandbox_obj,
const ContextOptions& options);
Expand Down
26 changes: 17 additions & 9 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ static T* MallocOpenSSL(size_t count) {

void SecureContext::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
SecureContext::kInternalFieldCount);
Local<String> secureContextString =
FIXED_ONE_BYTE_STRING(env->isolate(), "SecureContext");
t->SetClassName(secureContextString);
Expand Down Expand Up @@ -3803,7 +3804,8 @@ EVP_PKEY* ManagedEVPPKey::get() const {

Local<Function> KeyObject::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
KeyObject::kInternalFieldCount);

env->SetProtoMethod(t, "init", Init);
env->SetProtoMethodNoSideEffect(t, "getSymmetricKeySize",
Expand Down Expand Up @@ -4036,7 +4038,8 @@ CipherBase::CipherBase(Environment* env,
void CipherBase::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
CipherBase::kInternalFieldCount);

env->SetProtoMethod(t, "init", Init);
env->SetProtoMethod(t, "initiv", InitIv);
Expand Down Expand Up @@ -4663,7 +4666,8 @@ Hmac::Hmac(Environment* env, v8::Local<v8::Object> wrap)
void Hmac::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
Hmac::kInternalFieldCount);

env->SetProtoMethod(t, "init", HmacInit);
env->SetProtoMethod(t, "update", HmacUpdate);
Expand Down Expand Up @@ -4789,7 +4793,8 @@ Hash::Hash(Environment* env, v8::Local<v8::Object> wrap)
void Hash::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
Hash::kInternalFieldCount);

env->SetProtoMethod(t, "update", HashUpdate);
env->SetProtoMethod(t, "digest", HashDigest);
Expand Down Expand Up @@ -5061,7 +5066,8 @@ Sign::Sign(Environment* env, v8::Local<v8::Object> wrap) : SignBase(env, wrap) {
void Sign::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
SignBase::kInternalFieldCount);

env->SetProtoMethod(t, "init", SignInit);
env->SetProtoMethod(t, "update", SignUpdate);
Expand Down Expand Up @@ -5385,7 +5391,8 @@ Verify::Verify(Environment* env, v8::Local<v8::Object> wrap) :
void Verify::Initialize(Environment* env, Local<Object> target) {
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
SignBase::kInternalFieldCount);

env->SetProtoMethod(t, "init", VerifyInit);
env->SetProtoMethod(t, "update", VerifyUpdate);
Expand Down Expand Up @@ -5697,7 +5704,8 @@ void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
const PropertyAttribute attributes =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(
DiffieHellman::kInternalFieldCount);

env->SetProtoMethod(t, "generateKeys", GenerateKeys);
env->SetProtoMethod(t, "computeSecret", ComputeSecret);
Expand Down Expand Up @@ -6036,7 +6044,7 @@ void ECDH::Initialize(Environment* env, Local<Object> target) {

Local<FunctionTemplate> t = env->NewFunctionTemplate(New);

t->InstanceTemplate()->SetInternalFieldCount(1);
t->InstanceTemplate()->SetInternalFieldCount(ECDH::kInternalFieldCount);

env->SetProtoMethod(t, "generateKeys", GenerateKeys);
env->SetProtoMethod(t, "computeSecret", ComputeSecret);
Expand Down
2 changes: 1 addition & 1 deletion src/node_dir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ void Initialize(Local<Object> target,
env->SetProtoMethod(dir, "read", DirHandle::Read);
env->SetProtoMethod(dir, "close", DirHandle::Close);
Local<ObjectTemplate> dirt = dir->InstanceTemplate();
dirt->SetInternalFieldCount(DirHandle::kDirHandleFieldCount);
dirt->SetInternalFieldCount(DirHandle::kInternalFieldCount);
Local<String> handleString =
FIXED_ONE_BYTE_STRING(isolate, "DirHandle");
dir->SetClassName(handleString);
Expand Down
2 changes: 0 additions & 2 deletions src/node_dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ namespace fs_dir {
// Needed to propagate `uv_dir_t`.
class DirHandle : public AsyncWrap {
public:
static constexpr int kDirHandleFieldCount = 1;

static DirHandle* New(Environment* env, uv_dir_t* dir);
~DirHandle() override;

Expand Down
12 changes: 7 additions & 5 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2290,7 +2290,8 @@ void Initialize(Local<Object> target,

// Create FunctionTemplate for FSReqCallback
Local<FunctionTemplate> fst = env->NewFunctionTemplate(NewFSReqCallback);
fst->InstanceTemplate()->SetInternalFieldCount(1);
fst->InstanceTemplate()->SetInternalFieldCount(
FSReqBase::kInternalFieldCount);
fst->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> wrapString =
FIXED_ONE_BYTE_STRING(isolate, "FSReqCallback");
Expand All @@ -2303,7 +2304,8 @@ void Initialize(Local<Object> target,
// Create FunctionTemplate for FileHandleReadWrap. There’s no need
// to do anything in the constructor, so we only store the instance template.
Local<FunctionTemplate> fh_rw = FunctionTemplate::New(isolate);
fh_rw->InstanceTemplate()->SetInternalFieldCount(1);
fh_rw->InstanceTemplate()->SetInternalFieldCount(
FSReqBase::kInternalFieldCount);
fh_rw->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<String> fhWrapString =
FIXED_ONE_BYTE_STRING(isolate, "FileHandleReqWrap");
Expand All @@ -2318,7 +2320,7 @@ void Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(isolate, "FSReqPromise");
fpt->SetClassName(promiseString);
Local<ObjectTemplate> fpo = fpt->InstanceTemplate();
fpo->SetInternalFieldCount(1);
fpo->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
env->set_fsreqpromise_constructor_template(fpo);

// Create FunctionTemplate for FileHandle
Expand All @@ -2327,7 +2329,7 @@ void Initialize(Local<Object> target,
env->SetProtoMethod(fd, "close", FileHandle::Close);
env->SetProtoMethod(fd, "releaseFD", FileHandle::ReleaseFD);
Local<ObjectTemplate> fdt = fd->InstanceTemplate();
fdt->SetInternalFieldCount(StreamBase::kStreamBaseFieldCount);
fdt->SetInternalFieldCount(StreamBase::kInternalFieldCount);
Local<String> handleString =
FIXED_ONE_BYTE_STRING(isolate, "FileHandle");
fd->SetClassName(handleString);
Expand All @@ -2344,7 +2346,7 @@ void Initialize(Local<Object> target,
"FileHandleCloseReq"));
fdclose->Inherit(AsyncWrap::GetConstructorTemplate(env));
Local<ObjectTemplate> fdcloset = fdclose->InstanceTemplate();
fdcloset->SetInternalFieldCount(1);
fdcloset->SetInternalFieldCount(FSReqBase::kInternalFieldCount);
env->set_fdclose_constructor_template(fdcloset);

Local<Symbol> use_promises_symbol =
Expand Down
Loading

0 comments on commit 0fac393

Please sign in to comment.