summaryrefslogtreecommitdiff
path: root/runtime/js/11_timers.js
diff options
context:
space:
mode:
authorAnonymous <65428781+00ff0000red@users.noreply.github.com>2021-01-06 05:53:30 -0800
committerGitHub <noreply@github.com>2021-01-06 08:53:30 -0500
commit3761d054d0d6f10f9ead6105f3eb633572a38673 (patch)
treec72b132dfa421c2a268b363b9bbef6628b1be95a /runtime/js/11_timers.js
parentd364a0effeac6638d44301e1672ac0b27bf6ee7f (diff)
fix: stronger input checking for setTimeout; add function overload (#8957)
Diffstat (limited to 'runtime/js/11_timers.js')
-rw-r--r--runtime/js/11_timers.js44
1 files changed, 25 insertions, 19 deletions
diff --git a/runtime/js/11_timers.js b/runtime/js/11_timers.js
index 5a59844a3..166694358 100644
--- a/runtime/js/11_timers.js
+++ b/runtime/js/11_timers.js
@@ -274,7 +274,7 @@
}
const { console } = globalThis;
- const OriginalDate = Date;
+ const OriginalDateNow = Date.now;
// Timeout values > TIMEOUT_MAX are set to 1.
const TIMEOUT_MAX = 2 ** 31 - 1;
@@ -333,7 +333,7 @@
}
function prepareReadyTimers() {
- const now = OriginalDate.now();
+ const now = OriginalDateNow();
// Bail out if we're not expecting the global timer to fire.
if (globalTimeoutDue === null || pendingEvents > 0) {
return;
@@ -409,7 +409,7 @@
const nextDueNode = dueTree.min();
setOrClearGlobalTimeout(
nextDueNode && nextDueNode.due,
- OriginalDate.now(),
+ OriginalDateNow(),
);
}
} else {
@@ -434,14 +434,18 @@
} else {
// Interval timer: compute when timer was supposed to fire next.
// However make sure to never schedule the next interval in the past.
- const now = OriginalDate.now();
+ const now = OriginalDateNow();
timer.due = Math.max(now, timer.due + timer.delay);
schedule(timer, now);
}
// Call the user callback. Intermediate assignment is to avoid leaking `this`
// to it, while also keeping the stack trace neat when it shows up in there.
const callback = timer.callback;
- callback();
+ if ("function" === typeof callback) {
+ callback();
+ } else {
+ eval(callback);
+ }
}
function checkThis(thisArg) {
@@ -450,24 +454,26 @@
}
}
- function checkBigInt(n) {
- if (typeof n === "bigint") {
- throw new TypeError("Cannot convert a BigInt value to a number");
- }
- }
-
function setTimer(
cb,
delay,
args,
repeat,
) {
- // Bind `args` to the callback and bind `this` to globalThis(global).
- const callback = cb.bind(globalThis, ...args);
+ // If the callack is a function, bind `args` to the callback and bind `this` to globalThis(global).
+ // otherwise call `String` on it, and `eval` it on calls; do not pass variardic args to the string
+ let callback;
+
+ if ("function" === typeof cb) {
+ callback = Function.prototype.bind.call(cb, globalThis, ...args);
+ } else {
+ callback = String(cb);
+ args = []; // args are ignored
+ }
// In the browser, the delay value must be coercible to an integer between 0
// and INT32_MAX. Any other value will cause the timer to fire immediately.
// We emulate this behavior.
- const now = OriginalDate.now();
+ const now = OriginalDateNow();
if (delay > TIMEOUT_MAX) {
console.warn(
`${delay} does not fit into` +
@@ -500,7 +506,7 @@
delay = 0,
...args
) {
- checkBigInt(delay);
+ delay >>>= 0;
checkThis(this);
return setTimer(cb, delay, args, false);
}
@@ -510,13 +516,13 @@
delay = 0,
...args
) {
- checkBigInt(delay);
+ delay >>>= 0;
checkThis(this);
return setTimer(cb, delay, args, true);
}
function clearTimer(id) {
- id = Number(id);
+ id >>>= 0;
const timer = idMap.get(id);
if (timer === undefined) {
// Timer doesn't exist any more or never existed. This is not an error.
@@ -528,7 +534,7 @@
}
function clearTimeout(id = 0) {
- checkBigInt(id);
+ id >>>= 0;
if (id === 0) {
return;
}
@@ -536,7 +542,7 @@
}
function clearInterval(id = 0) {
- checkBigInt(id);
+ id >>>= 0;
if (id === 0) {
return;
}