From 6e78cc90d3415694ec15bd273b47d21bb1be96ad Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Fri, 11 Jul 2025 20:20:48 +0300 Subject: [PATCH] libexpr: Fix invalid handling of errors for imported functions c39cc004043b95d55a0c2c2bdba58d6d3e0db846 has added assertions for all Value accesses and the following case has started failing with an `unreachable`: (/tmp/fun.nix): ```nix {a}: a ``` ``` $ nix eval --impure --expr 'import /tmp/fun.nix {a="a";b="b";}' ``` This would crash: ``` terminating due to unexpected unrecoverable internal error: Unexpected condition in getStorage at ../include/nix/expr/value.hh:844 ``` This is not a regression, but rather surfaces an existing problem, which previously was left undiagnosed. In the case of an import `fun` is the `import` primOp, so that read is invalid and previously this resulted in an access into an inactive union member, which is UB. The correct thing to use is `vCur`. Identical problem also affected the case of a missing argument. Add previously failing test cases to the functional/lang test suite. Fixes #13448. --- src/libexpr/eval.cc | 4 ++-- .../lang/eval-fail-missing-arg-import.err.exp | 12 ++++++++++++ .../lang/eval-fail-missing-arg-import.nix | 1 + .../lang/eval-fail-undeclared-arg-import.err.exp | 13 +++++++++++++ .../lang/eval-fail-undeclared-arg-import.nix | 4 ++++ .../lang/non-eval-trivial-lambda-formals.nix | 1 + 6 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/functional/lang/eval-fail-missing-arg-import.err.exp create mode 100644 tests/functional/lang/eval-fail-missing-arg-import.nix create mode 100644 tests/functional/lang/eval-fail-undeclared-arg-import.err.exp create mode 100644 tests/functional/lang/eval-fail-undeclared-arg-import.nix create mode 100644 tests/functional/lang/non-eval-trivial-lambda-formals.nix diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 1321e00a5..47cc35daa 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1602,7 +1602,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, symbols[i.name]) .atPos(lambda.pos) .withTrace(pos, "from call site") - .withFrame(*fun.lambda().env, lambda) + .withFrame(*vCur.lambda().env, lambda) .debugThrow(); } env2.values[displ++] = i.def->maybeThunk(*this, env2); @@ -1629,7 +1629,7 @@ void EvalState::callFunction(Value & fun, std::span args, Value & vRes, .atPos(lambda.pos) .withTrace(pos, "from call site") .withSuggestions(suggestions) - .withFrame(*fun.lambda().env, lambda) + .withFrame(*vCur.lambda().env, lambda) .debugThrow(); } unreachable(); diff --git a/tests/functional/lang/eval-fail-missing-arg-import.err.exp b/tests/functional/lang/eval-fail-missing-arg-import.err.exp new file mode 100644 index 000000000..45774f003 --- /dev/null +++ b/tests/functional/lang/eval-fail-missing-arg-import.err.exp @@ -0,0 +1,12 @@ +error: + … from call site + at /pwd/lang/eval-fail-missing-arg-import.nix:1:1: + 1| import ./non-eval-trivial-lambda-formals.nix { } + | ^ + 2| + + error: function 'anonymous lambda' called without required argument 'a' + at /pwd/lang/non-eval-trivial-lambda-formals.nix:1:1: + 1| { a }: a + | ^ + 2| diff --git a/tests/functional/lang/eval-fail-missing-arg-import.nix b/tests/functional/lang/eval-fail-missing-arg-import.nix new file mode 100644 index 000000000..7cb33f2b5 --- /dev/null +++ b/tests/functional/lang/eval-fail-missing-arg-import.nix @@ -0,0 +1 @@ +import ./non-eval-trivial-lambda-formals.nix { } diff --git a/tests/functional/lang/eval-fail-undeclared-arg-import.err.exp b/tests/functional/lang/eval-fail-undeclared-arg-import.err.exp new file mode 100644 index 000000000..ca797d3ec --- /dev/null +++ b/tests/functional/lang/eval-fail-undeclared-arg-import.err.exp @@ -0,0 +1,13 @@ +error: + … from call site + at /pwd/lang/eval-fail-undeclared-arg-import.nix:1:1: + 1| import ./non-eval-trivial-lambda-formals.nix { + | ^ + 2| a = "a"; + + error: function 'anonymous lambda' called with unexpected argument 'b' + at /pwd/lang/non-eval-trivial-lambda-formals.nix:1:1: + 1| { a }: a + | ^ + 2| + Did you mean a? diff --git a/tests/functional/lang/eval-fail-undeclared-arg-import.nix b/tests/functional/lang/eval-fail-undeclared-arg-import.nix new file mode 100644 index 000000000..e8454c725 --- /dev/null +++ b/tests/functional/lang/eval-fail-undeclared-arg-import.nix @@ -0,0 +1,4 @@ +import ./non-eval-trivial-lambda-formals.nix { + a = "a"; + b = "b"; +} diff --git a/tests/functional/lang/non-eval-trivial-lambda-formals.nix b/tests/functional/lang/non-eval-trivial-lambda-formals.nix new file mode 100644 index 000000000..46a7ea4f4 --- /dev/null +++ b/tests/functional/lang/non-eval-trivial-lambda-formals.nix @@ -0,0 +1 @@ +{ a }: a