Stream: ideas

Topic: dev builds reporting suspected infinite loops


view this post on Zulip Richard Feldman (Dec 19 2023 at 19:56):

in another thread about compile-time evaluations of constants, I wrote:

Richard Feldman said:

in general I don't think top level evaluations should have any restrictions beyond what they'd have if they were evaluated anywhere else
an implication of this is that they can hang your build if there's an infinite loop in them, but I think that's worth accepting as a downside

I had an idea related to this: what if in all dev builds (including when running tests and also when doing top-level evaluation of constants in the future) we had a mechanism for detecting and reporting about suspected infinite loops?

view this post on Zulip Richard Feldman (Dec 19 2023 at 19:58):

an idea I like for how we could do this:

view this post on Zulip Richard Feldman (Dec 19 2023 at 19:58):

the idea being that if we only ever emitted those in actual generated loops (which are the only places where pure Roc code can ever get stuck in an infinite loop, since all other forms of recursion will run out of stack space eventually and terminate that way) it seems like it would make infinite loops a lot easier to track down in practice

view this post on Zulip Richard Feldman (Dec 19 2023 at 19:58):

especially in tests, which would preserve the testing property I like of "only report failures, because successes aren't actionable besides a report of how long they took to run, which can happen at the end"

view this post on Zulip Richard Feldman (Dec 19 2023 at 19:59):

in optimized builds we'd never generate the counter, on the theory that (a) we don't want to pay the performance cost, and (b) if you actually authored an infinite loop, you almost certainly would have discovered it during a dev build, test run, etc.

view this post on Zulip Richard Feldman (Dec 19 2023 at 19:59):

thoughts?

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:33):

whenever we are doing a dev build and the tail recursion optimization kicks in (which is the only scenario in which pure roc code can loop forever), we include a counter in the loop

Not just tail recursive, right? Any recursive could hit it

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:33):

on each iteration of the loop, we increment the counter and check if it has exceeded some huge value (the value can be configured by a CLI flag, or this check can be disabled altogether if desired)

I think this is essentially what zig does. It limits backwards branches I believe.

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:34):

non tail recursive functions would stack overflow eventually, so they have a built in reporting mechanics :laughing:

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:34):

ah

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:34):

first consuming 128 GB of ram, a few bytes at a time.

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:35):

haha well stacks tend to normally be limited to some number of kb or maybe mb

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:35):

true

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:35):

even Go with its segmented stacks has a cap of 1gb apparently

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:35):

Also, wouldn't this all happen at compile time, so this extra counter would never appear in the final binary?

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:36):

not even with dev builds?

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:42):

the idea would be for the counter to be inserted into the compiled binary during code gen

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:42):

so you'd see the crash at runtime when running the program

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:43):

and then when doing compile time evaluation of constants it would work the same way as it would when running an ordinary dev build

view this post on Zulip Richard Feldman (Dec 19 2023 at 20:43):

so no difference in behavior between a dev build and a compile time evaluation

view this post on Zulip Brendan Hansknecht (Dec 19 2023 at 20:44):

Interesting. What is the gain to also having this happen in dev builds, I don't quite follow that. Just help debug accidentally giant loops that generate constants?

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:02):

assuming it's actually successful at detecting infinite loops (as opposed to false positives), it would be nice during tests

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:03):

I like that roc test only prints failures at the end, and not what test it's currently running, because it keeps the output cleaner and focused on actionable information - but it does mean that if a test gets stuck in an infinite loop, there's no way to tell which test it was (or for that matter what function within the test)

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:03):

so this would help with that; it would guarantee that tests of pure Roc code would always terminate

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:04):

(naturally tests of effects in the future couldn't have that guarantee, so we might want timeouts on effectful tests once those exist)

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:05):

similarly, during dev builds, seeing "this is the function that got stuck in the loop" plus a crash backtrace would be nicer than just having the program hang

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:05):

of course if it turns out to have false positives, that would be annoying, but my hope is that by setting the counter high enough, that will be rare enough in practice that overall it'll be an improvement to user experience

view this post on Zulip Asier Elorz (he/him) (Dec 19 2023 at 21:39):

I love the idea.

The biggest challenge I see is deciding the magic number at language level, in a way that works for all loops. Too low and you start getting false negatives. Too high and it takes too long to report. Not all loops take the same time per iteration. If I have to wait an hour to know where I have an infinite loop I will most likely kill the process before that happens.

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:42):

yup haha

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:43):

my hope is that setting it high would work well in practice because it's not going to be doing any I/O if it's in pure roc code, so even if it were like a couple billion I'd usually expect it to crash in a second or two

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:44):

unless it was doing something pure but also really slow on each iteration of the loop, and the loop turned out to be infinite

view this post on Zulip Richard Feldman (Dec 19 2023 at 21:44):

which of course is possible, but hopefully wouldn't come up very often :sweat_smile:


Last updated: Jun 16 2026 at 16:19 UTC