Skip to content
Permalink
Browse files

src: improve handling of internal field counting

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 authored and MylesBorins committed Feb 25, 2020
1 parent 0fc45f8 commit 4d5318c16467623770bb77f7ecac720cb93b0326
@@ -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();
@@ -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,
@@ -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,
@@ -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();
@@ -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);
}
@@ -67,7 +69,7 @@ BaseObject::~BaseObject() {

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

@@ -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));
}


@@ -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;
}

@@ -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);
@@ -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>);
@@ -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));
@@ -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);
@@ -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);
@@ -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>);
@@ -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);
@@ -145,7 +145,7 @@ MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
return MaybeLocal<Object>();
}

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

@@ -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());

@@ -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
@@ -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);
@@ -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());
}
@@ -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);
@@ -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);
@@ -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",
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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;

@@ -2198,7 +2198,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");
@@ -2211,7 +2212,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");
@@ -2226,7 +2228,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
@@ -2235,7 +2237,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);
@@ -2252,7 +2254,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 =

0 comments on commit 4d5318c

Please sign in to comment.
You can’t perform that action at this time.