1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-02 13:31:48 +02:00

Merge remote-tracking branch 'origin/master' into relative-flakes

This commit is contained in:
Eelco Dolstra 2025-01-13 14:13:56 +01:00
commit cd0127f957
112 changed files with 2268 additions and 434 deletions

View file

@ -3185,12 +3185,16 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) {
return v.print(str);
}
void forceNoNullByte(std::string_view s)
void forceNoNullByte(std::string_view s, std::function<Pos()> pos)
{
if (s.find('\0') != s.npos) {
using namespace std::string_view_literals;
auto str = replaceStrings(std::string(s), "\0"sv, ""sv);
throw Error("input string '%s' cannot be represented as Nix string because it contains null bytes", str);
Error error("input string '%s' cannot be represented as Nix string because it contains null bytes", str);
if (pos) {
error.atPos(pos());
}
throw error;
}
}

View file

@ -41,16 +41,18 @@ namespace nix {
// we make use of the fact that the parser receives a private copy of the input
// string and can munge around in it.
static StringToken unescapeStr(SymbolTable & symbols, char * s, size_t length)
// getting the position is expensive and thus it is implemented lazily.
static StringToken unescapeStr(char * const s, size_t length, std::function<Pos()> && pos)
{
char * result = s;
bool noNullByte = true;
char * t = s;
char c;
// the input string is terminated with *two* NULs, so we can safely take
// *one* character after the one being checked against.
while ((c = *s++)) {
for (size_t i = 0; i < length; t++) {
char c = s[i++];
noNullByte &= c != '\0';
if (c == '\\') {
c = *s++;
c = s[i++];
if (c == 'n') *t = '\n';
else if (c == 'r') *t = '\r';
else if (c == 't') *t = '\t';
@ -59,12 +61,14 @@ static StringToken unescapeStr(SymbolTable & symbols, char * s, size_t length)
else if (c == '\r') {
/* Normalise CR and CR/LF into LF. */
*t = '\n';
if (*s == '\n') s++; /* cr/lf */
if (s[i] == '\n') i++; /* cr/lf */
}
else *t = c;
t++;
}
return {result, size_t(t - result)};
if (!noNullByte) {
forceNoNullByte({s, size_t(t - s)}, std::move(pos));
}
return {s, size_t(t - s)};
}
static void requireExperimentalFeature(const ExperimentalFeature & feature, const Pos & pos)
@ -175,7 +179,7 @@ or { return OR_KW; }
/* It is impossible to match strings ending with '$' with one
regex because trailing contexts are only valid at the end
of a rule. (A sane but undocumented limitation.) */
yylval->str = unescapeStr(state->symbols, yytext, yyleng);
yylval->str = unescapeStr(yytext, yyleng, [&]() { return state->positions[CUR_POS]; });
return STR;
}
<STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }
@ -191,6 +195,7 @@ or { return OR_KW; }
\'\'(\ *\n)? { PUSH_STATE(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
yylval->str = {yytext, (size_t) yyleng, true};
forceNoNullByte(yylval->str, [&]() { return state->positions[CUR_POS]; });
return IND_STR;
}
<IND_STRING>\'\'\$ |
@ -203,7 +208,7 @@ or { return OR_KW; }
return IND_STR;
}
<IND_STRING>\'\'\\{ANY} {
yylval->str = unescapeStr(state->symbols, yytext + 2, yyleng - 2);
yylval->str = unescapeStr(yytext + 2, yyleng - 2, [&]() { return state->positions[CUR_POS]; });
return IND_STR;
}
<IND_STRING>\$\{ { PUSH_STATE(DEFAULT); return DOLLAR_CURLY; }

View file

@ -4,8 +4,6 @@ project('nix-expr', 'cpp',
'cpp_std=c++2a',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'debug=true',
'optimization=2',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.1',

View file

@ -2045,7 +2045,7 @@ static RegisterPrimOp primop_readFileType({
.args = {"p"},
.doc = R"(
Determine the directory entry type of a filesystem node, being
one of "directory", "regular", "symlink", or "unknown".
one of `"directory"`, `"regular"`, `"symlink"`, or `"unknown"`.
)",
.fun = prim_readFileType,
});
@ -4059,7 +4059,7 @@ static RegisterPrimOp primop_toString({
});
/* `substring start len str' returns the substring of `str' starting
at character position `min(start, stringLength str)' inclusive and
at byte position `min(start, stringLength str)' inclusive and
ending at `min(start + len, stringLength str)'. `start' must be
non-negative. */
static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
@ -4098,7 +4098,7 @@ static RegisterPrimOp primop_substring({
.name = "__substring",
.args = {"start", "len", "s"},
.doc = R"(
Return the substring of *s* from character position *start*
Return the substring of *s* from byte position *start*
(zero-based) up to but not including *start + len*. If *start* is
greater than the length of the string, an empty string is returned.
If *start + len* lies beyond the end of the string or *len* is `-1`,

View file

@ -108,7 +108,11 @@ json printValueAsJSON(EvalState & state, bool strict,
void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore)
{
str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
try {
str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
} catch (nlohmann::json::exception & e) {
throw JSONSerializationError("JSON serialization error: %s", e.what());
}
}
json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,

View file

@ -16,4 +16,7 @@ nlohmann::json printValueAsJSON(EvalState & state, bool strict,
void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, NixStringContext & context, bool copyToStore = true);
MakeError(JSONSerializationError, Error);
}

View file

@ -510,6 +510,6 @@ typedef std::shared_ptr<Value *> RootValue;
RootValue allocRootValue(Value * v);
void forceNoNullByte(std::string_view s);
void forceNoNullByte(std::string_view s, std::function<Pos()> = nullptr);
}