From b21b3ad8513f1385ca7b112d06b99d3693b6e395 Mon Sep 17 00:00:00 2001 From: Damien Diederen Date: Tue, 18 Feb 2025 11:56:35 +0100 Subject: [PATCH] fix: Add missing context to builtins.{match,split} results Without this, it is easy to accidentally generate, e.g., a config file referencing a store path without recording proper dependency information. --- src/libexpr/primops.cc | 12 +++++------ .../lang/eval-okay-match-context.exp | 1 + .../lang/eval-okay-match-context.nix | 20 +++++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 tests/functional/lang/eval-okay-match-context.exp create mode 100644 tests/functional/lang/eval-okay-match-context.nix diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 51d2991e799..96fb8f74ad9 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -40,10 +40,10 @@ namespace nix { * Miscellaneous *************************************************************/ -static inline Value * mkString(EvalState & state, const std::csub_match & match) +static inline Value * mkString(EvalState & state, const std::csub_match & match, const NixStringContext & context) { Value * v = state.allocValue(); - v->mkString({match.first, match.second}); + v->mkString({match.first, match.second}, context); return v; } @@ -4318,7 +4318,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) if (!match[i + 1].matched) v2 = &state.vNull; else - v2 = mkString(state, match[i + 1]); + v2 = mkString(state, match[i + 1], context); v.mkList(list); } catch (std::regex_error & e) { @@ -4402,7 +4402,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) const auto & match = *i; // Add a string for non-matched characters. - list[idx++] = mkString(state, match.prefix()); + list[idx++] = mkString(state, match.prefix(), context); // Add a list for matched substrings. const size_t slen = match.size() - 1; @@ -4413,14 +4413,14 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) if (!match[si + 1].matched) v2 = &state.vNull; else - v2 = mkString(state, match[si + 1]); + v2 = mkString(state, match[si + 1], context); } (list[idx++] = state.allocValue())->mkList(list2); // Add a string for non-matched suffix characters. if (idx == 2 * len) - list[idx++] = mkString(state, match.suffix()); + list[idx++] = mkString(state, match.suffix(), context); } assert(idx == 2 * len + 1); diff --git a/tests/functional/lang/eval-okay-match-context.exp b/tests/functional/lang/eval-okay-match-context.exp new file mode 100644 index 00000000000..75f0013931c --- /dev/null +++ b/tests/functional/lang/eval-okay-match-context.exp @@ -0,0 +1 @@ +[ true true true ] diff --git a/tests/functional/lang/eval-okay-match-context.nix b/tests/functional/lang/eval-okay-match-context.nix new file mode 100644 index 00000000000..f436ad39d0f --- /dev/null +++ b/tests/functional/lang/eval-okay-match-context.nix @@ -0,0 +1,20 @@ +let + + s = "${builtins.derivation { + name = "test"; + builder = "/bin/sh"; + system = "x86_64-linux"; + }}"; + + c = builtins.getContext s; + + matchRes = builtins.match ".*(-).*" s; + + splitRes = builtins.split "(-)" s; + +in +[ + (c == builtins.getContext (builtins.head matchRes)) + (c == builtins.getContext (builtins.head splitRes)) + (c == builtins.getContext (builtins.head (builtins.elemAt splitRes 1))) +]