diff options
-rw-r--r-- | doc/manual/src/language/advanced-attributes.md | 6 | ||||
-rw-r--r-- | package.nix | 16 | ||||
-rw-r--r-- | src/libexpr/eval.cc | 14 | ||||
-rw-r--r-- | src/libexpr/eval.hh | 13 | ||||
-rw-r--r-- | src/libexpr/parser/parser.cc | 6 | ||||
-rw-r--r-- | src/libexpr/parser/state.hh | 1 | ||||
-rw-r--r-- | src/libexpr/primops.cc | 14 | ||||
-rw-r--r-- | src/libstore/build/local-derivation-goal.cc | 18 | ||||
-rw-r--r-- | tests/functional/lang/eval-okay-derivation-legacy.err.exp | 6 | ||||
-rw-r--r-- | tests/functional/lang/eval-okay-derivation-legacy.exp | 1 | ||||
-rw-r--r-- | tests/functional/lang/eval-okay-derivation-legacy.nix | 12 | ||||
-rw-r--r-- | tests/unit/libexpr-support/tests/libexpr.hh | 4 | ||||
-rw-r--r-- | tests/unit/libexpr/trivial.cc | 17 |
13 files changed, 107 insertions, 21 deletions
diff --git a/doc/manual/src/language/advanced-attributes.md b/doc/manual/src/language/advanced-attributes.md index e9006a3ae..ee93f5672 100644 --- a/doc/manual/src/language/advanced-attributes.md +++ b/doc/manual/src/language/advanced-attributes.md @@ -292,6 +292,12 @@ Derivations can declare some infrequently used optional attributes. (associative) arrays. For example, the attribute `hardening.format = true` ends up as the Bash associative array element `${hardening[format]}`. + > **Warning** + > + > If set to `true`, other advanced attributes such as [`allowedReferences`](#adv-attr-allowedReferences), [`allowedReferences`](#adv-attr-allowedReferences), [`allowedRequisites`](#adv-attr-allowedRequisites), + [`disallowedReferences`](#adv-attr-disallowedReferences) and [`disallowedRequisites`](#adv-attr-disallowedRequisites), maxSize, and maxClosureSize. + will have no effect. + - [`outputChecks`]{#adv-attr-outputChecks}\ When using [structured attributes](#adv-attr-structuredAttrs), the `outputChecks` attribute allows defining checks per-output. diff --git a/package.nix b/package.nix index 0f006fef4..be2f0010d 100644 --- a/package.nix +++ b/package.nix @@ -58,8 +58,11 @@ buildUnreleasedNotes ? true, internalApiDocs ? false, + # Support garbage collection in the evaluator. + enableGC ? sanitize == null || !builtins.elem "address" sanitize, # List of Meson sanitize options. Accepts values of b_sanitize, e.g. # "address", "undefined", "thread". + # Enabling the "address" sanitizer will disable garbage collection in the evaluator. sanitize ? null, # Turn compiler warnings into errors. werror ? false, @@ -118,10 +121,7 @@ let # The internal API docs need these for the build, but if we're not building # Nix itself, then these don't need to be propagated. - maybePropagatedInputs = [ - boehmgc-nix - nlohmann_json - ]; + maybePropagatedInputs = lib.optional enableGC boehmgc-nix ++ [ nlohmann_json ]; # .gitignore has already been processed, so any changes in it are irrelevant # at this point. It is not represented verbatim for test purposes because @@ -179,10 +179,9 @@ stdenv.mkDerivation (finalAttrs: { mesonFlags = let - sanitizeOpts = lib.optionals (sanitize != null) ( - [ "-Db_sanitize=${builtins.concatStringsSep "," sanitize}" ] - ++ lib.optional (builtins.elem "address" sanitize) "-Dgc=disabled" - ); + sanitizeOpts = lib.optional ( + sanitize != null + ) "-Db_sanitize=${builtins.concatStringsSep "," sanitize}"; in lib.optionals hostPlatform.isLinux [ # You'd think meson could just find this in PATH, but busybox is in buildInputs, @@ -196,6 +195,7 @@ stdenv.mkDerivation (finalAttrs: { # mesonConfigurePhase automatically passes -Dauto_features=enabled, # so we must explicitly enable or disable features that we are not passing # dependencies for. + (lib.mesonEnable "gc" enableGC) (lib.mesonEnable "internal-api-docs" internalApiDocs) (lib.mesonBool "enable-tests" finalAttrs.finalPackage.doCheck) (lib.mesonBool "enable-docs" canRunInstalled) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index a925ce2d8..741a24e3c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -249,6 +249,12 @@ EvalState::EvalState( , sRight(symbols.create("right")) , sWrong(symbols.create("wrong")) , sStructuredAttrs(symbols.create("__structuredAttrs")) + , sAllowedReferences(symbols.create("allowedReferences")) + , sAllowedRequisites(symbols.create("allowedRequisites")) + , sDisallowedReferences(symbols.create("disallowedReferences")) + , sDisallowedRequisites(symbols.create("disallowedRequisites")) + , sMaxSize(symbols.create("maxSize")) + , sMaxClosureSize(symbols.create("maxClosureSize")) , sBuilder(symbols.create("builder")) , sArgs(symbols.create("args")) , sContentAddressed(symbols.create("__contentAddressed")) @@ -2802,20 +2808,20 @@ Expr & EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<Sta } -Expr & EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv) +Expr & EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv, const ExperimentalFeatureSettings & xpSettings) { // NOTE this method (and parseStdin) must take care to *fully copy* their input // into their respective Pos::Origin until the parser stops overwriting its input // data. auto s = make_ref<std::string>(s_); s_.append("\0\0", 2); - return *parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv); + return *parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv, xpSettings); } -Expr & EvalState::parseExprFromString(std::string s, const SourcePath & basePath) +Expr & EvalState::parseExprFromString(std::string s, const SourcePath & basePath, const ExperimentalFeatureSettings & xpSettings) { - return parseExprFromString(std::move(s), basePath, staticBaseEnv); + return parseExprFromString(std::move(s), basePath, staticBaseEnv, xpSettings); } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index e54eede40..ff45efc08 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -13,7 +13,6 @@ #include "search-path.hh" #include "repl-exit-status.hh" -#include <gc/gc_allocator.h> #include <map> #include <optional> #include <unordered_map> @@ -162,7 +161,10 @@ public: const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, sFile, sLine, sColumn, sFunctor, sToString, - sRight, sWrong, sStructuredAttrs, sBuilder, sArgs, + sRight, sWrong, sStructuredAttrs, + sAllowedReferences, sAllowedRequisites, sDisallowedReferences, sDisallowedRequisites, + sMaxSize, sMaxClosureSize, + sBuilder, sArgs, sContentAddressed, sImpure, sOutputHash, sOutputHashAlgo, sOutputHashMode, sRecurseForDerivations, @@ -342,8 +344,8 @@ public: /** * Parse a Nix expression from the specified string. */ - Expr & parseExprFromString(std::string s, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv); - Expr & parseExprFromString(std::string s, const SourcePath & basePath); + Expr & parseExprFromString(std::string s, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); + Expr & parseExprFromString(std::string s, const SourcePath & basePath, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); Expr & parseStdin(); @@ -566,7 +568,8 @@ private: size_t length, Pos::Origin origin, const SourcePath & basePath, - std::shared_ptr<StaticEnv> & staticEnv); + std::shared_ptr<StaticEnv> & staticEnv, + const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings); /** * Current Nix call stack depth, used with `max-call-depth` setting to throw stack overflow hopefully before we run out of system stack. diff --git a/src/libexpr/parser/parser.cc b/src/libexpr/parser/parser.cc index b7a105fe7..68aa3ddc5 100644 --- a/src/libexpr/parser/parser.cc +++ b/src/libexpr/parser/parser.cc @@ -631,7 +631,7 @@ template<> struct BuildAST<grammar::expr::path> : p::maybe_nothing {}; template<> struct BuildAST<grammar::expr::uri> { static void apply(const auto & in, ExprState & s, State & ps) { - static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals); + bool noURLLiterals = ps.xpSettings.isEnabled(Xp::NoUrlLiterals); if (noURLLiterals) throw ParseError({ .msg = HintFmt("URL literals are disabled"), @@ -832,7 +832,8 @@ Expr * EvalState::parse( size_t length, Pos::Origin origin, const SourcePath & basePath, - std::shared_ptr<StaticEnv> & staticEnv) + std::shared_ptr<StaticEnv> & staticEnv, + const ExperimentalFeatureSettings & xpSettings) { parser::State s = { symbols, @@ -840,6 +841,7 @@ Expr * EvalState::parse( basePath, positions.addOrigin(origin, length), exprSymbols, + xpSettings }; parser::ExprState x; diff --git a/src/libexpr/parser/state.hh b/src/libexpr/parser/state.hh index 29889152e..30803a37e 100644 --- a/src/libexpr/parser/state.hh +++ b/src/libexpr/parser/state.hh @@ -19,6 +19,7 @@ struct State SourcePath basePath; PosTable::Origin origin; const Expr::AstSymbols & s; + const ExperimentalFeatureSettings & xpSettings; void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos); void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 0951a54de..561492f86 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1213,6 +1213,20 @@ drvName, Bindings * attrs, Value & v) handleOutputs(ss); } + if (i->name == state.sAllowedReferences) + warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'allowedReferences'; use 'outputChecks.<output>.allowedReferences' instead", drvName); + if (i->name == state.sAllowedRequisites) + warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'allowedRequisites'; use 'outputChecks.<output>.allowedRequisites' instead", drvName); + if (i->name == state.sDisallowedReferences) + warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedReferences'; use 'outputChecks.<output>.disallowedReferences' instead", drvName); + if (i->name == state.sDisallowedRequisites) + warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedRequisites'; use 'outputChecks.<output>.disallowedRequisites' instead", drvName); + if (i->name == state.sMaxSize) + warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'maxSize'; use 'outputChecks.<output>.maxSize' instead", drvName); + if (i->name == state.sMaxClosureSize) + warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'maxClosureSize'; use 'outputChecks.<output>.maxClosureSize' instead", drvName); + + } else { auto s = state.coerceToString(pos, *i->value, context, context_below, true).toOwned(); drv.env.emplace(key, s); diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 23903117a..db380e07c 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -2517,6 +2517,24 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo }; if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) { + if (get(*structuredAttrs, "allowedReferences")){ + warn("'structuredAttrs' disables the effect of the top-level attribute 'allowedReferences'; use 'outputChecks' instead"); + } + if (get(*structuredAttrs, "allowedRequisites")){ + warn("'structuredAttrs' disables the effect of the top-level attribute 'allowedRequisites'; use 'outputChecks' instead"); + } + if (get(*structuredAttrs, "disallowedRequisites")){ + warn("'structuredAttrs' disables the effect of the top-level attribute 'disallowedRequisites'; use 'outputChecks' instead"); + } + if (get(*structuredAttrs, "disallowedReferences")){ + warn("'structuredAttrs' disables the effect of the top-level attribute 'disallowedReferences'; use 'outputChecks' instead"); + } + if (get(*structuredAttrs, "maxSize")){ + warn("'structuredAttrs' disables the effect of the top-level attribute 'maxSize'; use 'outputChecks' instead"); + } + if (get(*structuredAttrs, "maxClosureSize")){ + warn("'structuredAttrs' disables the effect of the top-level attribute 'maxClosureSize'; use 'outputChecks' instead"); + } if (auto outputChecks = get(*structuredAttrs, "outputChecks")) { if (auto output = get(*outputChecks, outputName)) { Checks checks; diff --git a/tests/functional/lang/eval-okay-derivation-legacy.err.exp b/tests/functional/lang/eval-okay-derivation-legacy.err.exp new file mode 100644 index 000000000..94f0854dd --- /dev/null +++ b/tests/functional/lang/eval-okay-derivation-legacy.err.exp @@ -0,0 +1,6 @@ +warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'allowedReferences'; use 'outputChecks.<output>.allowedReferences' instead +warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'allowedRequisites'; use 'outputChecks.<output>.allowedRequisites' instead +warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedReferences'; use 'outputChecks.<output>.disallowedReferences' instead +warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedRequisites'; use 'outputChecks.<output>.disallowedRequisites' instead +warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'maxClosureSize'; use 'outputChecks.<output>.maxClosureSize' instead +warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'maxSize'; use 'outputChecks.<output>.maxSize' instead diff --git a/tests/functional/lang/eval-okay-derivation-legacy.exp b/tests/functional/lang/eval-okay-derivation-legacy.exp new file mode 100644 index 000000000..4f374a1aa --- /dev/null +++ b/tests/functional/lang/eval-okay-derivation-legacy.exp @@ -0,0 +1 @@ +"/nix/store/mzgwvrjjir216ra58mwwizi8wj6y9ddr-eval-okay-derivation-legacy" diff --git a/tests/functional/lang/eval-okay-derivation-legacy.nix b/tests/functional/lang/eval-okay-derivation-legacy.nix new file mode 100644 index 000000000..b529cdf90 --- /dev/null +++ b/tests/functional/lang/eval-okay-derivation-legacy.nix @@ -0,0 +1,12 @@ +(builtins.derivationStrict { + name = "eval-okay-derivation-legacy"; + system = "x86_64-linux"; + builder = "/dontcare"; + __structuredAttrs = true; + allowedReferences = [ ]; + disallowedReferences = [ ]; + allowedRequisites = [ ]; + disallowedRequisites = [ ]; + maxSize = 1234; + maxClosureSize = 12345; +}).out diff --git a/tests/unit/libexpr-support/tests/libexpr.hh b/tests/unit/libexpr-support/tests/libexpr.hh index 01dcbb34c..745aa168d 100644 --- a/tests/unit/libexpr-support/tests/libexpr.hh +++ b/tests/unit/libexpr-support/tests/libexpr.hh @@ -26,9 +26,9 @@ namespace nix { , state({}, store) { } - Value eval(std::string input, bool forceValue = true) { + Value eval(std::string input, bool forceValue = true, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings) { Value v; - Expr & e = state.parseExprFromString(input, state.rootPath(CanonPath::root)); + Expr & e = state.parseExprFromString(input, state.rootPath(CanonPath::root), xpSettings); state.eval(e, v); if (forceValue) state.forceValue(v, noPos); diff --git a/tests/unit/libexpr/trivial.cc b/tests/unit/libexpr/trivial.cc index 171727ac7..19b62aff8 100644 --- a/tests/unit/libexpr/trivial.cc +++ b/tests/unit/libexpr/trivial.cc @@ -59,6 +59,11 @@ namespace nix { ASSERT_THAT(v, IsFloatEq(1.234)); } + TEST_F(TrivialExpressionTest, pointfloat) { + auto v = eval(".234"); + ASSERT_THAT(v, IsFloatEq(0.234)); + } + TEST_F(TrivialExpressionTest, updateAttrs) { auto v = eval("{ a = 1; } // { b = 2; a = 3; }"); ASSERT_THAT(v, IsAttrsOfSize(2)); @@ -81,6 +86,18 @@ namespace nix { ASSERT_THAT(v, IsTrue()); } + TEST_F(TrivialExpressionTest, urlLiteral) { + auto v = eval("https://nixos.org"); + ASSERT_THAT(v, IsStringEq("https://nixos.org")); + } + + TEST_F(TrivialExpressionTest, noUrlLiteral) { + ExperimentalFeatureSettings mockXpSettings; + mockXpSettings.set("experimental-features", "no-url-literals"); + + ASSERT_THROW(eval("https://nixos.org", true, mockXpSettings), Error); + } + TEST_F(TrivialExpressionTest, withFound) { auto v = eval("with { a = 23; }; a"); ASSERT_THAT(v, IsIntEq(23)); |