Browse Source

timers: do not use user object call/apply

Timers should work even if the user has monkey-patched `.call()` and
`.apply()` to undesirable values.

PR-URL: https://github.com/nodejs/node/pull/12960
Ref: https://github.com/nodejs/node/issues/12956
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
v6.x
Rich Trott 8 years ago
committed by Myles Borins
parent
commit
e8438c1b22
No known key found for this signature in database GPG Key ID: 933B01F40B5CA946
  1. 12
      lib/timers.js
  2. 40
      test/parallel/test-timers-user-call.js

12
lib/timers.js

@ -383,20 +383,20 @@ function ontimeout(timer) {
var args = timer._timerArgs;
var callback = timer._onTimeout;
if (!args)
callback.call(timer);
timer._onTimeout();
else {
switch (args.length) {
case 1:
callback.call(timer, args[0]);
timer._onTimeout(args[0]);
break;
case 2:
callback.call(timer, args[0], args[1]);
timer._onTimeout(args[0], args[1]);
break;
case 3:
callback.call(timer, args[0], args[1], args[2]);
timer._onTimeout(args[0], args[1], args[2]);
break;
default:
callback.apply(timer, args);
Function.prototype.apply.call(callback, timer, args);
}
}
if (timer._repeat)
@ -678,7 +678,7 @@ function runCallback(timer) {
return timer._callback(argv[0], argv[1], argv[2]);
// more than 3 arguments run slower with .apply
default:
return timer._callback.apply(timer, argv);
return Function.prototype.apply.call(timer._callback, timer, argv);
}
}

40
test/parallel/test-timers-user-call.js

@ -0,0 +1,40 @@
// Make sure `setTimeout()` and friends don't throw if the user-supplied
// function has .call() and .apply() monkey-patched to undesirable values.
// Refs: https://github.com/nodejs/node/issues/12956
'use strict';
const common = require('../common');
{
const fn = common.mustCall(10);
fn.call = 'not a function';
fn.apply = 'also not a function';
setTimeout(fn, 1);
setTimeout(fn, 1, 'oneArg');
setTimeout(fn, 1, 'two', 'args');
setTimeout(fn, 1, 'three', '(3)', 'args');
setTimeout(fn, 1, 'more', 'than', 'three', 'args');
setImmediate(fn, 1);
setImmediate(fn, 1, 'oneArg');
setImmediate(fn, 1, 'two', 'args');
setImmediate(fn, 1, 'three', '(3)', 'args');
setImmediate(fn, 1, 'more', 'than', 'three', 'args');
}
{
const testInterval = (...args) => {
const fn = common.mustCall(() => { clearInterval(interval); });
fn.call = 'not a function';
fn.apply = 'also not a function';
const interval = setInterval(fn, 1, ...args);
};
testInterval();
testInterval('oneArg');
testInterval('two', 'args');
testInterval('three', '(3)', 'args');
testInterval('more', 'than', 'three', 'args');
}
Loading…
Cancel
Save