Skip to content

Commit

Permalink
Merge pull request #10757 from obsidiansystems/fix-4977
Browse files Browse the repository at this point in the history
Require `drvPath` attribute to end with `.drv`
  • Loading branch information
Ericson2314 committed May 24, 2024
2 parents c90a763 + f923ed6 commit e0c94b9
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/libexpr/eval-cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,7 @@ StorePath AttrCursor::forceDerivation()
{
auto aDrvPath = getAttr(root->state.sDrvPath, true);
auto drvPath = root->state.store->parseStorePath(aDrvPath->getString());
drvPath.requireDerivation();
if (!root->state.store->isValidPath(drvPath) && !settings.readOnlyMode) {
/* The eval cache contains 'drvPath', but the actual path has
been garbage-collected. So force it to be regenerated. */
Expand Down
3 changes: 1 addition & 2 deletions src/libexpr/eval-error.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ EvalErrorBuilder<T> & EvalErrorBuilder<T>::atPos(Value & value, PosIdx fallback)
template<class T>
EvalErrorBuilder<T> & EvalErrorBuilder<T>::withTrace(PosIdx pos, const std::string_view text)
{
error.err.traces.push_front(
Trace{.pos = error.state.positions[pos], .hint = HintFmt(std::string(text))});
error.addTrace(error.state.positions[pos], text);
return *this;
}

Expand Down
18 changes: 13 additions & 5 deletions src/libexpr/get-drvs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,21 @@ std::string PackageInfo::querySystem() const
std::optional<StorePath> PackageInfo::queryDrvPath() const
{
if (!drvPath && attrs) {
NixStringContext context;
if (auto i = attrs->get(state->sDrvPath))
drvPath = {state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the 'drvPath' attribute of a derivation")};
else
if (auto i = attrs->get(state->sDrvPath)) {
NixStringContext context;
auto found = state->coerceToStorePath(i->pos, *i->value, context, "while evaluating the 'drvPath' attribute of a derivation");
try {
found.requireDerivation();
} catch (Error & e) {
e.addTrace(state->positions[i->pos], "while evaluating the 'drvPath' attribute of a derivation");
throw;
}
drvPath = {std::move(found)};
} else
drvPath = {std::nullopt};
}
return drvPath.value_or(std::nullopt);
drvPath.value_or(std::nullopt);
return *drvPath;
}


Expand Down
23 changes: 17 additions & 6 deletions src/libexpr/print.cc
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,27 @@ class Printer

void printDerivation(Value & v)
{
NixStringContext context;
std::string storePath;
if (auto i = v.attrs()->get(state.sDrvPath))
storePath = state.store->printStorePath(state.coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation"));
std::optional<StorePath> storePath;
if (auto i = v.attrs()->get(state.sDrvPath)) {
NixStringContext context;
storePath = state.coerceToStorePath(i->pos, *i->value, context, "while evaluating the drvPath of a derivation");
}

/* This unforutately breaks printing nested values because of
how the pretty printer is used (when pretting printing and warning
to same terminal / std stream). */
#if 0
if (storePath && !storePath->isDerivation())
warn(
"drvPath attribute '%s' is not a valid store path to a derivation, this value not work properly",
state.store->printStorePath(*storePath));
#endif

if (options.ansiColors)
output << ANSI_GREEN;
output << "«derivation";
if (!storePath.empty()) {
output << " " << storePath;
if (storePath) {
output << " " << state.store->printStorePath(*storePath);
}
output << "»";
if (options.ansiColors)
Expand Down
5 changes: 2 additions & 3 deletions src/libstore/derivations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -930,10 +930,9 @@ DerivationOutputsAndOptPaths BasicDerivation::outputsAndOptPaths(const StoreDirC

std::string_view BasicDerivation::nameFromPath(const StorePath & drvPath)
{
drvPath.requireDerivation();
auto nameWithSuffix = drvPath.name();
constexpr std::string_view extension = ".drv";
assert(hasSuffix(nameWithSuffix, extension));
nameWithSuffix.remove_suffix(extension.size());
nameWithSuffix.remove_suffix(drvExtension.size());
return nameWithSuffix;
}

Expand Down
8 changes: 7 additions & 1 deletion src/libstore/path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,17 @@ StorePath::StorePath(const Hash & hash, std::string_view _name)
checkName(baseName, name());
}

bool StorePath::isDerivation() const
bool StorePath::isDerivation() const noexcept
{
return hasSuffix(name(), drvExtension);
}

void StorePath::requireDerivation() const
{
if (!isDerivation())
throw FormatError("store path '%s' is not a valid derivation path", to_string());
}

StorePath StorePath::dummy("ffffffffffffffffffffffffffffffff-x");

StorePath StorePath::random(std::string_view name)
Expand Down
27 changes: 10 additions & 17 deletions src/libstore/path.hh
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,23 @@ public:

StorePath(const Hash & hash, std::string_view name);

std::string_view to_string() const
std::string_view to_string() const noexcept
{
return baseName;
}

bool operator < (const StorePath & other) const
{
return baseName < other.baseName;
}

bool operator == (const StorePath & other) const
{
return baseName == other.baseName;
}

bool operator != (const StorePath & other) const
{
return baseName != other.baseName;
}
bool operator == (const StorePath & other) const noexcept = default;
auto operator <=> (const StorePath & other) const noexcept = default;

/**
* Check whether a file name ends with the extension for derivations.
*/
bool isDerivation() const;
bool isDerivation() const noexcept;

/**
* Throw an exception if `isDerivation` is false.
*/
void requireDerivation() const;

std::string_view name() const
{
Expand All @@ -82,7 +75,7 @@ typedef std::vector<StorePath> StorePaths;
* The file extension of \ref Derivation derivations when serialized
* into store objects.
*/
const std::string drvExtension = ".drv";
constexpr std::string_view drvExtension = ".drv";

}

Expand Down
1 change: 1 addition & 0 deletions src/nix-env/user-env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ bool createUserEnv(EvalState & state, PackageInfos & elems,
NixStringContext context;
auto & aDrvPath(*topLevel.attrs()->find(state.sDrvPath));
auto topLevelDrv = state.coerceToStorePath(aDrvPath.pos, *aDrvPath.value, context, "");
topLevelDrv.requireDerivation();
auto & aOutPath(*topLevel.attrs()->find(state.sOutPath));
auto topLevelOut = state.coerceToStorePath(aOutPath.pos, *aOutPath.value, context, "");

Expand Down
2 changes: 2 additions & 0 deletions src/nix/bundle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ struct CmdBundle : InstallableValueCommand
NixStringContext context2;
auto drvPath = evalState->coerceToStorePath(attr1->pos, *attr1->value, context2, "");

drvPath.requireDerivation();

auto attr2 = vRes->attrs()->get(evalState->sOutPath);
if (!attr2)
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
Expand Down
3 changes: 3 additions & 0 deletions tests/functional/lang.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ nix-instantiate --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grepQuietIn
nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grepQuietInverse Hello
expectStderr 1 nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' | grepQuiet Hello
expectStderr 1 nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello %" (throw "Foo")' | grepQuiet 'Hello %'
# Relies on parsing the expression derivation as a derivation, can't use --eval
expectStderr 1 nix-instantiate --show-trace lang/non-eval-fail-bad-drvPath.nix | grepQuiet "store path '8qlfcic10lw5304gqm8q45nr7g7jl62b-cachix-1.7.3-bin' is not a valid derivation path"


nix-instantiate --eval -E 'let x = builtins.trace { x = x; } true; in x' \
2>&1 | grepQuiet -E 'trace: { x = «potential infinite recursion»; }'
Expand Down
14 changes: 14 additions & 0 deletions tests/functional/lang/non-eval-fail-bad-drvPath.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
let
package = {
type = "derivation";
name = "cachix-1.7.3";
system = builtins.currentSystem;
outputs = [ "out" ];
# Illegal, because does not end in `.drv`
drvPath = "${builtins.storeDir}/8qlfcic10lw5304gqm8q45nr7g7jl62b-cachix-1.7.3-bin";
outputName = "out";
outPath = "${builtins.storeDir}/8qlfcic10lw5304gqm8q45nr7g7jl62b-cachix-1.7.3-bin";
out = package;
};
in
package

0 comments on commit e0c94b9

Please sign in to comment.