Ensure that files are parsed/evaluated only once (2nd attempt)#14040
Conversation
|
I was hitting this test failure on cygwin: And I tracked it to the leaking of the This sort of thing has happened before (#14576), and it's quite difficult to track down. I wonder if we should assert that the store is actually being destroyed with In terms of working around this, would it be safe to store the pointers in EvalState and delete them in the destructor? edit: something like this commit 868b29c39a7c2e2dd8722a9e7208f193779a9e05
Author: David McFarland <corngood@gmail.com>
Date: Fri Jan 9 15:53:46 2026 -0400
Fix leak in EvalState::evalFile
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 84f14198f..40f0b4b7b 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -1129,14 +1129,14 @@ void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
// https://github.com/NixOS/nix/pull/13930 is merged. That will ensure
// the post-condition that `expr` is unreachable after
// `forceValue()` returns.
- auto expr = new ExprParseFile{*resolvedPath, mustBeTrivial};
+ auto expr = parseFileExprs.emplace_back(std::make_shared<ExprParseFile>(*resolvedPath, mustBeTrivial));
fileEvalCache->try_emplace_and_cvisit(
*resolvedPath,
nullptr,
[&](auto & i) {
vExpr = allocValue();
- vExpr->mkThunk(&baseEnv, expr);
+ vExpr->mkThunk(&baseEnv, expr.get());
i.second = vExpr;
},
[&](auto & i) { vExpr = i.second; });
diff --git a/src/libexpr/include/nix/expr/eval.hh b/src/libexpr/include/nix/expr/eval.hh
index b70c9db78..ae6e32505 100644
--- a/src/libexpr/include/nix/expr/eval.hh
+++ b/src/libexpr/include/nix/expr/eval.hh
@@ -366,6 +366,8 @@ private:
Statistics stats;
};
+struct ExprParseFile;
+
class EvalState : public std::enable_shared_from_this<EvalState>
{
public:
@@ -508,6 +510,8 @@ private:
*/
const ref<RegexCache> regexCache;
+ std::vector<std::shared_ptr<ExprParseFile> > parseFileExprs;
+
public:
/** |
Ideally we'd just enable leak sanitizer once all parser leaks are fully plugged. Not sure about the status of that currently, but we should be closer to that now. |
|
CC @Radvendii |
Motivation
Fixes the segfault in #13938 that necessitated the revert in #14013.
ExprParseFileis allocated on the heap for now. We can put it back on the stack once if #13930 is merged (since it ensures the postcondition that the expr is unreachable afterforceValue()returns).Context
Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.