libexpr: fix stack overflow in getDerivations on deeply nested structures

nix-instantiate on deeply nested structures with recurseForDerivations
(e.g., `let x = { recurseForDerivations = true; more = x; }; in x`)
caused an uncontrolled OS-level stack overflow with no Nix stack trace.

Fix by adding call depth tracking to getDerivations, integrating with
Nix's existing max-call-depth mechanism. Now produces a controlled
"stack overflow; max-call-depth exceeded" error with a proper stack
trace.
This commit is contained in:
Robert Hensing
2025-11-22 20:32:05 +01:00
parent c7e1c612eb
commit 5166cee704
2 changed files with 7 additions and 0 deletions

View File

@@ -378,6 +378,8 @@ static void getDerivations(
Done & done,
bool ignoreAssertionFailures)
{
auto _level = state.addCallDepth(vIn.determinePos(noPos));
Value v;
state.autoCallFunction(autoArgs, vIn, v);

View File

@@ -35,3 +35,8 @@ if test "$outPath" != "/foo/xxiwa5zlaajv6xdjynf9yym9g319d6mn-big-derivation-attr
echo "big-derivation-attr.nix hash appears broken, got $outPath. Memory corruption in large drv attr?"
exit 1
fi
# Test that nix-instantiate on a deeply nested recurseForDerivations structure
# produces a controlled stack overflow error rather than a segfault.
expectStderr 1 nix-instantiate --expr 'let x = { recurseForDerivations = true; more = x; }; in x' \
| grepQuiet "stack overflow; max-call-depth exceeded"