nix/tests/functional/lang/eval-fail-mutual-recursion.err.exp
Rebecca Turner 7434caca05
Fix segfault on infinite recursion in some cases
This fixes a segfault on infinite function call recursion (rather than
infinite thunk recursion) by tracking the function call depth in
`EvalState`.

Additionally, to avoid printing extremely long stack traces, stack
frames are now deduplicated, with a `(19997 duplicate traces omitted)`
message. This should only really be triggered in infinite recursion
scenarios.

Before:

    $ nix-instantiate --eval --expr '(x: x x) (x: x x)'
    Segmentation fault: 11

After:

    $ nix-instantiate --eval --expr '(x: x x) (x: x x)'
    error: stack overflow

           at «string»:1:14:
                1| (x: x x) (x: x x)
                 |              ^

    $ nix-instantiate --eval --expr '(x: x x) (x: x x)' --show-trace
    error:
           … from call site
             at «string»:1:1:
                1| (x: x x) (x: x x)
                 | ^

           … while calling anonymous lambda
             at «string»:1:2:
                1| (x: x x) (x: x x)
                 |  ^

           … from call site
             at «string»:1:5:
                1| (x: x x) (x: x x)
                 |     ^

           … while calling anonymous lambda
             at «string»:1:11:
                1| (x: x x) (x: x x)
                 |           ^

           … from call site
             at «string»:1:14:
                1| (x: x x) (x: x x)
                 |              ^

           (19997 duplicate traces omitted)

           error: stack overflow
           at «string»:1:14:
                1| (x: x x) (x: x x)
                 |              ^
2023-12-29 22:16:44 -08:00

58 lines
1.7 KiB
Plaintext

error:
… from call site
at /pwd/lang/eval-fail-mutual-recursion.nix:36:3:
35| in
36| throwAfterA true 10
| ^
37|
… while calling 'throwAfterA'
at /pwd/lang/eval-fail-mutual-recursion.nix:29:26:
28|
29| throwAfterA = recurse: n:
| ^
30| if n > 0
… from call site
at /pwd/lang/eval-fail-mutual-recursion.nix:31:10:
30| if n > 0
31| then throwAfterA recurse (n - 1)
| ^
32| else if recurse
(19 duplicate frames omitted)
… from call site
at /pwd/lang/eval-fail-mutual-recursion.nix:33:10:
32| else if recurse
33| then throwAfterB true 10
| ^
34| else throw "Uh oh!";
… while calling 'throwAfterB'
at /pwd/lang/eval-fail-mutual-recursion.nix:22:26:
21| let
22| throwAfterB = recurse: n:
| ^
23| if n > 0
… from call site
at /pwd/lang/eval-fail-mutual-recursion.nix:24:10:
23| if n > 0
24| then throwAfterB recurse (n - 1)
| ^
25| else if recurse
(19 duplicate frames omitted)
… from call site
at /pwd/lang/eval-fail-mutual-recursion.nix:26:10:
25| else if recurse
26| then throwAfterA false 10
| ^
27| else throw "Uh oh!";
(21 duplicate frames omitted)
error: Uh oh!