mirror of
https://github.com/NixOS/nix.git
synced 2025-11-12 21:46:01 +01:00
libexpr: Do not overflow heap buffer when there are too many formal arguments
3a3c062982 introduced a buffer overflow for the
case when there are more than 65535 formal arguments. It is a perfectly reasonable
limitation, but we *must* not crash, corrupt memory or otherwise crash the process.
Add a test for the graceful behavior and switch to using an explicit uninitialized_copy_n
to further guard against buffer overflows.
This commit is contained in:
parent
9d1907fff7
commit
134613e885
3 changed files with 40 additions and 8 deletions
|
|
@ -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