Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/libexpr-tests/trivial.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "nix/expr/tests/libexpr.hh"
#include "nix/util/tests/gmock-matchers.hh"

namespace nix {
// Testing of trivial expressions
Expand Down Expand Up @@ -160,7 +161,8 @@ TEST_F(TrivialExpressionTest, assertPassed)
ASSERT_THAT(v, IsIntEq(123));
}

class AttrSetMergeTrvialExpressionTest : public TrivialExpressionTest, public testing::WithParamInterface<const char *>
class AttrSetMergeTrvialExpressionTest : public TrivialExpressionTest,
public ::testing::WithParamInterface<const char *>
{};

TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
Expand Down Expand Up @@ -196,7 +198,7 @@ TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
INSTANTIATE_TEST_SUITE_P(
attrsetMergeLazy,
AttrSetMergeTrvialExpressionTest,
testing::Values("{ a.b = 1; a.c = 2; }", "{ a = { b = 1; }; a = { c = 2; }; }"));
::testing::Values("{ a.b = 1; a.c = 2; }", "{ a = { b = 1; }; a = { c = 2; }; }"));

// The following macros ultimately define 48 tests (16 variations on three
// templates). Each template tests an expression that can be written in 2^4
Expand Down Expand Up @@ -339,4 +341,18 @@ TEST_F(TrivialExpressionTest, orCantBeUsed)
{
ASSERT_THROW(eval("let or = 1; in or"), Error);
}

TEST_F(TrivialExpressionTest, tooManyFormals)
{
std::string expr = "let f = { ";
for (uint32_t i = 0; i <= std::numeric_limits<uint16_t>::max(); ++i) {
expr += fmt("arg%d, ", i);
}
expr += " }: 0 in; f {}";
ASSERT_THAT(
[&]() { eval(expr); },
::testing::ThrowsMessage<Error>(::nix::testing::HasSubstrIgnoreANSIMatcher(
"too many formal arguments, implementation supports at most 65535")));
}

} /* namespace nix */
22 changes: 19 additions & 3 deletions src/libexpr/include/nix/expr/nixexpr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "nix/expr/eval-error.hh"
#include "nix/util/pos-idx.hh"
#include "nix/expr/counter.hh"
#include "nix/util/pos-table.hh"
#include "nix/util/error.hh"

namespace nix {

Expand Down Expand Up @@ -535,6 +537,7 @@ public:
DocComment docComment;

ExprLambda(
const PosTable & positions,
std::pmr::polymorphic_allocator<char> & alloc,
PosIdx pos,
Symbol arg,
Expand All @@ -548,7 +551,15 @@ public:
, formalsStart(alloc.allocate_object<Formal>(nFormals))
, body(body)
{
std::ranges::copy(formals.formals, formalsStart);
if (formals.formals.size() > nFormals) [[unlikely]] {
auto err = Error(
"too many formal arguments, implementation supports at most %1%",
std::numeric_limits<decltype(nFormals)>::max());
if (pos)
err.atPos(positions[pos]);
throw err;
}
std::uninitialized_copy_n(formals.formals.begin(), nFormals, formalsStart);
};

ExprLambda(PosIdx pos, Symbol arg, Expr * body)
Expand All @@ -560,8 +571,13 @@ public:
, formalsStart(nullptr)
, body(body) {};

ExprLambda(std::pmr::polymorphic_allocator<char> & alloc, PosIdx pos, FormalsBuilder formals, Expr * body)
: ExprLambda(alloc, pos, Symbol(), formals, body) {};
ExprLambda(
const PosTable & positions,
std::pmr::polymorphic_allocator<char> & alloc,
PosIdx pos,
FormalsBuilder formals,
Expr * body)
: ExprLambda(positions, alloc, pos, Symbol(), formals, body) {};

void setName(Symbol name) override;
std::string showNamePos(const EvalState & state) const;
Expand Down
6 changes: 3 additions & 3 deletions src/libexpr/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -186,23 +186,23 @@ expr_function
| formal_set ':' expr_function[body]
{
state->validateFormals($formal_set);
auto me = new ExprLambda(state->alloc, CUR_POS, std::move($formal_set), $body);
auto me = new ExprLambda(state->positions, state->alloc, CUR_POS, std::move($formal_set), $body);
$$ = me;
SET_DOC_POS(me, @1);
}
| formal_set '@' ID ':' expr_function[body]
{
auto arg = state->symbols.create($ID);
state->validateFormals($formal_set, CUR_POS, arg);
auto me = new ExprLambda(state->alloc, CUR_POS, arg, std::move($formal_set), $body);
auto me = new ExprLambda(state->positions, state->alloc, CUR_POS, arg, std::move($formal_set), $body);
$$ = me;
SET_DOC_POS(me, @1);
}
| ID '@' formal_set ':' expr_function[body]
{
auto arg = state->symbols.create($ID);
state->validateFormals($formal_set, CUR_POS, arg);
auto me = new ExprLambda(state->alloc, CUR_POS, arg, std::move($formal_set), $body);
auto me = new ExprLambda(state->positions, state->alloc, CUR_POS, arg, std::move($formal_set), $body);
$$ = me;
SET_DOC_POS(me, @1);
}
Expand Down
Loading