From 935ebb87061f0275cb27a6db648ac27f732a01c2 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 16 Dec 2014 17:17:28 -0500 Subject: [PATCH] net: throw on invalid socket timeouts This commit restricts socket timeouts non-negative, finite numbers. Any other value throws a TypeError or RangeError. This prevents subtle bugs that can happen due to type coercion. --- lib/net.js | 12 ++++++------ lib/timers.js | 15 ++++++++++++--- test/simple/test-net-settimeout.js | 2 +- test/simple/test-net-socket-timeout.js | 25 +++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/lib/net.js b/lib/net.js index fac78f8c04d..2fabd5355c5 100644 --- a/lib/net.js +++ b/lib/net.js @@ -319,17 +319,17 @@ Socket.prototype.listen = function() { Socket.prototype.setTimeout = function(msecs, callback) { - if (msecs > 0 && isFinite(msecs)) { + if (msecs === 0) { + timers.unenroll(this); + if (callback) { + this.removeListener('timeout', callback); + } + } else { timers.enroll(this, msecs); timers._unrefActive(this); if (callback) { this.once('timeout', callback); } - } else if (msecs === 0) { - timers.unenroll(this); - if (callback) { - this.removeListener('timeout', callback); - } } }; diff --git a/lib/timers.js b/lib/timers.js index 68e3e65e9aa..218f8f9a43f 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -28,7 +28,8 @@ var kOnTimeout = Timer.kOnTimeout | 0; // Timeout values > TIMEOUT_MAX are set to 1. var TIMEOUT_MAX = 2147483647; // 2^31-1 -var debug = require('util').debuglog('timer'); +var util = require('util'); +var debug = util.debuglog('timer'); // IDLE TIMEOUTS @@ -151,13 +152,21 @@ var unenroll = exports.unenroll = function(item) { // Does not start the time, just sets up the members needed. exports.enroll = function(item, msecs) { + if (!util.isNumber(msecs)) { + throw new TypeError('msecs must be a number'); + } + + if (msecs < 0 || !isFinite(msecs)) { + throw new RangeError('msecs must be a non-negative finite number'); + } + // if this item was already in a list somewhere // then we should unenroll it from that if (item._idleNext) unenroll(item); // Ensure that msecs fits into signed int32 - if (msecs > 0x7fffffff) { - msecs = 0x7fffffff; + if (msecs > TIMEOUT_MAX) { + msecs = TIMEOUT_MAX; } item._idleTimeout = msecs; diff --git a/test/simple/test-net-settimeout.js b/test/simple/test-net-settimeout.js index da13385b94e..bce73584fec 100644 --- a/test/simple/test-net-settimeout.js +++ b/test/simple/test-net-settimeout.js @@ -33,7 +33,7 @@ var server = net.createServer(function(c) { }); server.listen(common.PORT); -var killers = [0, Infinity, NaN]; +var killers = [0]; var left = killers.length; killers.forEach(function(killer) { diff --git a/test/simple/test-net-socket-timeout.js b/test/simple/test-net-socket-timeout.js index 2256d6813aa..7f874c0cef0 100644 --- a/test/simple/test-net-socket-timeout.js +++ b/test/simple/test-net-socket-timeout.js @@ -23,6 +23,31 @@ var common = require('../common'); var net = require('net'); var assert = require('assert'); +// Verify that invalid delays throw +var noop = function() {}; +var s = new net.Socket(); +var nonNumericDelays = ['100', true, false, undefined, null, '', {}, noop, []]; +var badRangeDelays = [-0.001, -1, -Infinity, Infinity, NaN]; +var validDelays = [0, 0.001, 1, 1e6]; + +for (var i = 0; i < nonNumericDelays.length; i++) { + assert.throws(function() { + s.setTimeout(nonNumericDelays[i], noop); + }, TypeError); +} + +for (var i = 0; i < badRangeDelays.length; i++) { + assert.throws(function() { + s.setTimeout(badRangeDelays[i], noop); + }, RangeError); +} + +for (var i = 0; i < validDelays.length; i++) { + assert.doesNotThrow(function() { + s.setTimeout(validDelays[i], noop); + }); +} + var timedout = false; var server = net.Server();