mirror of
https://github.com/NixOS/nix.git
synced 2025-11-08 19:46:02 +01:00
Merge pull request #14439 from NixOS/no-buffer-overflows
libexpr: Do not overflow heap buffer when there are too many formal a…
This commit is contained in:
commit
6fa7510055
3 changed files with 40 additions and 8 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#include "nix/expr/tests/libexpr.hh"
|
||||
#include "nix/util/tests/gmock-matchers.hh"
|
||||
|
||||
namespace nix {
|
||||
// Testing of trivial expressions
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
@ -535,6 +537,7 @@ public:
|
|||
DocComment docComment;
|
||||
|
||||
ExprLambda(
|
||||
const PosTable & positions,
|
||||
std::pmr::polymorphic_allocator<char> & alloc,
|
||||
PosIdx pos,
|
||||
Symbol arg,
|
||||
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ 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);
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ expr_function
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
@ -202,7 +202,7 @@ expr_function
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue