Skip to content

Commit bd11043

Browse files
authored
Merge pull request #14623 from Radvendii/exprcall-alloc-shvach
libexpr: plug ExprCall memory leak
2 parents 2bbec7d + dbfe631 commit bd11043

File tree

4 files changed

+21
-12
lines changed

4 files changed

+21
-12
lines changed

src/libexpr/eval.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,9 +1751,9 @@ void ExprCall::eval(EvalState & state, Env & env, Value & v)
17511751
// 4: about 60
17521752
// 5: under 10
17531753
// This excluded attrset lambdas (`{...}:`). Contributions of mixed lambdas appears insignificant at ~150 total.
1754-
SmallValueVector<4> vArgs(args.size());
1755-
for (size_t i = 0; i < args.size(); ++i)
1756-
vArgs[i] = args[i]->maybeThunk(state, env);
1754+
SmallValueVector<4> vArgs(args->size());
1755+
for (size_t i = 0; i < args->size(); ++i)
1756+
vArgs[i] = (*args)[i]->maybeThunk(state, env);
17571757

17581758
state.callFunction(vFun, vArgs, v, pos);
17591759
}

src/libexpr/include/nix/expr/nixexpr.hh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -592,19 +592,22 @@ public:
592592
struct ExprCall : Expr
593593
{
594594
Expr * fun;
595-
std::vector<Expr *> args;
595+
/**
596+
* args will never be null. See comment on ExprAttrs::AttrDefs below.
597+
*/
598+
std::optional<std::pmr::vector<Expr *>> args;
596599
PosIdx pos;
597600
std::optional<PosIdx> cursedOrEndPos; // used during parsing to warn about https://github.com/NixOS/nix/issues/11118
598601

599-
ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args)
602+
ExprCall(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args)
600603
: fun(fun)
601604
, args(args)
602605
, pos(pos)
603606
, cursedOrEndPos({})
604607
{
605608
}
606609

607-
ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args, PosIdx && cursedOrEndPos)
610+
ExprCall(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args, PosIdx && cursedOrEndPos)
608611
: fun(fun)
609612
, args(args)
610613
, pos(pos)
@@ -836,15 +839,15 @@ public:
836839
// we define some calls to add explicitly so that the argument can be passed in as initializer lists
837840
template<class C>
838841
[[gnu::always_inline]]
839-
C * add(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args)
842+
C * add(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args)
840843
requires(std::same_as<C, ExprCall>)
841844
{
842845
return alloc.new_object<C>(pos, fun, std::move(args));
843846
}
844847

845848
template<class C>
846849
[[gnu::always_inline]]
847-
C * add(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args, PosIdx && cursedOrEndPos)
850+
C * add(const PosIdx & pos, Expr * fun, std::pmr::vector<Expr *> && args, PosIdx && cursedOrEndPos)
848851
requires(std::same_as<C, ExprCall>)
849852
{
850853
return alloc.new_object<C>(pos, fun, std::move(args), std::move(cursedOrEndPos));

src/libexpr/nixexpr.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ void ExprCall::show(const SymbolTable & symbols, std::ostream & str) const
191191
{
192192
str << '(';
193193
fun->show(symbols, str);
194-
for (auto e : args) {
194+
for (auto e : *args) {
195195
str << ' ';
196196
e->show(symbols, str);
197197
}
@@ -486,11 +486,17 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv>
486486

487487
void ExprCall::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
488488
{
489+
// Move storage into the Exprs arena
490+
{
491+
auto arena = es.mem.exprs.alloc;
492+
std::pmr::vector<Expr *> newArgs{std::move(*args), arena};
493+
args.emplace(std::move(newArgs), arena);
494+
}
489495
if (es.debugRepl)
490496
es.exprEnvs.insert(std::make_pair(this, env));
491497

492498
fun->bindVars(es, env);
493-
for (auto e : args)
499+
for (auto e : *args)
494500
e->bindVars(es, env);
495501
}
496502

src/libexpr/parser.y

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ static void setDocPosition(const LexerState & lexerState, ExprLambda * lambda, P
115115

116116
static Expr * makeCall(Exprs & exprs, PosIdx pos, Expr * fn, Expr * arg) {
117117
if (auto e2 = dynamic_cast<ExprCall *>(fn)) {
118-
e2->args.push_back(arg);
118+
e2->args->push_back(arg);
119119
return fn;
120120
}
121121
return exprs.add<ExprCall>(pos, fn, {arg});
@@ -129,7 +129,7 @@ static Expr * makeCall(Exprs & exprs, PosIdx pos, Expr * fn, Expr * arg) {
129129
%type <Expr *> start expr expr_function expr_if expr_op
130130
%type <Expr *> expr_select expr_simple expr_app
131131
%type <Expr *> expr_pipe_from expr_pipe_into
132-
%type <std::vector<Expr *>> list
132+
%type <std::pmr::vector<Expr *>> list
133133
%type <ExprAttrs *> binds binds1
134134
%type <FormalsBuilder> formals formal_set
135135
%type <Formal> formal

0 commit comments

Comments
 (0)