diff --git a/lib/timers.js b/lib/timers.js index 94567f7990b994..c220cf1226f64b 100644 --- a/lib/timers.js +++ b/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); } } diff --git a/test/parallel/test-timers-user-call.js b/test/parallel/test-timers-user-call.js new file mode 100644 index 00000000000000..4ff24e688b5aa3 --- /dev/null +++ b/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'); +}