diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 8b9f49266..00b09f4ea 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -168,9 +168,9 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state) ? state.rootPath(absPath(getCommandBaseDir())) : state.rootPath("."))); }, - [&](const AutoArgString & arg) { v->mkString(arg.s); }, - [&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string())); }, - [&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO)); }}, + [&](const AutoArgString & arg) { v->mkString(arg.s, state.mem); }, + [&](const AutoArgFile & arg) { v->mkString(readFile(arg.path.string()), state.mem); }, + [&](const AutoArgStdin & arg) { v->mkString(readFile(STDIN_FILENO), state.mem); }}, arg); res.insert(state.symbols.create(name), v); } diff --git a/src/libexpr-c/nix_api_expr.cc b/src/libexpr-c/nix_api_expr.cc index 76f3b6486..0dd9fa0a5 100644 --- a/src/libexpr-c/nix_api_expr.cc +++ b/src/libexpr-c/nix_api_expr.cc @@ -69,8 +69,8 @@ nix_err nix_expr_eval_from_string( context->last_err_code = NIX_OK; try { nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path))); - state->state.eval(parsedExpr, value->value); - state->state.forceValue(value->value, nix::noPos); + state->state.eval(parsedExpr, *value->value); + state->state.forceValue(*value->value, nix::noPos); } NIXC_CATCH_ERRS } @@ -80,8 +80,8 @@ nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, n if (context) context->last_err_code = NIX_OK; try { - state->state.callFunction(fn->value, arg->value, value->value, nix::noPos); - state->state.forceValue(value->value, nix::noPos); + state->state.callFunction(*fn->value, *arg->value, *value->value, nix::noPos); + state->state.forceValue(*value->value, nix::noPos); } NIXC_CATCH_ERRS } @@ -91,9 +91,15 @@ nix_err nix_value_call_multi( { if (context) context->last_err_code = NIX_OK; + + std::vector internal_args; + internal_args.reserve(nargs); + for (size_t i = 0; i < nargs; i++) + internal_args.push_back(args[i]->value); + try { - state->state.callFunction(fn->value, {(nix::Value **) args, nargs}, value->value, nix::noPos); - state->state.forceValue(value->value, nix::noPos); + state->state.callFunction(*fn->value, {internal_args.data(), nargs}, *value->value, nix::noPos); + state->state.forceValue(*value->value, nix::noPos); } NIXC_CATCH_ERRS } @@ -103,7 +109,7 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value * if (context) context->last_err_code = NIX_OK; try { - state->state.forceValue(value->value, nix::noPos); + state->state.forceValue(*value->value, nix::noPos); } NIXC_CATCH_ERRS } @@ -113,7 +119,7 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val if (context) context->last_err_code = NIX_OK; try { - state->state.forceValueDeep(value->value); + state->state.forceValueDeep(*value->value); } NIXC_CATCH_ERRS } diff --git a/src/libexpr-c/nix_api_expr_internal.h b/src/libexpr-c/nix_api_expr_internal.h index 3aa1d9932..07c7a2194 100644 --- a/src/libexpr-c/nix_api_expr_internal.h +++ b/src/libexpr-c/nix_api_expr_internal.h @@ -39,7 +39,13 @@ struct ListBuilder struct nix_value { - nix::Value value; + nix::Value * value; + /** + * As we move to a managed heap, we need EvalMemory in more places. Ideally, we would take in EvalState or + * EvalMemory as an argument when we need it, but we don't want to make changes to the stable C api, so we stuff it + * into the nix_value that will get passed in to the relevant functions. + */ + nix::EvalMemory * mem; }; struct nix_string_return diff --git a/src/libexpr-c/nix_api_value.cc b/src/libexpr-c/nix_api_value.cc index e231c36f4..be8ff4926 100644 --- a/src/libexpr-c/nix_api_value.cc +++ b/src/libexpr-c/nix_api_value.cc @@ -20,7 +20,7 @@ static const nix::Value & check_value_not_null(const nix_value * value) if (!value) { throw std::runtime_error("nix_value is null"); } - return *((const nix::Value *) value); + return *value->value; } static nix::Value & check_value_not_null(nix_value * value) @@ -28,7 +28,7 @@ static nix::Value & check_value_not_null(nix_value * value) if (!value) { throw std::runtime_error("nix_value is null"); } - return value->value; + return *value->value; } static const nix::Value & check_value_in(const nix_value * value) @@ -58,9 +58,14 @@ static nix::Value & check_value_out(nix_value * value) return v; } -static inline nix_value * as_nix_value_ptr(nix::Value * v) +static inline nix_value * new_nix_value(nix::Value * v, nix::EvalMemory & mem) { - return reinterpret_cast(v); + nix_value * ret = new (mem.allocBytes(sizeof(nix_value))) nix_value{ + .value = v, + .mem = &mem, + }; + nix_gc_incref(nullptr, ret); + return ret; } /** @@ -69,7 +74,13 @@ static inline nix_value * as_nix_value_ptr(nix::Value * v) * Deals with errors and converts arguments from C++ into C types. */ static void nix_c_primop_wrapper( - PrimOpFun f, void * userdata, nix::EvalState & state, const nix::PosIdx pos, nix::Value ** args, nix::Value & v) + PrimOpFun f, + void * userdata, + int arity, + nix::EvalState & state, + const nix::PosIdx pos, + nix::Value ** args, + nix::Value & v) { nix_c_context ctx; @@ -85,8 +96,15 @@ static void nix_c_primop_wrapper( // ok because we don't see a need for this yet (e.g. inspecting thunks, // or maybe something to make blackholes work better; we don't know). nix::Value vTmp; + nix_value * vTmpPtr = new_nix_value(&vTmp, state.mem); - f(userdata, &ctx, (EvalState *) &state, (nix_value **) args, (nix_value *) &vTmp); + std::vector external_args; + external_args.reserve(arity); + for (int i = 0; i < arity; i++) { + nix_value * external_arg = new_nix_value(args[i], state.mem); + external_args.push_back(external_arg); + } + f(userdata, &ctx, (EvalState *) &state, external_args.data(), vTmpPtr); if (ctx.last_err_code != NIX_OK) { /* TODO: Throw different errors depending on the error code */ @@ -135,7 +153,7 @@ PrimOp * nix_alloc_primop( .args = {}, .arity = (size_t) arity, .doc = doc, - .fun = std::bind(nix_c_primop_wrapper, fun, user_data, _1, _2, _3, _4)}; + .fun = std::bind(nix_c_primop_wrapper, fun, user_data, arity, _1, _2, _3, _4)}; if (args) for (size_t i = 0; args[i]; i++) p->args.emplace_back(*args); @@ -160,8 +178,7 @@ nix_value * nix_alloc_value(nix_c_context * context, EvalState * state) if (context) context->last_err_code = NIX_OK; try { - nix_value * res = as_nix_value_ptr(state->state.allocValue()); - nix_gc_incref(nullptr, res); + nix_value * res = new_nix_value(state->state.allocValue(), state->state.mem); return res; } NIXC_CATCH_ERRS_NULL @@ -331,10 +348,10 @@ nix_value * nix_get_list_byidx(nix_c_context * context, const nix_value * value, return nullptr; } auto * p = v.listView()[ix]; - nix_gc_incref(nullptr, p); - if (p != nullptr) - state->state.forceValue(*p, nix::noPos); - return as_nix_value_ptr(p); + if (p == nullptr) + return nullptr; + state->state.forceValue(*p, nix::noPos); + return new_nix_value(p, state->state.mem); } NIXC_CATCH_ERRS_NULL } @@ -352,9 +369,8 @@ nix_get_list_byidx_lazy(nix_c_context * context, const nix_value * value, EvalSt return nullptr; } auto * p = v.listView()[ix]; - nix_gc_incref(nullptr, p); // Note: intentionally NOT calling forceValue() to keep the element lazy - return as_nix_value_ptr(p); + return new_nix_value(p, state->state.mem); } NIXC_CATCH_ERRS_NULL } @@ -369,9 +385,8 @@ nix_value * nix_get_attr_byname(nix_c_context * context, const nix_value * value nix::Symbol s = state->state.symbols.create(name); auto attr = v.attrs()->get(s); if (attr) { - nix_gc_incref(nullptr, attr->value); state->state.forceValue(*attr->value, nix::noPos); - return as_nix_value_ptr(attr->value); + return new_nix_value(attr->value, state->state.mem); } nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute"); return nullptr; @@ -390,9 +405,8 @@ nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalS nix::Symbol s = state->state.symbols.create(name); auto attr = v.attrs()->get(s); if (attr) { - nix_gc_incref(nullptr, attr->value); // Note: intentionally NOT calling forceValue() to keep the attribute lazy - return as_nix_value_ptr(attr->value); + return new_nix_value(attr->value, state->state.mem); } nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute"); return nullptr; @@ -440,9 +454,8 @@ nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state } const nix::Attr & a = (*v.attrs())[i]; *name = state->state.symbols[a.name].c_str(); - nix_gc_incref(nullptr, a.value); state->state.forceValue(*a.value, nix::noPos); - return as_nix_value_ptr(a.value); + return new_nix_value(a.value, state->state.mem); } NIXC_CATCH_ERRS_NULL } @@ -461,9 +474,8 @@ nix_value * nix_get_attr_byidx_lazy( } const nix::Attr & a = (*v.attrs())[i]; *name = state->state.symbols[a.name].c_str(); - nix_gc_incref(nullptr, a.value); // Note: intentionally NOT calling forceValue() to keep the attribute lazy - return as_nix_value_ptr(a.value); + return new_nix_value(a.value, state->state.mem); } NIXC_CATCH_ERRS_NULL } @@ -503,7 +515,7 @@ nix_err nix_init_string(nix_c_context * context, nix_value * value, const char * context->last_err_code = NIX_OK; try { auto & v = check_value_out(value); - v.mkString(std::string_view(str)); + v.mkString(std::string_view(str), *value->mem); } NIXC_CATCH_ERRS } @@ -514,7 +526,7 @@ nix_err nix_init_path_string(nix_c_context * context, EvalState * s, nix_value * context->last_err_code = NIX_OK; try { auto & v = check_value_out(value); - v.mkPath(s->state.rootPath(nix::CanonPath(str))); + v.mkPath(s->state.rootPath(nix::CanonPath(str)), s->state.mem); } NIXC_CATCH_ERRS } diff --git a/src/libexpr-tests/json.cc b/src/libexpr-tests/json.cc index aa71c4d86..31e7a18c5 100644 --- a/src/libexpr-tests/json.cc +++ b/src/libexpr-tests/json.cc @@ -73,7 +73,7 @@ TEST_F(JSONValueTest, StringQuotes) TEST_F(JSONValueTest, DISABLED_Path) { Value v; - v.mkPath(state.rootPath(CanonPath("/test"))); + v.mkPath(state.rootPath(CanonPath("/test")), state.mem); ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\""); } } /* namespace nix */ diff --git a/src/libexpr-tests/value/print.cc b/src/libexpr-tests/value/print.cc index 0456835b4..d22606219 100644 --- a/src/libexpr-tests/value/print.cc +++ b/src/libexpr-tests/value/print.cc @@ -268,7 +268,7 @@ struct StringPrintingTests : LibExprTest void test(std::string_view literal, std::string_view expected, unsigned int maxLength, A... args) { Value v; - v.mkString(literal); + v.mkString(literal, state.mem); std::stringstream out; printValue(state, out, v, PrintOptions{.maxStringLength = maxLength}); @@ -353,7 +353,7 @@ TEST_F(ValuePrintingTests, ansiColorsStringElided) TEST_F(ValuePrintingTests, ansiColorsPath) { Value v; - v.mkPath(state.rootPath(CanonPath("puppy"))); + v.mkPath(state.rootPath(CanonPath("puppy")), state.mem); test(v, ANSI_GREEN "/puppy" ANSI_NORMAL, PrintOptions{.ansiColors = true}); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 29aa11035..71834f10f 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -81,20 +81,20 @@ static const char * makeImmutableString(std::string_view s) return t; } -StringData & StringData::alloc(size_t size) +StringData & StringData::alloc(EvalMemory & mem, size_t size) { - void * t = GC_MALLOC_ATOMIC(sizeof(StringData) + size + 1); + void * t = mem.allocBytes(sizeof(StringData) + size + 1); if (!t) throw std::bad_alloc(); auto res = new (t) StringData(size); return *res; } -const StringData & StringData::make(std::string_view s) +const StringData & StringData::make(EvalMemory & mem, std::string_view s) { if (s.empty()) return ""_sds; - auto & res = alloc(s.size()); + auto & res = alloc(mem, s.size()); std::memcpy(&res.data_, s.data(), s.size()); res.data_[s.size()] = '\0'; return res; @@ -849,9 +849,9 @@ DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) evalState.runDebugRepl(nullptr, trace.env, trace.expr); } -void Value::mkString(std::string_view s) +void Value::mkString(std::string_view s, EvalMemory & mem) { - mkStringNoCopy(StringData::make(s)); + mkStringNoCopy(StringData::make(mem, s)); } Value::StringWithContext::Context * @@ -862,13 +862,13 @@ Value::StringWithContext::Context::fromBuilder(const NixStringContext & context, auto ctx = new (mem.allocBytes(sizeof(Context) + context.size() * sizeof(value_type))) Context(context.size()); std::ranges::transform( - context, ctx->elems, [](const NixStringContextElem & elt) { return &StringData::make(elt.to_string()); }); + context, ctx->elems, [&](const NixStringContextElem & elt) { return &StringData::make(mem, elt.to_string()); }); return ctx; } void Value::mkString(std::string_view s, const NixStringContext & context, EvalMemory & mem) { - mkStringNoCopy(StringData::make(s), Value::StringWithContext::Context::fromBuilder(context, mem)); + mkStringNoCopy(StringData::make(mem, s), Value::StringWithContext::Context::fromBuilder(context, mem)); } void Value::mkStringMove(const StringData & s, const NixStringContext & context, EvalMemory & mem) @@ -876,9 +876,9 @@ void Value::mkStringMove(const StringData & s, const NixStringContext & context, mkStringNoCopy(s, Value::StringWithContext::Context::fromBuilder(context, mem)); } -void Value::mkPath(const SourcePath & path) +void Value::mkPath(const SourcePath & path, EvalMemory & mem) { - mkPath(&*path.accessor, StringData::make(path.path.abs())); + mkPath(&*path.accessor, StringData::make(mem, path.path.abs())); } inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) @@ -943,7 +943,7 @@ void EvalState::mkPos(Value & v, PosIdx p) auto origin = positions.originOf(p); if (auto path = std::get_if(&origin)) { auto attrs = buildBindings(3); - attrs.alloc(s.file).mkString(path->path.abs()); + attrs.alloc(s.file).mkString(path->path.abs(), mem); makePositionThunks(*this, p, attrs.alloc(s.line), attrs.alloc(s.column)); v.mkAttrs(attrs); } else @@ -2139,9 +2139,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) for (const auto & part : strings) { resultStr += *part; } - v.mkPath(state.rootPath(CanonPath(resultStr))); + v.mkPath(state.rootPath(CanonPath(resultStr)), state.mem); } else { - auto & resultStr = StringData::alloc(sSize); + auto & resultStr = StringData::alloc(state.mem, sSize); auto * tmp = resultStr.data(); for (const auto & part : strings) { std::memcpy(tmp, part->data(), part->size()); diff --git a/src/libexpr/include/nix/expr/value.hh b/src/libexpr/include/nix/expr/value.hh index ff62092f2..004dcc43f 100644 --- a/src/libexpr/include/nix/expr/value.hh +++ b/src/libexpr/include/nix/expr/value.hh @@ -232,13 +232,13 @@ public: * Allocate StringData on the (possibly) GC-managed heap and copy * the contents of s to it. */ - static const StringData & make(std::string_view s); + static const StringData & make(EvalMemory & mem, std::string_view s); /** * Allocate StringData on the (possibly) GC-managed heap. * @param size Length of the string (without the NUL terminator). */ - static StringData & alloc(size_t size); + static StringData & alloc(EvalMemory & mem, size_t size); size_t size() const { @@ -1147,13 +1147,13 @@ public: setStorage(StringWithContext{.str = &s, .context = context}); } - void mkString(std::string_view s); + void mkString(std::string_view s, EvalMemory & mem); void mkString(std::string_view s, const NixStringContext & context, EvalMemory & mem); void mkStringMove(const StringData & s, const NixStringContext & context, EvalMemory & mem); - void mkPath(const SourcePath & path); + void mkPath(const SourcePath & path, EvalMemory & mem); inline void mkPath(SourceAccessor * accessor, const StringData & path) noexcept { diff --git a/src/libexpr/json-to-value.cc b/src/libexpr/json-to-value.cc index 9c645e7fd..4a68308c6 100644 --- a/src/libexpr/json-to-value.cc +++ b/src/libexpr/json-to-value.cc @@ -151,7 +151,7 @@ public: bool string(string_t & val) override { forceNoNullByte(val); - rs->value(state).mkString(val); + rs->value(state).mkString(val, state.mem); rs->add(); return true; } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 35f16a68d..573dee74f 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -53,7 +53,7 @@ RegisterPrimOp::PrimOps & RegisterPrimOp::primOps() static inline Value * mkString(EvalState & state, const std::csub_match & match) { Value * v = state.allocValue(); - v->mkString({match.first, match.second}); + v->mkString({match.first, match.second}, state.mem); return v; } @@ -230,12 +230,12 @@ void derivationToValue( NixStringContextElem::DrvDeep{.drvPath = storePath}, }, state.mem); - attrs.alloc(state.s.name).mkString(drv.env["name"]); + attrs.alloc(state.s.name).mkString(drv.env["name"], state.mem); auto list = state.buildList(drv.outputs.size()); for (const auto & [i, o] : enumerate(drv.outputs)) { mkOutputString(state, attrs, storePath, o); - (list[i] = state.allocValue())->mkString(o.first); + (list[i] = state.allocValue())->mkString(o.first, state.mem); } attrs.alloc(state.s.outputs).mkList(list); @@ -519,7 +519,7 @@ static void prim_typeOf(EvalState & state, const PosIdx pos, Value ** args, Valu v.mkStringNoCopy("lambda"_sds); break; case nExternal: - v.mkString(args[0]->external()->typeOf()); + v.mkString(args[0]->external()->typeOf(), state.mem); break; case nFloat: v.mkStringNoCopy("float"_sds); @@ -1176,7 +1176,7 @@ static void prim_getEnv(EvalState & state, const PosIdx pos, Value ** args, Valu { std::string name( state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getEnv")); - v.mkString(state.settings.restrictEval || state.settings.pureEval ? "" : getEnv(name).value_or("")); + v.mkString(state.settings.restrictEval || state.settings.pureEval ? "" : getEnv(name).value_or(""), state.mem); } static RegisterPrimOp primop_getEnv({ @@ -1842,8 +1842,10 @@ static RegisterPrimOp primop_derivationStrict( ‘out’. */ static void prim_placeholder(EvalState & state, const PosIdx pos, Value ** args, Value & v) { - v.mkString(hashPlaceholder( - state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.placeholder"))); + v.mkString( + hashPlaceholder(state.forceStringNoCtx( + *args[0], pos, "while evaluating the first argument passed to builtins.placeholder")), + state.mem); } static RegisterPrimOp primop_placeholder({ @@ -2027,7 +2029,7 @@ static void prim_dirOf(EvalState & state, const PosIdx pos, Value ** args, Value state.forceValue(*args[0], pos); if (args[0]->type() == nPath) { auto path = args[0]->path(); - v.mkPath(path.path.isRoot() ? path : path.parent()); + v.mkPath(path.path.isRoot() ? path : path.parent(), state.mem); } else { NixStringContext context; auto path = state.coerceToString( @@ -2144,7 +2146,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value ** args, Va auto path = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.findFile"); - v.mkPath(state.findFile(lookupPath, path, pos)); + v.mkPath(state.findFile(lookupPath, path, pos), state.mem); } static RegisterPrimOp primop_findFile( @@ -2293,7 +2295,7 @@ static void prim_hashFile(EvalState & state, const PosIdx pos, Value ** args, Va auto path = realisePath(state, pos, *args[1]); - v.mkString(hashString(*ha, path.readFile()).to_string(HashFormat::Base16, false)); + v.mkString(hashString(*ha, path.readFile()).to_string(HashFormat::Base16, false), state.mem); } static RegisterPrimOp primop_hashFile({ @@ -2382,7 +2384,7 @@ static void prim_readDir(EvalState & state, const PosIdx pos, Value ** args, Val // detailed node info quickly in this case we produce a thunk to // query the file type lazily. auto epath = state.allocValue(); - epath->mkPath(path / name); + epath->mkPath(path / name, state.mem); if (!readFileType) readFileType = &state.getBuiltin("readFileType"); attr.mkApp(readFileType, epath); @@ -2763,7 +2765,7 @@ bool EvalState::callPathFilter(Value * filterFun, const SourcePath & path, PosId /* Call the filter function. The first argument is the path, the second is a string indicating the type of the file. */ Value arg1; - arg1.mkString(path.path.abs()); + arg1.mkString(path.path.abs(), mem); // assert that type is not "unknown" Value * args[]{&arg1, const_cast(&fileTypeToString(*this, st.type))}; @@ -4541,7 +4543,7 @@ static void prim_hashString(EvalState & state, const PosIdx pos, Value ** args, auto s = state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.hashString"); - v.mkString(hashString(*ha, s).to_string(HashFormat::Base16, false)); + v.mkString(hashString(*ha, s).to_string(HashFormat::Base16, false), state.mem); } static RegisterPrimOp primop_hashString({ @@ -4574,7 +4576,7 @@ static void prim_convertHash(EvalState & state, const PosIdx pos, Value ** args, HashFormat hf = parseHashFormat( state.forceStringNoCtx(*iteratorToHashFormat->value, pos, "while evaluating the attribute 'toHashFormat'")); - v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI)); + v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI), state.mem); } static RegisterPrimOp primop_convertHash({ @@ -4992,8 +4994,8 @@ static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value ** args state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.parseDrvName"); DrvName parsed(name); auto attrs = state.buildBindings(2); - attrs.alloc(state.s.name).mkString(parsed.name); - attrs.alloc("version").mkString(parsed.version); + attrs.alloc(state.s.name).mkString(parsed.name, state.mem); + attrs.alloc("version").mkString(parsed.version, state.mem); v.mkAttrs(attrs); } @@ -5048,7 +5050,7 @@ static void prim_splitVersion(EvalState & state, const PosIdx pos, Value ** args } auto list = state.buildList(components.size()); for (const auto & [n, component] : enumerate(components)) - (list[n] = state.allocValue())->mkString(std::move(component)); + (list[n] = state.allocValue())->mkString(std::move(component), state.mem); v.mkList(list); } @@ -5192,7 +5194,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings) }); if (!settings.pureEval) - v.mkString(settings.getCurrentSystem()); + v.mkString(settings.getCurrentSystem(), mem); addConstant( "__currentSystem", v, @@ -5224,7 +5226,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings) .impureOnly = true, }); - v.mkString(nixVersion); + v.mkString(nixVersion, mem); addConstant( "__nixVersion", v, @@ -5249,7 +5251,7 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings) )", }); - v.mkString(store->storeDir); + v.mkString(store->storeDir, mem); addConstant( "__storeDir", v, @@ -5314,8 +5316,8 @@ void EvalState::createBaseEnv(const EvalSettings & evalSettings) auto list = buildList(lookupPath.elements.size()); for (const auto & [n, i] : enumerate(lookupPath.elements)) { auto attrs = buildBindings(2); - attrs.alloc("path").mkString(i.path.s); - attrs.alloc("prefix").mkString(i.prefix.s); + attrs.alloc("path").mkString(i.path.s, mem); + attrs.alloc("prefix").mkString(i.prefix.s, mem); (list[n] = allocValue())->mkAttrs(attrs); } v.mkList(list); diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc index 2c5add148..70c13e298 100644 --- a/src/libexpr/primops/context.cc +++ b/src/libexpr/primops/context.cc @@ -11,7 +11,7 @@ static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos, NixStringContext context; auto s = state.coerceToString( pos, *args[0], context, "while evaluating the argument passed to builtins.unsafeDiscardStringContext"); - v.mkString(*s); + v.mkString(*s, state.mem); } static RegisterPrimOp primop_unsafeDiscardStringContext({ @@ -218,7 +218,7 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value ** args, if (!info.second.outputs.empty()) { auto list = state.buildList(info.second.outputs.size()); for (const auto & [i, output] : enumerate(info.second.outputs)) - (list[i] = state.allocValue())->mkString(output); + (list[i] = state.allocValue())->mkString(output, state.mem); infoAttrs.alloc(state.s.outputs).mkList(list); } attrs.alloc(state.store->printStorePath(info.first)).mkAttrs(infoAttrs); diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index 2174275ec..cc42931a6 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -86,12 +86,12 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value ** ar auto attrs2 = state.buildBindings(8); state.mkStorePathString(storePath, attrs2.alloc(state.s.outPath)); if (input2.getRef()) - attrs2.alloc("branch").mkString(*input2.getRef()); + attrs2.alloc("branch").mkString(*input2.getRef(), state.mem); // Backward compatibility: set 'rev' to // 0000000000000000000000000000000000000000 for a dirty tree. auto rev2 = input2.getRev().value_or(Hash(HashAlgorithm::SHA1)); - attrs2.alloc("rev").mkString(rev2.gitRev()); - attrs2.alloc("shortRev").mkString(rev2.gitRev().substr(0, 12)); + attrs2.alloc("rev").mkString(rev2.gitRev(), state.mem); + attrs2.alloc("shortRev").mkString(rev2.gitRev().substr(0, 12), state.mem); if (auto revCount = input2.getRevCount()) attrs2.alloc("revCount").mkInt(*revCount); v.mkAttrs(attrs2); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index db976a3e0..1614fcc59 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -35,7 +35,7 @@ void emitTreeAttrs( // FIXME: support arbitrary input attributes. if (auto narHash = input.getNarHash()) - attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true)); + attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true), state.mem); if (input.getType() == "git") attrs.alloc("submodules").mkBool(fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false)); @@ -43,13 +43,13 @@ void emitTreeAttrs( if (!forceDirty) { if (auto rev = input.getRev()) { - attrs.alloc("rev").mkString(rev->gitRev()); - attrs.alloc("shortRev").mkString(rev->gitShortRev()); + attrs.alloc("rev").mkString(rev->gitRev(), state.mem); + attrs.alloc("shortRev").mkString(rev->gitShortRev(), state.mem); } else if (emptyRevFallback) { // Backwards compat for `builtins.fetchGit`: dirty repos return an empty sha1 as rev auto emptyHash = Hash(HashAlgorithm::SHA1); - attrs.alloc("rev").mkString(emptyHash.gitRev()); - attrs.alloc("shortRev").mkString(emptyHash.gitShortRev()); + attrs.alloc("rev").mkString(emptyHash.gitRev(), state.mem); + attrs.alloc("shortRev").mkString(emptyHash.gitShortRev(), state.mem); } if (auto revCount = input.getRevCount()) @@ -59,13 +59,14 @@ void emitTreeAttrs( } if (auto dirtyRev = fetchers::maybeGetStrAttr(input.attrs, "dirtyRev")) { - attrs.alloc("dirtyRev").mkString(*dirtyRev); - attrs.alloc("dirtyShortRev").mkString(*fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev")); + attrs.alloc("dirtyRev").mkString(*dirtyRev, state.mem); + attrs.alloc("dirtyShortRev").mkString(*fetchers::maybeGetStrAttr(input.attrs, "dirtyShortRev"), state.mem); } if (auto lastModified = input.getLastModified()) { attrs.alloc("lastModified").mkInt(*lastModified); - attrs.alloc("lastModifiedDate").mkString(fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S"))); + attrs.alloc("lastModifiedDate") + .mkString(fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S")), state.mem); } v.mkAttrs(attrs); diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc index a06224fee..562ff3d14 100644 --- a/src/libexpr/primops/fromTOML.cc +++ b/src/libexpr/primops/fromTOML.cc @@ -126,7 +126,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va case toml::value_t::string: { auto s = toml::get(t); forceNoNullByte(s); - v.mkString(s); + v.mkString(s, state.mem); } break; case toml::value_t::local_datetime: case toml::value_t::offset_datetime: @@ -142,7 +142,7 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Va s << t; auto str = s.view(); forceNoNullByte(str); - attrs.alloc("value").mkString(str); + attrs.alloc("value").mkString(str, state.mem); v.mkAttrs(attrs); } else { throw std::runtime_error("Dates and times are not supported"); diff --git a/src/libflake-c/nix_api_flake.cc b/src/libflake-c/nix_api_flake.cc index 2de0e667e..32329585a 100644 --- a/src/libflake-c/nix_api_flake.cc +++ b/src/libflake-c/nix_api_flake.cc @@ -200,7 +200,7 @@ nix_value * nix_locked_flake_get_output_attrs( nix_clear_err(context); try { auto v = nix_alloc_value(context, evalState); - nix::flake::callFlake(evalState->state, *lockedFlake->lockedFlake, v->value); + nix::flake::callFlake(evalState->state, *lockedFlake->lockedFlake, *v->value); return v; } NIXC_CATCH_ERRS_NULL diff --git a/src/libflake/flake-primops.cc b/src/libflake/flake-primops.cc index 3f65dc47a..962edbb3d 100644 --- a/src/libflake/flake-primops.cc +++ b/src/libflake/flake-primops.cc @@ -93,7 +93,7 @@ static void prim_parseFlakeRef(EvalState & state, const PosIdx pos, Value ** arg auto & vv = binds.alloc(s); std::visit( overloaded{ - [&vv](const std::string & value) { vv.mkString(value); }, + [&vv, &state](const std::string & value) { vv.mkString(value, state.mem); }, [&vv](const uint64_t & value) { vv.mkInt(value); }, [&vv](const Explicit & value) { vv.mkBool(value.t); }}, value); @@ -156,7 +156,7 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value ** } } auto flakeRef = FlakeRef::fromAttrs(state.fetchSettings, attrs); - v.mkString(flakeRef.to_string()); + v.mkString(flakeRef.to_string(), state.mem); } nix::PrimOp flakeRefToString({ diff --git a/src/libflake/flake.cc b/src/libflake/flake.cc index 6e5fa6ca1..9f7476bd0 100644 --- a/src/libflake/flake.cc +++ b/src/libflake/flake.cc @@ -956,7 +956,7 @@ void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & vRes) auto key = keyMap.find(node); assert(key != keyMap.end()); - override.alloc(state.symbols.create("dir")).mkString(CanonPath(subdir).rel()); + override.alloc(state.symbols.create("dir")).mkString(CanonPath(subdir).rel(), state.mem); overrides.alloc(state.symbols.create(key->second)).mkAttrs(override); } @@ -966,7 +966,7 @@ void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & vRes) Value * vCallFlake = requireInternalFile(state, CanonPath("call-flake.nix")); auto vLocks = state.allocValue(); - vLocks->mkString(lockFileStr); + vLocks->mkString(lockFileStr, state.mem); auto vFetchFinalTree = get(state.internalPrimOps, "fetchFinalTree"); assert(vFetchFinalTree); diff --git a/src/nix/main.cc b/src/nix/main.cc index 945cce9ac..1d7066449 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -271,7 +271,7 @@ static void showHelp(std::vector subcommand, NixArgs & toplevel) ); auto vDump = state.allocValue(); - vDump->mkString(toplevel.dumpCli()); + vDump->mkString(toplevel.dumpCli(), state.mem); auto vRes = state.allocValue(); Value * args[]{&state.getBuiltin("false"), vDump}; diff --git a/src/nix/nix-env/nix-env.cc b/src/nix/nix-env/nix-env.cc index 2a0984d18..54443a22c 100644 --- a/src/nix/nix-env/nix-env.cc +++ b/src/nix/nix-env/nix-env.cc @@ -132,7 +132,7 @@ static void getAllExprs(EvalState & state, const SourcePath & path, StringSet & } /* Load the expression on demand. */ auto vArg = state.allocValue(); - vArg->mkPath(path2); + vArg->mkPath(path2, state.mem); if (seen.size() == maxAttrs) throw Error("too many Nix expressions in directory '%1%'", path); attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg); @@ -483,7 +483,7 @@ static bool keep(PackageInfo & drv) static void setMetaFlag(EvalState & state, PackageInfo & drv, const std::string & name, const std::string & value) { auto v = state.allocValue(); - v->mkString(value); + v->mkString(value, state.mem); drv.setMeta(name, v); } diff --git a/src/nix/nix-env/user-env.cc b/src/nix/nix-env/user-env.cc index 21fdf25bc..d09365073 100644 --- a/src/nix/nix-env/user-env.cc +++ b/src/nix/nix-env/user-env.cc @@ -58,20 +58,20 @@ bool createUserEnv( auto attrs = state.buildBindings(7 + outputs.size()); attrs.alloc(state.s.type).mkStringNoCopy("derivation"_sds); - attrs.alloc(state.s.name).mkString(i.queryName()); + attrs.alloc(state.s.name).mkString(i.queryName(), state.mem); auto system = i.querySystem(); if (!system.empty()) - attrs.alloc(state.s.system).mkString(system); - attrs.alloc(state.s.outPath).mkString(state.store->printStorePath(i.queryOutPath())); + attrs.alloc(state.s.system).mkString(system, state.mem); + attrs.alloc(state.s.outPath).mkString(state.store->printStorePath(i.queryOutPath()), state.mem); if (drvPath) - attrs.alloc(state.s.drvPath).mkString(state.store->printStorePath(*drvPath)); + attrs.alloc(state.s.drvPath).mkString(state.store->printStorePath(*drvPath), state.mem); // Copy each output meant for installation. auto outputsList = state.buildList(outputs.size()); for (const auto & [m, j] : enumerate(outputs)) { - (outputsList[m] = state.allocValue())->mkString(j.first); + (outputsList[m] = state.allocValue())->mkString(j.first, state.mem); auto outputAttrs = state.buildBindings(2); - outputAttrs.alloc(state.s.outPath).mkString(state.store->printStorePath(*j.second)); + outputAttrs.alloc(state.s.outPath).mkString(state.store->printStorePath(*j.second), state.mem); attrs.alloc(j.first).mkAttrs(outputAttrs); /* This is only necessary when installing store paths, e.g.,