Merge pull request #9747 from awakesecurity/mz/fix-quadratic-splitString
Fix performance of builtins.substring for empty substrings
(cherry picked from commit b2deff1947c2fe57fdbf1a472eb9003eb407f8d3)
Change-Id: I4ddfc8d26a4781c9520fff9807849a073ee7bed8
This commit is contained in:
parent
64b077cdaa
commit
2c85fcce87
|
@ -3700,9 +3700,6 @@ static RegisterPrimOp primop_toString({
|
|||
static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
int start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring");
|
||||
int len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring");
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[2], context, "while evaluating the third argument (the string) passed to builtins.substring");
|
||||
|
||||
if (start < 0)
|
||||
state.debugThrowLastTrace(EvalError({
|
||||
|
@ -3710,6 +3707,22 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value * * args,
|
|||
.errPos = state.positions[pos]
|
||||
}));
|
||||
|
||||
|
||||
int len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring");
|
||||
|
||||
// Special-case on empty substring to avoid O(n) strlen
|
||||
// This allows for the use of empty substrings to efficently capture string context
|
||||
if (len == 0) {
|
||||
state.forceValue(*args[2], pos);
|
||||
if (args[2]->type() == nString) {
|
||||
v.mkString("", args[2]->string.context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[2], context, "while evaluating the third argument (the string) passed to builtins.substring");
|
||||
|
||||
v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context);
|
||||
}
|
||||
|
||||
|
|
1
tests/functional/lang/eval-okay-substring-context.exp
Normal file
1
tests/functional/lang/eval-okay-substring-context.exp
Normal file
|
@ -0,0 +1 @@
|
|||
"okay"
|
11
tests/functional/lang/eval-okay-substring-context.nix
Normal file
11
tests/functional/lang/eval-okay-substring-context.nix
Normal file
|
@ -0,0 +1,11 @@
|
|||
with builtins;
|
||||
|
||||
let
|
||||
|
||||
s = "${builtins.derivation { name = "test"; builder = "/bin/sh"; system = "x86_64-linux"; }}";
|
||||
|
||||
in
|
||||
|
||||
if getContext s == getContext "${substring 0 0 s + unsafeDiscardStringContext s}"
|
||||
then "okay"
|
||||
else throw "empty substring should preserve context"
|
Loading…
Reference in a new issue