From 908a011a4a2fe4e494e5b6e4c94f013f159f3616 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 1 Dec 2023 00:50:20 +0100 Subject: [PATCH 1/2] Revert "Switch from std::regex to boost::regex" --- flake.nix | 22 +++++++--------------- src/libexpr/local.mk | 2 +- src/libexpr/primops.cc | 35 ++++++++++++----------------------- 3 files changed, 20 insertions(+), 39 deletions(-) diff --git a/flake.nix b/flake.nix index 33673575b..822b3d31e 100644 --- a/flake.nix +++ b/flake.nix @@ -157,7 +157,7 @@ configureFlags = lib.optionals stdenv.isLinux [ - "--with-boost=${boost-nix}/lib" + "--with-boost=${boost}/lib" "--with-sandbox-shell=${sh}/bin/busybox" ] ++ lib.optionals (stdenv.isLinux && !(isStatic && stdenv.system == "aarch64-linux")) [ @@ -210,7 +210,7 @@ version = libgit2.lastModifiedDate; cmakeFlags = (attrs.cmakeFlags or []) ++ ["-DUSE_SSH=exec"]; })) - boost-nix + boost lowdown-nix libsodium ] @@ -434,14 +434,14 @@ propagatedBuildInputs = propagatedDeps; - disallowedReferences = [ boost-nix ]; + disallowedReferences = [ boost ]; preConfigure = lib.optionalString (! currentStdenv.hostPlatform.isStatic) '' # Copy libboost_context so we don't get all of Boost in our closure. # https://github.com/NixOS/nixpkgs/issues/45462 mkdir -p $out/lib - cp -pd ${boost-nix}/lib/{libboost_context*,libboost_thread*,libboost_system*,libboost_regex*} $out/lib + cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib rm -f $out/lib/*.a ${lib.optionalString currentStdenv.hostPlatform.isLinux '' chmod u+w $out/lib/*.so.* @@ -451,9 +451,9 @@ for LIB in $out/lib/*.dylib; do chmod u+w $LIB install_name_tool -id $LIB $LIB - install_name_tool -delete_rpath ${boost-nix}/lib/ $LIB || true + install_name_tool -delete_rpath ${boost}/lib/ $LIB || true done - install_name_tool -change ${boost-nix}/lib/libboost_system.dylib $out/lib/libboost_system.dylib $out/lib/libboost_thread.dylib + install_name_tool -change ${boost}/lib/libboost_system.dylib $out/lib/libboost_system.dylib $out/lib/libboost_thread.dylib ''} ''; @@ -481,13 +481,9 @@ ''} ${lib.optionalString currentStdenv.isDarwin '' install_name_tool \ - -change ${boost-nix}/lib/libboost_context.dylib \ + -change ${boost}/lib/libboost_context.dylib \ $out/lib/libboost_context.dylib \ $out/lib/libnixutil.dylib - install_name_tool \ - -change ${boost-nix}/lib/libboost_regex.dylib \ - $out/lib/libboost_regex.dylib \ - $out/lib/libnixexpr.dylib ''} ''; @@ -510,10 +506,6 @@ meta.mainProgram = "nix"; }); - boost-nix = final.boost.override { - enableIcu = false; - }; - lowdown-nix = with final; currentStdenv.mkDerivation rec { name = "lowdown-0.9.0"; diff --git a/src/libexpr/local.mk b/src/libexpr/local.mk index c07a18bb5..ed6bc761a 100644 --- a/src/libexpr/local.mk +++ b/src/libexpr/local.mk @@ -16,7 +16,7 @@ libexpr_CXXFLAGS += -I src/libutil -I src/libstore -I src/libfetchers -I src/lib libexpr_LIBS = libutil libstore libfetchers -libexpr_LDFLAGS += -lboost_context -lboost_regex -pthread +libexpr_LDFLAGS += -lboost_context -pthread ifdef HOST_LINUX libexpr_LDFLAGS += -ldl endif diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ebf2549e4..146a7603c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -17,7 +17,6 @@ #include "primops.hh" #include -#include #include #include @@ -26,6 +25,7 @@ #include #include +#include #include #include @@ -3886,30 +3886,19 @@ static RegisterPrimOp primop_convertHash({ .fun = prim_convertHash, }); -// regex aliases, switch between boost and std -using regex = boost::regex; -using regex_error = boost::regex_error; -using cmatch = boost::cmatch; -using cregex_iterator = boost::cregex_iterator; -namespace regex_constants = boost::regex_constants; -// overloaded function alias -constexpr auto regex_match = [] (auto &&...args) { - return boost::regex_match(std::forward(args)...); - }; - struct RegexCache { // TODO use C++20 transparent comparison when available - std::unordered_map cache; + std::unordered_map cache; std::list keys; - regex get(std::string_view re) + std::regex get(std::string_view re) { auto it = cache.find(re); if (it != cache.end()) return it->second; keys.emplace_back(re); - return cache.emplace(keys.back(), regex(keys.back(), regex::extended)).first->second; + return cache.emplace(keys.back(), std::regex(keys.back(), std::regex::extended)).first->second; } }; @@ -3929,8 +3918,8 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) NixStringContext context; const auto str = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.match"); - cmatch match; - if (!regex_match(str.begin(), str.end(), match, regex)) { + std::cmatch match; + if (!std::regex_match(str.begin(), str.end(), match, regex)) { v.mkNull(); return; } @@ -3945,8 +3934,8 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) (v.listElems()[i] = state.allocValue())->mkString(match[i + 1].str()); } - } catch (regex_error & e) { - if (e.code() == regex_constants::error_space) { + } catch (std::regex_error & e) { + if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ state.debugThrowLastTrace(EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), @@ -4009,8 +3998,8 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) NixStringContext context; const auto str = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.split"); - auto begin = cregex_iterator(str.begin(), str.end(), regex); - auto end = cregex_iterator(); + auto begin = std::cregex_iterator(str.begin(), str.end(), regex); + auto end = std::cregex_iterator(); // Any matches results are surrounded by non-matching results. const size_t len = std::distance(begin, end); @@ -4049,8 +4038,8 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) assert(idx == 2 * len + 1); - } catch (regex_error & e) { - if (e.code() == regex_constants::error_space) { + } catch (std::regex_error & e) { + if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ state.debugThrowLastTrace(EvalError({ .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), From 333ea684b065318aa49aec367c995b3d8c5d65ed Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 1 Dec 2023 01:39:52 +0100 Subject: [PATCH 2/2] Add boost::regex regression test --- src/libexpr/tests/primops.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libexpr/tests/primops.cc b/src/libexpr/tests/primops.cc index d820b860e..7485fa0d0 100644 --- a/src/libexpr/tests/primops.cc +++ b/src/libexpr/tests/primops.cc @@ -814,6 +814,14 @@ namespace nix { ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO")); } + TEST_F(PrimOpTest, match5) { + // The regex "\\{}" is valid and matches the string "{}". + // Caused a regression before when trying to switch from std::regex to boost::regex. + // See https://github.com/NixOS/nix/pull/7762#issuecomment-1834303659 + auto v = eval("builtins.match \"\\\\{}\" \"{}\""); + ASSERT_THAT(v, IsListOfSize(0)); + } + TEST_F(PrimOpTest, attrNames) { auto v = eval("builtins.attrNames { x = 1; y = 2; z = 3; a = 2; }"); ASSERT_THAT(v, IsListOfSize(4));