Live data from Hacker News

setBigTimeout

evanhahn.com

31–40 of 129 posts

Re: setBigTimeout

#31
post #10

The default behaviour of setTimeout seems problematic. Could be used for an exploit, because code like this might not work as expected: const attackerControlled = ...; if (attackerControlled { console.log("Surely at least 1min has passed!"); }, attackerControlled); The attacker could set the value to a comically large number and the callback would execute immediately. This also seems to be true for NaN. The better so…

That's just terrible input validation and has nothing to do with setTimeout.

If your code would misbehave outside a certain range of values and you're input might span a larger range, you should be checking your input against the range that's valid. Your sample code simply doesn't do that, and that's why there's a bug.

That the bug happens to involve a timer is irrelevant.

Re: setBigTimeout

#32
post #3

What is the use-case for such a function?

Off the top of my head, a cron scheduler for a server that reads from a database and sets a timeout upon boot. Every time the server is reboot the timeouts are reinitialized (fail safe in case of downtime). If upon boot there’s a timeout > 25 days it’ll get executed immediately which is not the behavior you want.

Why would you do that in JS rather than just using cron for it?

Re: setBigTimeout

#33

instead of chaining together shorter timeouts, why not calculate the datetime of the delay and then invoke via window.requestAnimationFrame (by checking the current date ofc).

[deleted]

Re: setBigTimeout

#34

instead of chaining together shorter timeouts, why not calculate the datetime of the delay and then invoke via window.requestAnimationFrame (by checking the current date ofc).

Are you suggesting checking the date every frame vs scheduling long task every once in a long while? Can't tell if it is ironic or not, I'm sorry (damn Poe's law). But assuming not, it would be a lot more computationaly expensive to do that, timeouts are very optmized and they "give back" on the computer resources while in the meantime

Re: setBigTimeout

#35
post #10

The default behaviour of setTimeout seems problematic. Could be used for an exploit, because code like this might not work as expected: const attackerControlled = ...; if (attackerControlled { console.log("Surely at least 1min has passed!"); }, attackerControlled); The attacker could set the value to a comically large number and the callback would execute immediately. This also seems to be true for NaN. The better so…

That's just terrible input validation and has nothing to do with setTimeout. If your code would misbehave outside a certain range of values and you're input might span a larger range, you should be checking your input against the range that's valid . Your sample code simply doesn't do that, and that's why there's a bug. That the bug happens to involve a timer is irrelevant.

> That's just terrible input validation and has nothing to do with setTimeout.

Except for the fact that this behaviour is surprising.

> you should be checking your input against the range that's valid. Your sample code simply doesn't do that, and that's why there's a bug.

Indeed, so why doesn't setTimeout internally do that?

Re: setBigTimeout

#36

Earlier quoted context omitted.

That's just terrible input validation and has nothing to do with setTimeout. If your code would misbehave outside a certain range of values and you're input might span a larger range, you should be checking your input against the range that's valid . Your sample code simply doesn't do that, and that's why there's a bug. That the bug happens to involve a timer is irrelevant.

> That's just terrible input validation and has nothing to do with setTimeout. Except for the fact that this behaviour is surprising. > you should be checking your input against the range that's valid. Your sample code simply doesn't do that, and that's why there's a bug. Indeed, so why doesn't setTimeout internally do that?

> Indeed, so why doesn't setTimeout internally do that?

Given that `setTimeout` is a part of JavaScript's ancient reptilian brain, I wouldn't be surprised it doesn't do those checks just because there's some silly compatibility requirement still lingering and no one in the committees is brave enough to make a breaking change.

(And then, what should setTimeout do if delay is NaN? Do nothing? Call immediately? Throw an exception? Personally I'd prefer it to throw, but I don't think there's any single undeniably correct answer.)

Given the trend to move away from the callbacks, I wonder why there is no `async function sleep(delay)` in the language, that would be free to sort this out nicely without having to be compatible with stuff from '90s. Or something like that.

Re: setBigTimeout

#37
post #28
post #24

> In most JavaScript runtimes, this duration is represented as a 32-bit signed integer I thought all numbers in JavaScript were basically some variation of double precision floating points, if so, why is setTimeout limited to a smaller 32bit signed integer? If this is true, then if I pass something like "0.5", does it round the number when casting it to an integer? Or does it execute the callback after half a millise…

You're correct about JS numbers. It works like this presumably because the implementation is written in C++ or the like and uses an int32 for this, because "25 days ought to be enough for everyone".

I thought most non-abandoned C/C++ projects have long switched to time_t or similar. 2038 is not that far in the future.

Re: setBigTimeout

#38
post #10

The default behaviour of setTimeout seems problematic. Could be used for an exploit, because code like this might not work as expected: const attackerControlled = ...; if (attackerControlled { console.log("Surely at least 1min has passed!"); }, attackerControlled); The attacker could set the value to a comically large number and the callback would execute immediately. This also seems to be true for NaN. The better so…

In nodejs you at least get a warning along with the problematic behavior:

    Welcome to Node.js v22.7.0.
    Type ".help" for more information.
    > setTimeout(() => console.log('reached'), 3.456e9)
    Timeout {  }
    > (node:64799) TimeoutOverflowWarning: 3456000000 does not fit into a 32-bit signed integer.
    Timeout duration was set to 1.
    (Use `node --trace-warnings ...` to show where the warning was created)
    reached
I'm surprised to see that setTimeout returns an object - I assume at one point it was an integer identifying the timer, the same way it is on the web. (I think I remember it being so at one point.)

Re: setBigTimeout

#39

Earlier quoted context omitted.

A scenario where an attacker can control a timeout where having the callback run sooner than one minute later would lead to security failures, but having it set to run days later is perfectly fine and so no upper bound check is required seems… quite a constructed edge case. The problem here is having an attacker control a security sensitive timer in the first place.

The exploit could be a DoS attack. I don't think it's that contrived to have a service that runs an expensive operation at a fixed rate, controlled by the user, limited to 1 operation per minute.

> I don't think it's that contrived to have a service that runs an expensive operation at a fixed rate, controlled by the user

Maybe not contrived but definitely insecure by definition. Allowing user control of rates is definitely useful & a power devs will need to grant but it should never be direct control.

Re: setBigTimeout

#40
post #29
post #24

> In most JavaScript runtimes, this duration is represented as a 32-bit signed integer I thought all numbers in JavaScript were basically some variation of double precision floating points, if so, why is setTimeout limited to a smaller 32bit signed integer? If this is true, then if I pass something like "0.5", does it round the number when casting it to an integer? Or does it execute the callback after half a millise…

JS numbers technically have 53 bits for integers (mantissa) but all binary operators turns it into a 32-bit signed integer. Maybe this is related somehow to the setTimeout limitation. JavaScript also has the >>> unsigned bit shift operator so you can squeeze that last bit out of it if you only care about positive values: ((2*32-1)>>>0).toString(2).length === 32

I assume by binary you mean logical? A + b certainly does not treat either side as 32bit.
Post reply on HN