diff --git a/lix/libexpr/eval.cc b/lix/libexpr/eval.cc index ab8e4f5ee..e9d24f941 100644 --- a/lix/libexpr/eval.cc +++ b/lix/libexpr/eval.cc @@ -1118,8 +1118,9 @@ Env & AttrsPattern::match( Value EvalState::callFunction(Value & fun, std::span args, const PosIdx pos) { - if (callDepth > evalSettings.maxCallDepth) + if (callDepth >= evalSettings.maxCallDepth) { ctx.errors.make("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow(); + } MaintainCount _level(callDepth); auto trace = evalSettings.traceFunctionCalls diff --git a/tests/functional2/lang/function-recursion/evail-fail-maxCallDepth0-maxCallDepth.err.exp b/tests/functional2/lang/function-recursion/evail-fail-maxCallDepth0-maxCallDepth.err.exp new file mode 100644 index 000000000..f5e84bc23 --- /dev/null +++ b/tests/functional2/lang/function-recursion/evail-fail-maxCallDepth0-maxCallDepth.err.exp @@ -0,0 +1,6 @@ +error: stack overflow; max-call-depth exceeded + at /pwd/in.nix:2:22: + 1| # Exactly two function calls deep, so should fail with maxCallDepth < 2 + 2| let f = x: x + 1; in f (f 0) + | ^ + 3| diff --git a/tests/functional2/lang/function-recursion/evail-fail-maxCallDepth1-maxCallDepth.err.exp b/tests/functional2/lang/function-recursion/evail-fail-maxCallDepth1-maxCallDepth.err.exp new file mode 100644 index 000000000..ff266cda4 --- /dev/null +++ b/tests/functional2/lang/function-recursion/evail-fail-maxCallDepth1-maxCallDepth.err.exp @@ -0,0 +1,28 @@ +error: + … from call site + at /pwd/in.nix:2:22: + 1| # Exactly two function calls deep, so should fail with maxCallDepth < 2 + 2| let f = x: x + 1; in f (f 0) + | ^ + 3| + + … while calling 'f' + at /pwd/in.nix:2:9: + 1| # Exactly two function calls deep, so should fail with maxCallDepth < 2 + 2| let f = x: x + 1; in f (f 0) + | ^ + 3| + + … while evaluating x + at /pwd/in.nix:2:12: + 1| # Exactly two function calls deep, so should fail with maxCallDepth < 2 + 2| let f = x: x + 1; in f (f 0) + | ^ + 3| + + error: stack overflow; max-call-depth exceeded + at /pwd/in.nix:2:25: + 1| # Exactly two function calls deep, so should fail with maxCallDepth < 2 + 2| let f = x: x + 1; in f (f 0) + | ^ + 3| diff --git a/tests/functional2/lang/function-recursion/eval-fail-infrec.err.exp b/tests/functional2/lang/function-recursion/eval-fail-infrec.err.exp index ba5d38491..19a56a016 100644 --- a/tests/functional2/lang/function-recursion/eval-fail-infrec.err.exp +++ b/tests/functional2/lang/function-recursion/eval-fail-infrec.err.exp @@ -29,7 +29,7 @@ error: | ^ 2| - (19997 duplicate frames omitted) + (19995 duplicate frames omitted) error: stack overflow; max-call-depth exceeded at /pwd/in.nix:1:14: diff --git a/tests/functional2/lang/function-recursion/eval-okay-maxCallDepth.out.exp b/tests/functional2/lang/function-recursion/eval-okay-maxCallDepth.out.exp new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/tests/functional2/lang/function-recursion/eval-okay-maxCallDepth.out.exp @@ -0,0 +1 @@ +2 diff --git a/tests/functional2/lang/function-recursion/in-maxCallDepth.nix b/tests/functional2/lang/function-recursion/in-maxCallDepth.nix new file mode 100644 index 000000000..64a8aa6ce --- /dev/null +++ b/tests/functional2/lang/function-recursion/in-maxCallDepth.nix @@ -0,0 +1,2 @@ +# Exactly two function calls deep, so should fail with maxCallDepth < 2 +let f = x: x + 1; in f (f 0) diff --git a/tests/functional2/lang/function-recursion/test.toml b/tests/functional2/lang/function-recursion/test.toml new file mode 100644 index 000000000..8f7d6dcfe --- /dev/null +++ b/tests/functional2/lang/function-recursion/test.toml @@ -0,0 +1,21 @@ +[[test]] +runner = "eval-fail" +in = ["in-infrec.nix", "in-mutrec.nix"] +matrix = true + +[[test]] +runner = "eval-okay" +in = "in-maxCallDepth.nix" +flags = ["--option", "max-call-depth", "2"] + +[[test]] +name = "evail-fail-maxCallDepth1" +runner = "eval-fail" +in = "in-maxCallDepth.nix" +flags = ["--option", "max-call-depth", "1"] + +[[test]] +name = "evail-fail-maxCallDepth0" +runner = "eval-fail" +in = "in-maxCallDepth.nix" +flags = ["--option", "max-call-depth", "0"]