mirror of
https://github.com/NixOS/nix.git
synced 2025-11-24 11:19:35 +01:00
libexpr: fix stack overflow in deepSeq on deeply nested structures
builtins.deepSeq on deeply nested structures (e.g., a linked list with 100,000 elements) caused an uncontrolled OS-level stack overflow with no Nix stack trace. Fix by adding call depth tracking to forceValueDeep, 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. Closes: https://github.com/NixOS/nix/issues/7816
This commit is contained in:
parent
152e7e48c1
commit
59a566db13
3 changed files with 42 additions and 0 deletions
|
|
@ -2188,6 +2188,8 @@ void EvalState::forceValueDeep(Value & v)
|
||||||
std::set<const Value *> seen;
|
std::set<const Value *> seen;
|
||||||
|
|
||||||
[&, &state(*this)](this const auto & recurse, Value & v) {
|
[&, &state(*this)](this const auto & recurse, Value & v) {
|
||||||
|
auto _level = state.addCallDepth(v.determinePos(noPos));
|
||||||
|
|
||||||
if (!seen.insert(&v).second)
|
if (!seen.insert(&v).second)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
error:
|
||||||
|
… while calling the 'deepSeq' builtin
|
||||||
|
at /pwd/lang/eval-fail-deepseq-stack-overflow.nix:8:1:
|
||||||
|
7| in
|
||||||
|
8| builtins.deepSeq reverseLinkedList (
|
||||||
|
| ^
|
||||||
|
9| throw "unexpected success; expected a controlled stack overflow instead"
|
||||||
|
|
||||||
|
… while evaluating the attribute 'tail'
|
||||||
|
at /pwd/lang/eval-fail-deepseq-stack-overflow.nix:6:67:
|
||||||
|
5| long = builtins.genList (x: x) 100000;
|
||||||
|
6| reverseLinkedList = builtins.foldl' (tail: head: { inherit head tail; }) null long;
|
||||||
|
| ^
|
||||||
|
7| in
|
||||||
|
|
||||||
|
(9997 duplicate frames omitted)
|
||||||
|
|
||||||
|
… while evaluating the attribute 'head'
|
||||||
|
at /pwd/lang/eval-fail-deepseq-stack-overflow.nix:6:62:
|
||||||
|
5| long = builtins.genList (x: x) 100000;
|
||||||
|
6| reverseLinkedList = builtins.foldl' (tail: head: { inherit head tail; }) null long;
|
||||||
|
| ^
|
||||||
|
7| in
|
||||||
|
|
||||||
|
error: stack overflow; max-call-depth exceeded
|
||||||
|
at /pwd/lang/eval-fail-deepseq-stack-overflow.nix:5:28:
|
||||||
|
4| let
|
||||||
|
5| long = builtins.genList (x: x) 100000;
|
||||||
|
| ^
|
||||||
|
6| reverseLinkedList = builtins.foldl' (tail: head: { inherit head tail; }) null long;
|
||||||
10
tests/functional/lang/eval-fail-deepseq-stack-overflow.nix
Normal file
10
tests/functional/lang/eval-fail-deepseq-stack-overflow.nix
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Test that deepSeq on a deeply nested structure produces a controlled
|
||||||
|
# stack overflow error rather than a segfault.
|
||||||
|
|
||||||
|
let
|
||||||
|
long = builtins.genList (x: x) 100000;
|
||||||
|
reverseLinkedList = builtins.foldl' (tail: head: { inherit head tail; }) null long;
|
||||||
|
in
|
||||||
|
builtins.deepSeq reverseLinkedList (
|
||||||
|
throw "unexpected success; expected a controlled stack overflow instead"
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue