diff options
author | isaacs <i@izs.me> | 2013-01-16 11:26:28 -0800 |
---|---|---|
committer | isaacs <i@izs.me> | 2013-01-17 09:21:45 -0800 |
commit | b48e303af023dc60b6f6590694ba94d9b8108702 (patch) | |
tree | 8955d9e110bc5a2193d9dfdc96660c59207b9fe6 | |
parent | 562d3f11f316a38b935f95841648da35fe754335 (diff) | |
download | nodejs-b48e303af023dc60b6f6590694ba94d9b8108702.tar.gz nodejs-b48e303af023dc60b6f6590694ba94d9b8108702.tar.bz2 nodejs-b48e303af023dc60b6f6590694ba94d9b8108702.zip |
events: Don't crash on events named __proto__
This prefixes all event names internally with 'ev'.
-rw-r--r-- | lib/events.js | 67 | ||||
-rw-r--r-- | test/simple/test-event-emitter-check-listener-leaks.js | 14 | ||||
-rw-r--r-- | test/simple/test-event-emitter-listeners-side-effects.js | 12 | ||||
-rw-r--r-- | test/simple/test-event-emitter-prototype-property.js | 37 |
4 files changed, 86 insertions, 44 deletions
diff --git a/lib/events.js b/lib/events.js index 223015ec6..5093f4ef1 100644 --- a/lib/events.js +++ b/lib/events.js @@ -53,8 +53,8 @@ var PROCESS; EventEmitter.prototype.emit = function(type) { // If there is no 'error' event listener then throw. if (type === 'error') { - if (!this._events || !this._events.error || - (isArray(this._events.error) && !this._events.error.length)) + if (!this._events || !this._events.everror || + (isArray(this._events.everror) && !this._events.everror.length)) { if (this.domain) { var er = arguments[1]; @@ -75,7 +75,8 @@ EventEmitter.prototype.emit = function(type) { } if (!this._events) return false; - var handler = this._events[type]; + var evtype = 'ev' + type; + var handler = this._events[evtype]; if (!handler) return false; if (typeof handler == 'function') { @@ -142,36 +143,37 @@ EventEmitter.prototype.addListener = function(type, listener) { // To avoid recursion in the case that type == "newListener"! Before // adding it to the listeners, first emit "newListener". - if (this._events.newListener) { + if (this._events.evnewListener) { this.emit('newListener', type, typeof listener.listener === 'function' ? listener.listener : listener); } - if (!this._events[type]) { + var evtype = 'ev' + type; + if (!this._events[evtype]) { // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - } else if (isArray(this._events[type])) { + this._events[evtype] = listener; + } else if (isArray(this._events[evtype])) { // If we've already got an array, just append. - this._events[type].push(listener); + this._events[evtype].push(listener); } else { // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; + this._events[evtype] = [this._events[evtype], listener]; } // Check for listener leak - if (isArray(this._events[type]) && !this._events[type].warned) { + if (isArray(this._events[evtype]) && !this._events[evtype].warned) { var m; m = this._maxListeners; - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; + if (m && m > 0 && this._events[evtype].length > m) { + this._events[evtype].warned = true; console.error('(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); + this._events[evtype].length); console.trace(); } } @@ -204,10 +206,11 @@ EventEmitter.prototype.removeListener = function(type, listener) { throw new Error('removeListener only takes instances of Function'); } - // does not use listeners(), so no side effect of creating _events[type] - if (!this._events || !this._events[type]) return this; + var evtype = 'ev' + type; + // does not use listeners(), so no side effect of creating _events[evtype] + if (!this._events || !this._events[evtype]) return this; - var list = this._events[type]; + var list = this._events[evtype]; if (isArray(list)) { var position = -1; @@ -223,17 +226,17 @@ EventEmitter.prototype.removeListener = function(type, listener) { if (position < 0) return this; list.splice(position, 1); if (list.length == 0) - this._events[type] = null; + this._events[evtype] = null; - if (this._events.removeListener) { + if (this._events.evremoveListener) { this.emit('removeListener', type, listener); } } else if (list === listener || (list.listener && list.listener === listener)) { - this._events[type] = null; + this._events[evtype] = null; - if (this._events.removeListener) { + if (this._events.evremoveListener) { this.emit('removeListener', type, listener); } } @@ -245,11 +248,11 @@ EventEmitter.prototype.removeAllListeners = function(type) { if (!this._events) return this; // fast path - if (!this._events.removeListener) { + if (!this._events.evremoveListener) { if (arguments.length === 0) { this._events = {}; - } else if (type && this._events && this._events[type]) { - this._events[type] = null; + } else if (type && this._events && this._events['ev' + type]) { + this._events['ev' + type] = null; } return this; } @@ -257,15 +260,16 @@ EventEmitter.prototype.removeAllListeners = function(type) { // slow(ish) path, emit 'removeListener' events for all removals if (arguments.length === 0) { for (var key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); + if (key === 'evremoveListener') continue; + this.removeAllListeners(key.slice(2)); } this.removeAllListeners('removeListener'); this._events = {}; return this; } - var listeners = this._events[type]; + var evtype = 'ev' + type; + var listeners = this._events[evtype]; if (isArray(listeners)) { while (listeners.length) { // LIFO order @@ -274,15 +278,16 @@ EventEmitter.prototype.removeAllListeners = function(type) { } else if (listeners) { this.removeListener(type, listeners); } - this._events[type] = null; + this._events[evtype] = null; return this; }; EventEmitter.prototype.listeners = function(type) { - if (!this._events || !this._events[type]) return []; - if (!isArray(this._events[type])) { - return [this._events[type]]; + var evtype = 'ev' + type; + if (!this._events || !this._events[evtype]) return []; + if (!isArray(this._events[evtype])) { + return [this._events[evtype]]; } - return this._events[type].slice(0); + return this._events[evtype].slice(0); }; diff --git a/test/simple/test-event-emitter-check-listener-leaks.js b/test/simple/test-event-emitter-check-listener-leaks.js index 7d9c20324..1aa54bf4c 100644 --- a/test/simple/test-event-emitter-check-listener-leaks.js +++ b/test/simple/test-event-emitter-check-listener-leaks.js @@ -29,30 +29,30 @@ var e = new events.EventEmitter(); for (var i = 0; i < 10; i++) { e.on('default', function() {}); } -assert.ok(!e._events['default'].hasOwnProperty('warned')); +assert.ok(!e._events.evdefault.hasOwnProperty('warned')); e.on('default', function() {}); -assert.ok(e._events['default'].warned); +assert.ok(e._events.evdefault.warned); // specific e.setMaxListeners(5); for (var i = 0; i < 5; i++) { e.on('specific', function() {}); } -assert.ok(!e._events['specific'].hasOwnProperty('warned')); +assert.ok(!e._events.evspecific.hasOwnProperty('warned')); e.on('specific', function() {}); -assert.ok(e._events['specific'].warned); +assert.ok(e._events.evspecific.warned); // only one e.setMaxListeners(1); e.on('only one', function() {}); -assert.ok(!e._events['only one'].hasOwnProperty('warned')); +assert.ok(!e._events['evonly one'].hasOwnProperty('warned')); e.on('only one', function() {}); -assert.ok(e._events['only one'].hasOwnProperty('warned')); +assert.ok(e._events['evonly one'].hasOwnProperty('warned')); // unlimited e.setMaxListeners(0); for (var i = 0; i < 1000; i++) { e.on('unlimited', function() {}); } -assert.ok(!e._events['unlimited'].hasOwnProperty('warned')); +assert.ok(!e._events['evunlimited'].hasOwnProperty('warned')); diff --git a/test/simple/test-event-emitter-listeners-side-effects.js b/test/simple/test-event-emitter-listeners-side-effects.js index 92a5bef97..f60e26b8b 100644 --- a/test/simple/test-event-emitter-listeners-side-effects.js +++ b/test/simple/test-event-emitter-listeners-side-effects.js @@ -37,21 +37,21 @@ assert.equal(e._events, null); e.on('foo', assert.fail); fl = e.listeners('foo'); -assert(e._events.foo === assert.fail); +assert(e._events.evfoo === assert.fail); assert(Array.isArray(fl)); assert(fl.length === 1); assert(fl[0] === assert.fail); e.listeners('bar'); -assert(!e._events.hasOwnProperty('bar')); +assert(!e._events.hasOwnProperty('evbar')); e.on('foo', assert.ok); fl = e.listeners('foo'); -assert(Array.isArray(e._events.foo)); -assert(e._events.foo.length === 2); -assert(e._events.foo[0] === assert.fail); -assert(e._events.foo[1] === assert.ok); +assert(Array.isArray(e._events.evfoo)); +assert(e._events.evfoo.length === 2); +assert(e._events.evfoo[0] === assert.fail); +assert(e._events.evfoo[1] === assert.ok); assert(Array.isArray(fl)); assert(fl.length === 2); diff --git a/test/simple/test-event-emitter-prototype-property.js b/test/simple/test-event-emitter-prototype-property.js new file mode 100644 index 000000000..a5d8a7d04 --- /dev/null +++ b/test/simple/test-event-emitter-prototype-property.js @@ -0,0 +1,37 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var events = require('events'); + +var e = new events.EventEmitter(); + +var emited = false; +e.on('__proto__', function() { + emited = true; +}); + +e.emit('__proto__'); + +process.on('exit', function() { + assert.equal(true, emited); +}); |