Skip to content

Commit

Permalink
async-wrap: ensure all objects have internal field
Browse files Browse the repository at this point in the history
If the constructor can't assign a class id then the heap snapshot will
not be able to report the object. So ensure that all AsyncWrap instances
use a FunctionTemplate instance with an internal field count >= 1.
  • Loading branch information
trevnorris committed Sep 30, 2015
1 parent 71dc4c8 commit 66b2890
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 12 deletions.
12 changes: 6 additions & 6 deletions lib/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const uv = process.binding('uv');

const GetAddrInfoReqWrap = cares.GetAddrInfoReqWrap;
const GetNameInfoReqWrap = cares.GetNameInfoReqWrap;
const QueryReqWrap = cares.QueryReqWrap;

const isIp = net.isIP;

Expand Down Expand Up @@ -223,12 +224,11 @@ function resolver(bindingName) {
}

callback = makeAsync(callback);
var req = {
bindingName: bindingName,
callback: callback,
hostname: name,
oncomplete: onresolve
};
var req = new QueryReqWrap();
req.bindingName = bindingName;
req.callback = callback;
req.hostname = name;
req.oncomplete = onresolve;
var err = binding(req, name);
if (err) throw errnoException(err, bindingName);
callback.immediately = true;
Expand Down
9 changes: 5 additions & 4 deletions src/async-wrap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ inline AsyncWrap::AsyncWrap(Environment* env,
ProviderType provider,
AsyncWrap* parent)
: BaseObject(env, object), bits_(static_cast<uint32_t>(provider) << 1) {
// Only set wrapper class id if object will be Wrap'd.
if (object->InternalFieldCount() > 0)
// Shift provider value over to prevent id collision.
persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider);
CHECK_NE(provider, PROVIDER_NONE);
CHECK_GE(object->InternalFieldCount(), 1);

// Shift provider value over to prevent id collision.
persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider);

// Check user controlled flag to see if the init callback should run.
if (!env->using_asyncwrap())
Expand Down
13 changes: 13 additions & 0 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ static void NewGetNameInfoReqWrap(const FunctionCallbackInfo<Value>& args) {
}


static void NewQueryReqWrap(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
}


static int cmp_ares_tasks(const ares_task_t* a, const ares_task_t* b) {
if (a->sock < b->sock)
return -1;
Expand Down Expand Up @@ -1312,6 +1317,14 @@ static void Initialize(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"),
niw->GetFunction());

Local<FunctionTemplate> qrw =
FunctionTemplate::New(env->isolate(), NewQueryReqWrap);
qrw->InstanceTemplate()->SetInternalFieldCount(1);
qrw->SetClassName(
FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"));
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"),
qrw->GetFunction());
}

} // namespace cares_wrap
Expand Down
13 changes: 13 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ inline Environment::Environment(v8::Local<v8::Context> context,
set_as_external(v8::External::New(isolate(), this));
set_binding_cache_object(v8::Object::New(isolate()));
set_module_load_list_array(v8::Array::New(isolate()));

v8::Local<v8::FunctionTemplate> fn_t = v8::FunctionTemplate::New(isolate());
fn_t->SetClassName(FIXED_ONE_BYTE_STRING(isolate(), "InternalFieldObject"));
v8::Local<v8::ObjectTemplate> obj_t = fn_t->InstanceTemplate();
obj_t->SetInternalFieldCount(1);
set_generic_internal_field_template(obj_t);

RB_INIT(&cares_task_list_);
handle_cleanup_waiting_ = 0;
}
Expand Down Expand Up @@ -513,6 +520,12 @@ inline void Environment::SetTemplateMethod(v8::Local<v8::FunctionTemplate> that,
function->SetName(name_string); // NODE_SET_METHOD() compatibility.
}

inline v8::Local<v8::Object> Environment::NewInternalFieldObject() {
v8::MaybeLocal<v8::Object> m_obj =
generic_internal_field_template()->NewInstance(this->context());
return m_obj.ToLocalChecked();
}

#define V(PropertyName, StringValue) \
inline \
v8::Local<v8::String> Environment::IsolateData::PropertyName() const { \
Expand Down
2 changes: 2 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ namespace node {
V(context, v8::Context) \
V(domain_array, v8::Array) \
V(fs_stats_constructor_function, v8::Function) \
V(generic_internal_field_template, v8::ObjectTemplate) \
V(jsstream_constructor_template, v8::FunctionTemplate) \
V(module_load_list_array, v8::Array) \
V(pipe_constructor_template, v8::FunctionTemplate) \
Expand Down Expand Up @@ -488,6 +489,7 @@ class Environment {
const char* name,
v8::FunctionCallback callback);

inline v8::Local<v8::Object> NewInternalFieldObject();

// Strings are shared across shared contexts. The getters simply proxy to
// the per-isolate primitive.
Expand Down
6 changes: 4 additions & 2 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4624,6 +4624,7 @@ class PBKDF2Request : public AsyncWrap {
iter_(iter) {
if (key() == nullptr)
FatalError("node::PBKDF2Request()", "Out of Memory");
Wrap(object, this);
}

~PBKDF2Request() override {
Expand Down Expand Up @@ -4833,7 +4834,7 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
digest = EVP_sha1();
}

obj = Object::New(env->isolate());
obj = env->NewInternalFieldObject();
req = new PBKDF2Request(env,
obj,
digest,
Expand Down Expand Up @@ -4885,6 +4886,7 @@ class RandomBytesRequest : public AsyncWrap {
data_(static_cast<char*>(malloc(size))) {
if (data() == nullptr)
FatalError("node::RandomBytesRequest()", "Out of Memory");
Wrap(object, this);
}

~RandomBytesRequest() override {
Expand Down Expand Up @@ -5001,7 +5003,7 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
if (size < 0 || size > Buffer::kMaxLength)
return env->ThrowRangeError("size is not a valid Smi");

Local<Object> obj = Object::New(env->isolate());
Local<Object> obj = env->NewInternalFieldObject();
RandomBytesRequest* req = new RandomBytesRequest(env, obj, size);

if (args[1]->IsFunction()) {
Expand Down

0 comments on commit 66b2890

Please sign in to comment.