From 441aba48234d66b69d3c78e8d8a700ae88f50949 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 7 Nov 2025 10:41:17 +0100 Subject: [PATCH 1/5] Bump version --- .version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.version b/.version index 5506598e0f5..fb3a0677958 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.32.3 +2.32.4 From 287b54b49c52e2c34dc1c87681025d8ced98fa65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 7 Nov 2025 20:27:49 +0100 Subject: [PATCH 2/5] build: Disable libstdc++ TBB backend to avoid unnecessary dependency boost::concurrent_flat_map (used in libutil and libstore) includes the C++17 header. GCC's libstdc++ implements parallel algorithms using Intel TBB as the backend, which creates a link-time dependency on libtbb even though we don't actually use any parallel algorithms. Disable the TBB backend for libstdc++ by setting _GLIBCXX_USE_TBB_PAR_BACKEND=0. This makes parallel algorithms fall back to serial execution, which is acceptable since we don't use them anyway. This only affects libstdc++ (GCC's standard library); other standard libraries like libc++ (LLVM) are unaffected. (cherry picked from commit 2f3ec16793b4ad029254be1ae25e7824ec0c1a71) --- nix-meson-build-support/common/meson.build | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/nix-meson-build-support/common/meson.build b/nix-meson-build-support/common/meson.build index 595503f6149..23013d6ee2b 100644 --- a/nix-meson-build-support/common/meson.build +++ b/nix-meson-build-support/common/meson.build @@ -42,6 +42,26 @@ if cxx.get_id() == 'clang' add_project_arguments('-fpch-instantiate-templates', language : 'cpp') endif +# Detect if we're using libstdc++ (GCC's standard library) +# libstdc++ uses Intel TBB as backend for C++17 parallel algorithms when is included. +# boost::concurrent_flat_map includes , which would require linking against TBB. +# Since we don't actually use parallel algorithms, disable the TBB backend to avoid the dependency. +# TBB is a dependency of blake3 and leaking into our build environment. +is_using_libstdcxx = cxx.compiles( + ''' + #include + #ifndef __GLIBCXX__ + #error "not libstdc++" + #endif + int main() { return 0; } +''', + name : 'using libstdc++', +) + +if is_using_libstdcxx + add_project_arguments('-D_GLIBCXX_USE_TBB_PAR_BACKEND=0', language : 'cpp') +endif + # Darwin ld doesn't like "X.Y.ZpreABCD+W" nix_soversion = meson.project_version().split('+')[0].split('pre')[0] From b591265a05d177d998e74f50ccb5f2f366402597 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Sun, 9 Nov 2025 18:55:11 +0300 Subject: [PATCH 3/5] tests/functional: Add tests for builtins.dirOf These will change in the next commit to fix the silent regression from 2.23 in the handling of multiple subsequent path separators. (cherry picked from commit 86f090837b07e8dacf8f839f603a44768b2ed999) --- .../lang/eval-okay-builtins-dirOf.exp | 1 + .../lang/eval-okay-builtins-dirOf.nix | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/functional/lang/eval-okay-builtins-dirOf.exp create mode 100644 tests/functional/lang/eval-okay-builtins-dirOf.nix diff --git a/tests/functional/lang/eval-okay-builtins-dirOf.exp b/tests/functional/lang/eval-okay-builtins-dirOf.exp new file mode 100644 index 00000000000..1130b15108c --- /dev/null +++ b/tests/functional/lang/eval-okay-builtins-dirOf.exp @@ -0,0 +1 @@ +{ pathDoesntExistNested1 = /totallydoesntexistreally; pathDoesntExistNested2 = /totallydoesntexistreally/subdir1; pathDoesntExistRoot = /; pathRoot = /; stringEmpty = "."; stringMultipleSeps = "a"; stringNoSep = "."; stringRoot = "/"; stringRootA = "/"; stringRootSlash = "//"; stringRootSlashSlash = "///"; stringSingleDir = "a"; stringWithDot = "a/b/c/."; stringWithDotAndDotDot = "a/b/c/../."; stringWithDotAndDotDotSep2 = "a/b/c/../."; stringWithDotDot = "a/b/c/.."; stringWithDotDotSep2 = "a/b/c/.."; stringWithDotSep2 = "a/b/c/."; } diff --git a/tests/functional/lang/eval-okay-builtins-dirOf.nix b/tests/functional/lang/eval-okay-builtins-dirOf.nix new file mode 100644 index 00000000000..d2eae1c4ea5 --- /dev/null +++ b/tests/functional/lang/eval-okay-builtins-dirOf.nix @@ -0,0 +1,21 @@ +{ + stringEmpty = dirOf ""; + stringNoSep = dirOf "filename"; + stringSingleDir = dirOf "a/b"; + stringMultipleSeps = dirOf "a///b"; + stringRoot = dirOf "/"; + stringRootSlash = dirOf "//"; + stringRootSlashSlash = dirOf "///"; + stringRootA = dirOf "/a"; + stringWithDot = dirOf "a/b/c/./d"; + stringWithDotSep2 = dirOf "a/b/c/.//d"; + stringWithDotDot = dirOf "a/b/c/../d"; + stringWithDotDotSep2 = dirOf "a/b/c/..//d"; + stringWithDotAndDotDot = dirOf "a/b/c/.././d"; + stringWithDotAndDotDotSep2 = dirOf "a/b/c/.././/d"; + + pathRoot = dirOf /.; + pathDoesntExistRoot = dirOf /totallydoesntexistreally; + pathDoesntExistNested1 = dirOf /totallydoesntexistreally/subdir1; + pathDoesntExistNested2 = dirOf /totallydoesntexistreally/subdir1/subdir2; +} From be250f00b90c9c7debbd9428d6157a7f4ee77283 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Sun, 9 Nov 2025 18:33:03 +0300 Subject: [PATCH 4/5] libexpr: Don't use nix::dirOf in prim_dirOf This gets us back to pre-2.23 behavior of this primop. Done by inlining the code of `nix::dirOf` from 2.2-maintenance. (cherry picked from commit a33fccf55a8450f54c91c56a54d462ada57c7712) --- src/libexpr/primops.cc | 9 +++++++-- tests/functional/lang/eval-okay-builtins-dirOf.exp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 86cb001316c..2526ff5e1cc 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1973,8 +1973,13 @@ static void prim_dirOf(EvalState & state, const PosIdx pos, Value ** args, Value NixStringContext context; auto path = state.coerceToString( pos, *args[0], context, "while evaluating the first argument passed to 'builtins.dirOf'", false, false); - auto dir = dirOf(*path); - v.mkString(dir, context); + auto pos = path->rfind('/'); + if (pos == path->npos) + v.mkStringMove(".", context); + else if (pos == 0) + v.mkStringMove("/", context); + else + v.mkString(path->substr(0, pos), context); } } diff --git a/tests/functional/lang/eval-okay-builtins-dirOf.exp b/tests/functional/lang/eval-okay-builtins-dirOf.exp index 1130b15108c..e0093e93ab8 100644 --- a/tests/functional/lang/eval-okay-builtins-dirOf.exp +++ b/tests/functional/lang/eval-okay-builtins-dirOf.exp @@ -1 +1 @@ -{ pathDoesntExistNested1 = /totallydoesntexistreally; pathDoesntExistNested2 = /totallydoesntexistreally/subdir1; pathDoesntExistRoot = /; pathRoot = /; stringEmpty = "."; stringMultipleSeps = "a"; stringNoSep = "."; stringRoot = "/"; stringRootA = "/"; stringRootSlash = "//"; stringRootSlashSlash = "///"; stringSingleDir = "a"; stringWithDot = "a/b/c/."; stringWithDotAndDotDot = "a/b/c/../."; stringWithDotAndDotDotSep2 = "a/b/c/../."; stringWithDotDot = "a/b/c/.."; stringWithDotDotSep2 = "a/b/c/.."; stringWithDotSep2 = "a/b/c/."; } +{ pathDoesntExistNested1 = /totallydoesntexistreally; pathDoesntExistNested2 = /totallydoesntexistreally/subdir1; pathDoesntExistRoot = /; pathRoot = /; stringEmpty = "."; stringMultipleSeps = "a//"; stringNoSep = "."; stringRoot = "/"; stringRootA = "/"; stringRootSlash = "/"; stringRootSlashSlash = "//"; stringSingleDir = "a"; stringWithDot = "a/b/c/."; stringWithDotAndDotDot = "a/b/c/../."; stringWithDotAndDotDotSep2 = "a/b/c/.././"; stringWithDotDot = "a/b/c/.."; stringWithDotDotSep2 = "a/b/c/../"; stringWithDotSep2 = "a/b/c/./"; } From 46a43dede9f2ab60a600f6740a84ff2ec64583a8 Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Mon, 10 Nov 2025 21:12:07 +0300 Subject: [PATCH 5/5] Restore isAllowed check in ChrootLinuxDerivationBuilder This early return was lost in d4ef822add1074483627c5dbbaa9077f15daf7bc. By doing some https://en.wikipedia.org/wiki/Non-virtual_interface_pattern, we can ensure that we don't make this mistake again --- implementations are no longer responsible for implementing the caching/memoization mechanism. (cherry picked from commit 496e43ec72643ad4fc48ce15e6b7220763e823a8) --- .../include/nix/store/restricted-store.hh | 16 +++++++++++++++- src/libstore/unix/build/derivation-builder.cc | 7 ++----- .../unix/build/linux-derivation-builder.cc | 5 ++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/libstore/include/nix/store/restricted-store.hh b/src/libstore/include/nix/store/restricted-store.hh index 8bbb2ff54d7..62cac385675 100644 --- a/src/libstore/include/nix/store/restricted-store.hh +++ b/src/libstore/include/nix/store/restricted-store.hh @@ -52,7 +52,21 @@ struct RestrictionContext * Add 'path' to the set of paths that may be referenced by the * outputs, and make it appear in the sandbox. */ - virtual void addDependency(const StorePath & path) = 0; + void addDependency(const StorePath & path) + { + if (isAllowed(path)) + return; + addDependencyImpl(path); + } + +protected: + + /** + * This is the underlying implementation to be defined. The caller + * will ensure that this is only called on newly added dependencies, + * and that idempotent calls are a no-op. + */ + virtual void addDependencyImpl(const StorePath & path) = 0; }; /** diff --git a/src/libstore/unix/build/derivation-builder.cc b/src/libstore/unix/build/derivation-builder.cc index dc17b15cdc9..639db85a588 100644 --- a/src/libstore/unix/build/derivation-builder.cc +++ b/src/libstore/unix/build/derivation-builder.cc @@ -325,7 +325,7 @@ class DerivationBuilderImpl : public DerivationBuilder, public DerivationBuilder protected: - void addDependency(const StorePath & path) override; + void addDependencyImpl(const StorePath & path) override; /** * Make a file owned by the builder. @@ -1181,11 +1181,8 @@ void DerivationBuilderImpl::stopDaemon() daemonSocket.close(); } -void DerivationBuilderImpl::addDependency(const StorePath & path) +void DerivationBuilderImpl::addDependencyImpl(const StorePath & path) { - if (isAllowed(path)) - return; - addedPaths.insert(path); } diff --git a/src/libstore/unix/build/linux-derivation-builder.cc b/src/libstore/unix/build/linux-derivation-builder.cc index f6e910d08a9..b89c03890ab 100644 --- a/src/libstore/unix/build/linux-derivation-builder.cc +++ b/src/libstore/unix/build/linux-derivation-builder.cc @@ -703,8 +703,11 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu DerivationBuilderImpl::killSandbox(getStats); } - void addDependency(const StorePath & path) override + void addDependencyImpl(const StorePath & path) override { + if (isAllowed(path)) + return; + auto [source, target] = ChrootDerivationBuilder::addDependencyPrep(path); /* Bind-mount the path into the sandbox. This requires