Skip to content

Commit 55c65cc

Browse files
bnoordhuisry
authored andcommitted
Safe constructor for ObjectWrapped classes
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
1 parent 9911629 commit 55c65cc

10 files changed

Lines changed: 56 additions & 9 deletions

src/node.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,22 @@ Local<Value> ErrnoException(int errorno,
787787
}
788788

789789

790+
Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate>& t,
791+
const Arguments& args) {
792+
HandleScope scope;
793+
794+
const int argc = args.Length();
795+
Local<Value> argv[argc];
796+
797+
for (int i = 0; i < argc; ++i) {
798+
argv[i] = args[i];
799+
}
800+
801+
Local<Object> instance = t->GetFunction()->NewInstance(argc, argv);
802+
return scope.Close(instance);
803+
}
804+
805+
790806
enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
791807
HandleScope scope;
792808

src/node.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ ssize_t DecodeWrite(char *buf,
6565
v8::Local<v8::Object> BuildStatsObject(struct stat * s);
6666

6767

68+
/**
69+
* Call this when your constructor is invoked as a regular function, e.g. Buffer(10) instead of new Buffer(10).
70+
* @param constructorTemplate Constructor template to instantiate from.
71+
* @param args The arguments object passed to your constructor.
72+
* @see v8::Arguments::IsConstructCall
73+
*/
74+
v8::Handle<v8::Value> FromConstructorTemplate(v8::Persistent<v8::FunctionTemplate>& constructorTemplate, const v8::Arguments& args);
75+
76+
6877
static inline v8::Persistent<v8::Function>* cb_persist(
6978
const v8::Local<v8::Value> &v) {
7079
v8::Persistent<v8::Function> *fn = new v8::Persistent<v8::Function>();

src/node_buffer.cc

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,12 @@ size_t Buffer::Length(Handle<Object> obj) {
127127

128128

129129
Handle<Value> Buffer::New(const Arguments &args) {
130-
HandleScope scope;
131-
132130
if (!args.IsConstructCall()) {
133-
Local<Value> argv[10];
134-
for (int i = 0; i < MIN(args.Length(), 10); i++) {
135-
argv[i] = args[i];
136-
}
137-
Local<Object> instance =
138-
constructor_template->GetFunction()->NewInstance(args.Length(), argv);
139-
return scope.Close(instance);
131+
return FromConstructorTemplate(constructor_template, args);
140132
}
141133

134+
HandleScope scope;
135+
142136
Buffer *buffer;
143137
if (args[0]->IsInt32()) {
144138
// var buffer = new Buffer(1024);

src/node_cares.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,10 @@ void Channel::Initialize(Handle<Object> target) {
459459

460460

461461
Handle<Value> Channel::New(const Arguments& args) {
462+
if (!args.IsConstructCall()) {
463+
return FromConstructorTemplate(constructor_template, args);
464+
}
465+
462466
HandleScope scope;
463467

464468
struct ares_options options;

src/node_idle_watcher.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ void IdleWatcher::Callback(EV_P_ ev_idle *w, int revents) {
7777
// idle.start();
7878
//
7979
Handle<Value> IdleWatcher::New(const Arguments& args) {
80+
if (!args.IsConstructCall()) {
81+
return FromConstructorTemplate(constructor_template, args);
82+
}
83+
8084
HandleScope scope;
8185

8286
IdleWatcher *s = new IdleWatcher();

src/node_io_watcher.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ void IOWatcher::Callback(EV_P_ ev_io *w, int revents) {
6868
// io.start();
6969
//
7070
Handle<Value> IOWatcher::New(const Arguments& args) {
71+
if (!args.IsConstructCall()) {
72+
return FromConstructorTemplate(constructor_template, args);
73+
}
74+
7175
HandleScope scope;
7276
IOWatcher *s = new IOWatcher();
7377
s->Wrap(args.This());

src/node_script.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ void node::Script::Initialize (Handle<Object> target) {
7878

7979

8080
Handle<Value> node::Script::New (const Arguments& args) {
81+
if (!args.IsConstructCall()) {
82+
return FromConstructorTemplate(constructor_template, args);
83+
}
84+
8185
HandleScope scope;
8286

8387
node::Script *t = new node::Script();

src/node_signal_watcher.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ void SignalWatcher::Callback(EV_P_ ev_signal *watcher, int revents) {
5151
}
5252

5353
Handle<Value> SignalWatcher::New(const Arguments& args) {
54+
if (!args.IsConstructCall()) {
55+
return FromConstructorTemplate(constructor_template, args);
56+
}
57+
5458
HandleScope scope;
5559

5660
if (args.Length() != 1 || !args[0]->IsInt32()) {

src/node_stat_watcher.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ void StatWatcher::Callback(EV_P_ ev_stat *watcher, int revents) {
4646

4747

4848
Handle<Value> StatWatcher::New(const Arguments& args) {
49+
if (!args.IsConstructCall()) {
50+
return FromConstructorTemplate(constructor_template, args);
51+
}
52+
4953
HandleScope scope;
5054
StatWatcher *s = new StatWatcher();
5155
s->Wrap(args.Holder());

src/node_timer.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ Timer::~Timer ()
9797
Handle<Value>
9898
Timer::New (const Arguments& args)
9999
{
100+
if (!args.IsConstructCall()) {
101+
return FromConstructorTemplate(constructor_template, args);
102+
}
103+
100104
HandleScope scope;
101105

102106
Timer *t = new Timer();

0 commit comments

Comments
 (0)