Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit b48e303

Browse files
committed
events: Don't crash on events named __proto__
This prefixes all event names internally with 'ev'.
1 parent 562d3f1 commit b48e303

4 files changed

+86
-44
lines changed

lib/events.js

+36-31
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ var PROCESS;
5353
EventEmitter.prototype.emit = function(type) {
5454
// If there is no 'error' event listener then throw.
5555
if (type === 'error') {
56-
if (!this._events || !this._events.error ||
57-
(isArray(this._events.error) && !this._events.error.length))
56+
if (!this._events || !this._events.everror ||
57+
(isArray(this._events.everror) && !this._events.everror.length))
5858
{
5959
if (this.domain) {
6060
var er = arguments[1];
@@ -75,7 +75,8 @@ EventEmitter.prototype.emit = function(type) {
7575
}
7676

7777
if (!this._events) return false;
78-
var handler = this._events[type];
78+
var evtype = 'ev' + type;
79+
var handler = this._events[evtype];
7980
if (!handler) return false;
8081

8182
if (typeof handler == 'function') {
@@ -142,36 +143,37 @@ EventEmitter.prototype.addListener = function(type, listener) {
142143

143144
// To avoid recursion in the case that type == "newListener"! Before
144145
// adding it to the listeners, first emit "newListener".
145-
if (this._events.newListener) {
146+
if (this._events.evnewListener) {
146147
this.emit('newListener', type, typeof listener.listener === 'function' ?
147148
listener.listener : listener);
148149
}
149150

150-
if (!this._events[type]) {
151+
var evtype = 'ev' + type;
152+
if (!this._events[evtype]) {
151153
// Optimize the case of one listener. Don't need the extra array object.
152-
this._events[type] = listener;
153-
} else if (isArray(this._events[type])) {
154+
this._events[evtype] = listener;
155+
} else if (isArray(this._events[evtype])) {
154156

155157
// If we've already got an array, just append.
156-
this._events[type].push(listener);
158+
this._events[evtype].push(listener);
157159

158160
} else {
159161
// Adding the second element, need to change to array.
160-
this._events[type] = [this._events[type], listener];
162+
this._events[evtype] = [this._events[evtype], listener];
161163

162164
}
163165

164166
// Check for listener leak
165-
if (isArray(this._events[type]) && !this._events[type].warned) {
167+
if (isArray(this._events[evtype]) && !this._events[evtype].warned) {
166168
var m;
167169
m = this._maxListeners;
168170

169-
if (m && m > 0 && this._events[type].length > m) {
170-
this._events[type].warned = true;
171+
if (m && m > 0 && this._events[evtype].length > m) {
172+
this._events[evtype].warned = true;
171173
console.error('(node) warning: possible EventEmitter memory ' +
172174
'leak detected. %d listeners added. ' +
173175
'Use emitter.setMaxListeners() to increase limit.',
174-
this._events[type].length);
176+
this._events[evtype].length);
175177
console.trace();
176178
}
177179
}
@@ -204,10 +206,11 @@ EventEmitter.prototype.removeListener = function(type, listener) {
204206
throw new Error('removeListener only takes instances of Function');
205207
}
206208

207-
// does not use listeners(), so no side effect of creating _events[type]
208-
if (!this._events || !this._events[type]) return this;
209+
var evtype = 'ev' + type;
210+
// does not use listeners(), so no side effect of creating _events[evtype]
211+
if (!this._events || !this._events[evtype]) return this;
209212

210-
var list = this._events[type];
213+
var list = this._events[evtype];
211214

212215
if (isArray(list)) {
213216
var position = -1;
@@ -223,17 +226,17 @@ EventEmitter.prototype.removeListener = function(type, listener) {
223226
if (position < 0) return this;
224227
list.splice(position, 1);
225228
if (list.length == 0)
226-
this._events[type] = null;
229+
this._events[evtype] = null;
227230

228-
if (this._events.removeListener) {
231+
if (this._events.evremoveListener) {
229232
this.emit('removeListener', type, listener);
230233
}
231234
} else if (list === listener ||
232235
(list.listener && list.listener === listener))
233236
{
234-
this._events[type] = null;
237+
this._events[evtype] = null;
235238

236-
if (this._events.removeListener) {
239+
if (this._events.evremoveListener) {
237240
this.emit('removeListener', type, listener);
238241
}
239242
}
@@ -245,27 +248,28 @@ EventEmitter.prototype.removeAllListeners = function(type) {
245248
if (!this._events) return this;
246249

247250
// fast path
248-
if (!this._events.removeListener) {
251+
if (!this._events.evremoveListener) {
249252
if (arguments.length === 0) {
250253
this._events = {};
251-
} else if (type && this._events && this._events[type]) {
252-
this._events[type] = null;
254+
} else if (type && this._events && this._events['ev' + type]) {
255+
this._events['ev' + type] = null;
253256
}
254257
return this;
255258
}
256259

257260
// slow(ish) path, emit 'removeListener' events for all removals
258261
if (arguments.length === 0) {
259262
for (var key in this._events) {
260-
if (key === 'removeListener') continue;
261-
this.removeAllListeners(key);
263+
if (key === 'evremoveListener') continue;
264+
this.removeAllListeners(key.slice(2));
262265
}
263266
this.removeAllListeners('removeListener');
264267
this._events = {};
265268
return this;
266269
}
267270

268-
var listeners = this._events[type];
271+
var evtype = 'ev' + type;
272+
var listeners = this._events[evtype];
269273
if (isArray(listeners)) {
270274
while (listeners.length) {
271275
// LIFO order
@@ -274,15 +278,16 @@ EventEmitter.prototype.removeAllListeners = function(type) {
274278
} else if (listeners) {
275279
this.removeListener(type, listeners);
276280
}
277-
this._events[type] = null;
281+
this._events[evtype] = null;
278282

279283
return this;
280284
};
281285

282286
EventEmitter.prototype.listeners = function(type) {
283-
if (!this._events || !this._events[type]) return [];
284-
if (!isArray(this._events[type])) {
285-
return [this._events[type]];
287+
var evtype = 'ev' + type;
288+
if (!this._events || !this._events[evtype]) return [];
289+
if (!isArray(this._events[evtype])) {
290+
return [this._events[evtype]];
286291
}
287-
return this._events[type].slice(0);
292+
return this._events[evtype].slice(0);
288293
};

test/simple/test-event-emitter-check-listener-leaks.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,30 @@ var e = new events.EventEmitter();
2929
for (var i = 0; i < 10; i++) {
3030
e.on('default', function() {});
3131
}
32-
assert.ok(!e._events['default'].hasOwnProperty('warned'));
32+
assert.ok(!e._events.evdefault.hasOwnProperty('warned'));
3333
e.on('default', function() {});
34-
assert.ok(e._events['default'].warned);
34+
assert.ok(e._events.evdefault.warned);
3535

3636
// specific
3737
e.setMaxListeners(5);
3838
for (var i = 0; i < 5; i++) {
3939
e.on('specific', function() {});
4040
}
41-
assert.ok(!e._events['specific'].hasOwnProperty('warned'));
41+
assert.ok(!e._events.evspecific.hasOwnProperty('warned'));
4242
e.on('specific', function() {});
43-
assert.ok(e._events['specific'].warned);
43+
assert.ok(e._events.evspecific.warned);
4444

4545
// only one
4646
e.setMaxListeners(1);
4747
e.on('only one', function() {});
48-
assert.ok(!e._events['only one'].hasOwnProperty('warned'));
48+
assert.ok(!e._events['evonly one'].hasOwnProperty('warned'));
4949
e.on('only one', function() {});
50-
assert.ok(e._events['only one'].hasOwnProperty('warned'));
50+
assert.ok(e._events['evonly one'].hasOwnProperty('warned'));
5151

5252
// unlimited
5353
e.setMaxListeners(0);
5454
for (var i = 0; i < 1000; i++) {
5555
e.on('unlimited', function() {});
5656
}
57-
assert.ok(!e._events['unlimited'].hasOwnProperty('warned'));
57+
assert.ok(!e._events['evunlimited'].hasOwnProperty('warned'));
5858

test/simple/test-event-emitter-listeners-side-effects.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,21 @@ assert.equal(e._events, null);
3737

3838
e.on('foo', assert.fail);
3939
fl = e.listeners('foo');
40-
assert(e._events.foo === assert.fail);
40+
assert(e._events.evfoo === assert.fail);
4141
assert(Array.isArray(fl));
4242
assert(fl.length === 1);
4343
assert(fl[0] === assert.fail);
4444

4545
e.listeners('bar');
46-
assert(!e._events.hasOwnProperty('bar'));
46+
assert(!e._events.hasOwnProperty('evbar'));
4747

4848
e.on('foo', assert.ok);
4949
fl = e.listeners('foo');
5050

51-
assert(Array.isArray(e._events.foo));
52-
assert(e._events.foo.length === 2);
53-
assert(e._events.foo[0] === assert.fail);
54-
assert(e._events.foo[1] === assert.ok);
51+
assert(Array.isArray(e._events.evfoo));
52+
assert(e._events.evfoo.length === 2);
53+
assert(e._events.evfoo[0] === assert.fail);
54+
assert(e._events.evfoo[1] === assert.ok);
5555

5656
assert(Array.isArray(fl));
5757
assert(fl.length === 2);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
var common = require('../common');
23+
var assert = require('assert');
24+
var events = require('events');
25+
26+
var e = new events.EventEmitter();
27+
28+
var emited = false;
29+
e.on('__proto__', function() {
30+
emited = true;
31+
});
32+
33+
e.emit('__proto__');
34+
35+
process.on('exit', function() {
36+
assert.equal(true, emited);
37+
});

0 commit comments

Comments
 (0)