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)))
+]