mirror of
https://github.com/NixOS/nix.git
synced 2025-11-09 03:56:01 +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/expr/tests/libexpr.hh"
|
||||||
|
#include "nix/util/tests/gmock-matchers.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
// Testing of trivial expressions
|
// Testing of trivial expressions
|
||||||
|
|
@ -160,7 +161,8 @@ TEST_F(TrivialExpressionTest, assertPassed)
|
||||||
ASSERT_THAT(v, IsIntEq(123));
|
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)
|
TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
|
||||||
|
|
@ -196,7 +198,7 @@ TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy)
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
attrsetMergeLazy,
|
attrsetMergeLazy,
|
||||||
AttrSetMergeTrvialExpressionTest,
|
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
|
// The following macros ultimately define 48 tests (16 variations on three
|
||||||
// templates). Each template tests an expression that can be written in 2^4
|
// 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);
|
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 */
|
} /* namespace nix */
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
#include "nix/expr/eval-error.hh"
|
#include "nix/expr/eval-error.hh"
|
||||||
#include "nix/util/pos-idx.hh"
|
#include "nix/util/pos-idx.hh"
|
||||||
#include "nix/expr/counter.hh"
|
#include "nix/expr/counter.hh"
|
||||||
|
#include "nix/util/pos-table.hh"
|
||||||
|
#include "nix/util/error.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
@ -535,6 +537,7 @@ public:
|
||||||
DocComment docComment;
|
DocComment docComment;
|
||||||
|
|
||||||
ExprLambda(
|
ExprLambda(
|
||||||
|
const PosTable & positions,
|
||||||
std::pmr::polymorphic_allocator<char> & alloc,
|
std::pmr::polymorphic_allocator<char> & alloc,
|
||||||
PosIdx pos,
|
PosIdx pos,
|
||||||
Symbol arg,
|
Symbol arg,
|
||||||
|
|
@ -548,7 +551,15 @@ public:
|
||||||
, formalsStart(alloc.allocate_object<Formal>(nFormals))
|
, formalsStart(alloc.allocate_object<Formal>(nFormals))
|
||||||
, body(body)
|
, 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)
|
ExprLambda(PosIdx pos, Symbol arg, Expr * body)
|
||||||
|
|
@ -560,8 +571,13 @@ public:
|
||||||
, formalsStart(nullptr)
|
, formalsStart(nullptr)
|
||||||
, body(body) {};
|
, body(body) {};
|
||||||
|
|
||||||
ExprLambda(std::pmr::polymorphic_allocator<char> & alloc, PosIdx pos, FormalsBuilder formals, Expr * body)
|
ExprLambda(
|
||||||
: ExprLambda(alloc, pos, Symbol(), formals, body) {};
|
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;
|
void setName(Symbol name) override;
|
||||||
std::string showNamePos(const EvalState & state) const;
|
std::string showNamePos(const EvalState & state) const;
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ expr_function
|
||||||
| formal_set ':' expr_function[body]
|
| formal_set ':' expr_function[body]
|
||||||
{
|
{
|
||||||
state->validateFormals($formal_set);
|
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;
|
$$ = me;
|
||||||
SET_DOC_POS(me, @1);
|
SET_DOC_POS(me, @1);
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ expr_function
|
||||||
{
|
{
|
||||||
auto arg = state->symbols.create($ID);
|
auto arg = state->symbols.create($ID);
|
||||||
state->validateFormals($formal_set, CUR_POS, arg);
|
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;
|
$$ = me;
|
||||||
SET_DOC_POS(me, @1);
|
SET_DOC_POS(me, @1);
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +202,7 @@ expr_function
|
||||||
{
|
{
|
||||||
auto arg = state->symbols.create($ID);
|
auto arg = state->symbols.create($ID);
|
||||||
state->validateFormals($formal_set, CUR_POS, arg);
|
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;
|
$$ = me;
|
||||||
SET_DOC_POS(me, @1);
|
SET_DOC_POS(me, @1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue