derived-path: refuse built derived path with a non-derivation base

Example: /nix/store/dr53sp25hyfsnzjpm8mh3r3y36vrw3ng-neovim-0.9.5^out

This is nonsensical since selecting outputs can only be done for a
buildable derivation, not for a realised store path. The build worker
side of things ends up crashing with an assertion when trying to handle
such malformed paths.

Change-Id: Ia3587c71fe3da5bea45d4e506e1be4dd62291ddf
This commit is contained in:
Pierre Bourdon 2024-05-17 02:02:48 +02:00
parent 9249c89dc6
commit 5a1824ebe1
Signed by: delroth
GPG key ID: 6FB80DCD84DA0F1C
2 changed files with 29 additions and 26 deletions

View file

@ -185,21 +185,32 @@ DerivedPath::Built DerivedPath::Built::parse(
}; };
} }
static SingleDerivedPath parseWithSingle( template <typename DerivedPathT>
static DerivedPathT parseDerivedPath(
const Store & store, std::string_view s, std::string_view separator, const Store & store, std::string_view s, std::string_view separator,
const ExperimentalFeatureSettings & xpSettings) const ExperimentalFeatureSettings & xpSettings)
{ {
size_t n = s.rfind(separator); size_t n = s.rfind(separator);
return n == s.npos if (n == s.npos) {
? (SingleDerivedPath) SingleDerivedPath::Opaque::parse(store, s) return DerivedPathT::Opaque::parse(store, s);
: (SingleDerivedPath) SingleDerivedPath::Built::parse(store, } else {
make_ref<SingleDerivedPath>(parseWithSingle( auto path = DerivedPathT::Built::parse(store,
make_ref<SingleDerivedPath>(parseDerivedPath<SingleDerivedPath>(
store, store,
s.substr(0, n), s.substr(0, n),
separator, separator,
xpSettings)), xpSettings)),
s.substr(n + 1), s.substr(n + 1),
xpSettings); xpSettings);
const auto& basePath = path.getBaseStorePath();
if (!basePath.isDerivation()) {
throw InvalidPath("cannot use output selection ('%s') on non-derivation store path '%s'",
separator, basePath.to_string());
}
return path;
}
} }
SingleDerivedPath SingleDerivedPath::parse( SingleDerivedPath SingleDerivedPath::parse(
@ -207,7 +218,7 @@ SingleDerivedPath SingleDerivedPath::parse(
std::string_view s, std::string_view s,
const ExperimentalFeatureSettings & xpSettings) const ExperimentalFeatureSettings & xpSettings)
{ {
return parseWithSingle(store, s, "^", xpSettings); return parseDerivedPath<SingleDerivedPath>(store, s, "^", xpSettings);
} }
SingleDerivedPath SingleDerivedPath::parseLegacy( SingleDerivedPath SingleDerivedPath::parseLegacy(
@ -215,24 +226,7 @@ SingleDerivedPath SingleDerivedPath::parseLegacy(
std::string_view s, std::string_view s,
const ExperimentalFeatureSettings & xpSettings) const ExperimentalFeatureSettings & xpSettings)
{ {
return parseWithSingle(store, s, "!", xpSettings); return parseDerivedPath<SingleDerivedPath>(store, s, "!", xpSettings);
}
static DerivedPath parseWith(
const Store & store, std::string_view s, std::string_view separator,
const ExperimentalFeatureSettings & xpSettings)
{
size_t n = s.rfind(separator);
return n == s.npos
? (DerivedPath) DerivedPath::Opaque::parse(store, s)
: (DerivedPath) DerivedPath::Built::parse(store,
make_ref<SingleDerivedPath>(parseWithSingle(
store,
s.substr(0, n),
separator,
xpSettings)),
s.substr(n + 1),
xpSettings);
} }
DerivedPath DerivedPath::parse( DerivedPath DerivedPath::parse(
@ -240,7 +234,7 @@ DerivedPath DerivedPath::parse(
std::string_view s, std::string_view s,
const ExperimentalFeatureSettings & xpSettings) const ExperimentalFeatureSettings & xpSettings)
{ {
return parseWith(store, s, "^", xpSettings); return parseDerivedPath<DerivedPath>(store, s, "^", xpSettings);
} }
DerivedPath DerivedPath::parseLegacy( DerivedPath DerivedPath::parseLegacy(
@ -248,7 +242,7 @@ DerivedPath DerivedPath::parseLegacy(
std::string_view s, std::string_view s,
const ExperimentalFeatureSettings & xpSettings) const ExperimentalFeatureSettings & xpSettings)
{ {
return parseWith(store, s, "!", xpSettings); return parseDerivedPath<DerivedPath>(store, s, "!", xpSettings);
} }
DerivedPath DerivedPath::fromSingle(const SingleDerivedPath & req) DerivedPath DerivedPath::fromSingle(const SingleDerivedPath & req)

View file

@ -77,6 +77,15 @@ TEST_F(DerivedPathTest, built_built_xp) {
MissingExperimentalFeature); MissingExperimentalFeature);
} }
/**
* Built paths with a non-derivation base should fail parsing.
*/
TEST_F(DerivedPathTest, non_derivation_base) {
ASSERT_THROW(
DerivedPath::parse(*store, "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x^foo"),
InvalidPath);
}
#ifndef COVERAGE #ifndef COVERAGE
RC_GTEST_FIXTURE_PROP( RC_GTEST_FIXTURE_PROP(