mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +02:00
correctly parse strings with null bytes and throw error
This commit is contained in:
parent
442a2623e4
commit
a44e9dd1ea
7 changed files with 22 additions and 13 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
BIN
tests/functional/lang/eval-fail-string-nul-1.err.exp
Normal file
BIN
tests/functional/lang/eval-fail-string-nul-1.err.exp
Normal file
Binary file not shown.
BIN
tests/functional/lang/eval-fail-string-nul-1.nix
Normal file
BIN
tests/functional/lang/eval-fail-string-nul-1.nix
Normal file
Binary file not shown.
BIN
tests/functional/lang/eval-fail-string-nul-2.err.exp
Normal file
BIN
tests/functional/lang/eval-fail-string-nul-2.err.exp
Normal file
Binary file not shown.
BIN
tests/functional/lang/eval-fail-string-nul-2.nix
Normal file
BIN
tests/functional/lang/eval-fail-string-nul-2.nix
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue