Skip to content

Commit

Permalink
Safe constructor for ObjectWrapped classes
Browse files Browse the repository at this point in the history
New() methods should be invoked as constructors, not regular functions.
Corner cases like Script::New() may cause a SIGSEGV when the GC is run.

More details: http://groups.google.com/group/nodejs/browse_thread/thread/a7e5db68d4cd6356
  • Loading branch information
bnoordhuis authored and ry committed Sep 29, 2010
1 parent 9911629 commit 55c65cc
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 9 deletions.
16 changes: 16 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,22 @@ Local<Value> ErrnoException(int errorno,
}


Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate>& t,
const Arguments& args) {
HandleScope scope;

const int argc = args.Length();
Local<Value> argv[argc];

for (int i = 0; i < argc; ++i) {
argv[i] = args[i];
}

Local<Object> instance = t->GetFunction()->NewInstance(argc, argv);
return scope.Close(instance);
}


enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
HandleScope scope;

Expand Down
9 changes: 9 additions & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,15 @@ ssize_t DecodeWrite(char *buf,
v8::Local<v8::Object> BuildStatsObject(struct stat * s);


/**
* Call this when your constructor is invoked as a regular function, e.g. Buffer(10) instead of new Buffer(10).
* @param constructorTemplate Constructor template to instantiate from.
* @param args The arguments object passed to your constructor.
* @see v8::Arguments::IsConstructCall
*/
v8::Handle<v8::Value> FromConstructorTemplate(v8::Persistent<v8::FunctionTemplate>& constructorTemplate, const v8::Arguments& args);


static inline v8::Persistent<v8::Function>* cb_persist(
const v8::Local<v8::Value> &v) {
v8::Persistent<v8::Function> *fn = new v8::Persistent<v8::Function>();
Expand Down
12 changes: 3 additions & 9 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,12 @@ size_t Buffer::Length(Handle<Object> obj) {


Handle<Value> Buffer::New(const Arguments &args) {
HandleScope scope;

if (!args.IsConstructCall()) {
Local<Value> argv[10];
for (int i = 0; i < MIN(args.Length(), 10); i++) {
argv[i] = args[i];
}
Local<Object> instance =
constructor_template->GetFunction()->NewInstance(args.Length(), argv);
return scope.Close(instance);
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;

Buffer *buffer;
if (args[0]->IsInt32()) {
// var buffer = new Buffer(1024);
Expand Down
4 changes: 4 additions & 0 deletions src/node_cares.cc
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,10 @@ void Channel::Initialize(Handle<Object> target) {


Handle<Value> Channel::New(const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;

struct ares_options options;
Expand Down
4 changes: 4 additions & 0 deletions src/node_idle_watcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ void IdleWatcher::Callback(EV_P_ ev_idle *w, int revents) {
// idle.start();
//
Handle<Value> IdleWatcher::New(const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;

IdleWatcher *s = new IdleWatcher();
Expand Down
4 changes: 4 additions & 0 deletions src/node_io_watcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ void IOWatcher::Callback(EV_P_ ev_io *w, int revents) {
// io.start();
//
Handle<Value> IOWatcher::New(const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;
IOWatcher *s = new IOWatcher();
s->Wrap(args.This());
Expand Down
4 changes: 4 additions & 0 deletions src/node_script.cc
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ void node::Script::Initialize (Handle<Object> target) {


Handle<Value> node::Script::New (const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;

node::Script *t = new node::Script();
Expand Down
4 changes: 4 additions & 0 deletions src/node_signal_watcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ void SignalWatcher::Callback(EV_P_ ev_signal *watcher, int revents) {
}

Handle<Value> SignalWatcher::New(const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;

if (args.Length() != 1 || !args[0]->IsInt32()) {
Expand Down
4 changes: 4 additions & 0 deletions src/node_stat_watcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ void StatWatcher::Callback(EV_P_ ev_stat *watcher, int revents) {


Handle<Value> StatWatcher::New(const Arguments& args) {
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;
StatWatcher *s = new StatWatcher();
s->Wrap(args.Holder());
Expand Down
4 changes: 4 additions & 0 deletions src/node_timer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ Timer::~Timer ()
Handle<Value>
Timer::New (const Arguments& args)
{
if (!args.IsConstructCall()) {
return FromConstructorTemplate(constructor_template, args);
}

HandleScope scope;

Timer *t = new Timer();
Expand Down

0 comments on commit 55c65cc

Please sign in to comment.