From 15f48dcd65fb17a4cb4cd1f93b872b3bb810c3b2 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 10 Jun 2025 11:47:41 +0200 Subject: solver3: Ignore Architecture: all for obsoleted-by In case a new version of the source package is published, we check that if there's a newer binary for the same architecture and then consider the binary obsoleted. This logic did not properly account for Architecture: all packages which are considered as native architecture package with an "All" multi-arch flag set, and hence a native architecture package may inadvertently be considered obsoleted by a package that only built on Architecture: all. --- apt-pkg/solver3.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'apt-pkg') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index a458acb0b..c53911a80 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -499,7 +499,9 @@ bool APT::Solver::ObsoletedByNewerSourceVersion(pkgCache::VerIterator cand) cons for (auto ver = cand.Cache()->FindGrp(cand.SourcePkgName()).VersionsInSource(); not ver.end(); ver = ver.NextInSource()) { // We are only interested in other packages in the same source package; built for the same architecture. - if (ver->ParentPkg == cand->ParentPkg || ver.ParentPkg()->Arch != cand.ParentPkg()->Arch || cache.VS->CmpVersion(ver.SourceVerStr(), cand.SourceVerStr()) <= 0) + if (ver->ParentPkg == cand->ParentPkg || ver.ParentPkg()->Arch != cand.ParentPkg()->Arch || + (ver->MultiArch & pkgCache::Version::All) != (cand->MultiArch & pkgCache::Version::All) || + cache.VS->CmpVersion(ver.SourceVerStr(), cand.SourceVerStr()) <= 0) continue; // We also take equal priority here, given that we have a higher version -- cgit v1.2.3-70-g09d2 From 060f4e274f08ea338158606fc81b451924a293d0 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 10 Jun 2025 13:44:18 +0200 Subject: solver3: Explicitly declare and define ~Solver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On recent armfhf and s390x builds in the PPA, the compiler seems to have generated the destructor at the wrong point where the definitions where not yet complete, and it does seem ill-advised to rely on a default-constructed destructor in the solver for future ABI sake. In file included from /usr/include/c++/14/vector:66, from /<>/obj-arm-linux-gnueabihf/include/apt-pkg/cachefilter.h:14: /usr/include/c++/14/bits/stl_vector.h: In instantiation of ‘constexpr std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = APT::Solver::Work; _Alloc = std::allocator]’: /usr/include/c++/14/bits/stl_vector.h:531:7: required from here 531 | vector() = default; | ^~~~~~ /usr/include/c++/14/bits/stl_vector.h:369:49: error: invalid use of incomplete type ‘struct APT::Solver::Work’ 369 | _M_impl._M_end_of_storage - _M_impl._M_start); | ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ In file included from /<>/apt-pkg/edsp.cc:22: /<>/obj-arm-linux-gnueabihf/include/apt-pkg/solver3.h:87:11: note: forward declaration of ‘struct APT::Solver::Work’ 87 | struct Work; | ^~~~ /usr/include/c++/14/bits/stl_vector.h: In instantiation of ‘constexpr std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = APT::Solver::Solved; _Alloc = std::allocator]’: /usr/include/c++/14/bits/stl_vector.h:531:7: required from here 531 | vector() = default; | ^~~~~~ /usr/include/c++/14/bits/stl_vector.h:369:49: error: invalid use of incomplete type ‘struct APT::Solver::Solved’ 369 | _M_impl._M_end_of_storage - _M_impl._M_start); | ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ /<>/obj-arm-linux-gnueabihf/include/apt-pkg/solver3.h:88:11: note: forward declaration of ‘struct APT::Solver::Solved’ 88 | struct Solved; | ^~~~~~ --- apt-pkg/solver3.cc | 2 ++ apt-pkg/solver3.h | 1 + 2 files changed, 3 insertions(+) (limited to 'apt-pkg') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index c53911a80..052142658 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -216,6 +216,8 @@ APT::Solver::Solver(pkgCache &cache, pkgDepCache::Policy &policy, EDSP::Request: rootState->decision = Decision::MUST; } +APT::Solver::~Solver() = default; + // This function determines if a work item is less important than another. bool APT::Solver::Work::operator<(APT::Solver::Work const &b) const { diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h index a333d684a..2331af869 100644 --- a/apt-pkg/solver3.h +++ b/apt-pkg/solver3.h @@ -287,6 +287,7 @@ class Solver // \brief Basic solver initializer. This cannot fail. Solver(pkgCache &Cache, pkgDepCache::Policy &Policy, EDSP::Request::Flags requestFlags); + ~Solver(); // Assume that the variable is decided as specified. [[nodiscard]] bool Assume(Var var, bool decision, const Clause *reason = nullptr); -- cgit v1.2.3-70-g09d2 From b99ec5f1d80962e39e9debb05f1a7c7840e7d97c Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 10 Jun 2025 16:09:19 +0200 Subject: solver3: Filter installed Recommends When inspecting Recommends of installed packages, filter them to the installed packages only, as we want to avoid switching between alternatives of recommended packages. --- apt-pkg/solver3.cc | 10 +++++++++ test/integration/test-solver3-break-recommends | 29 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100755 test/integration/test-solver3-break-recommends (limited to 'apt-pkg') diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index 052142658..c2877946c 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -964,6 +964,16 @@ APT::Solver::Clause APT::Solver::TranslateOrGroup(pkgCache::DepIterator start, p std::cerr << "Promoting new clause to hard dependency: " << clause.toString(cache) << std::endl; clause.optional = false; } + else if (not existing.end() && importantToKeep(start) && satisfied) + { + if (unlikely(debug >= 3)) + std::cerr << "Restricting existing Recommends to installed packages: " << clause.toString(cache, true) << std::endl; + // Erase the non-installed solutions. We will process this last and try to keep the previously installed + // "best" solution installed. + clause.solutions.erase(std::remove_if(clause.solutions.begin(), clause.solutions.end(), [this](auto var) + { return var.CastPkg(cache)->CurrentVer == nullptr; }), + clause.solutions.end()); + } } return clause; diff --git a/test/integration/test-solver3-break-recommends b/test/integration/test-solver3-break-recommends new file mode 100755 index 000000000..88051f5de --- /dev/null +++ b/test/integration/test-solver3-break-recommends @@ -0,0 +1,29 @@ +#!/bin/sh +set -e + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" +setupenvironment +configarchitecture 'amd64' + +insertpackage 'installed' 'root' 'all' '1' 'Recommends: a | b' +insertpackage 'installed,unstable' 'a' 'all' '1' +insertpackage 'unstable' 'b' 'all' '1' + +setupaptarchive + +msgmsg "b should not be installed" + +testsuccessequal "Reading package lists... +Building dependency tree... +The following packages will be REMOVED: + a +0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded. +Remv a [1]" aptget remove a -s + +testsuccessequal "Reading package lists... +Building dependency tree... +The following packages will be REMOVED: + a +0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded. +Remv a [1]" apt remove a -s -- cgit v1.2.3-70-g09d2