Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
c420ea6130
!98 Fix a memory leak in glob_for_cachedir
From: @han_hui_hui 
Reviewed-by: @anonymous_z 
Signed-off-by: @anonymous_z
2024-11-25 11:08:18 +00:00
hanhuihui
f458cdadf1 Fix a memory leak in glob_for_cachedir 2024-11-25 09:14:46 +00:00
openeuler-ci-bot
d6a36e0156
!82 上游补丁回合
From: @addrexist 
Reviewed-by: @t_feng 
Signed-off-by: @t_feng
2024-07-24 02:42:48 +00:00
wangziliang
f0b24c689b backport 2 patches from upstream 2024-07-02 06:40:42 +00:00
openeuler-ci-bot
d99e9081d9
!79 Fix history rollback cmd not meet the expectation and Fix memory leak in subject-py
From: @han_hui_hui 
Reviewed-by: @anonymous_z 
Signed-off-by: @anonymous_z
2024-06-17 01:34:03 +00:00
hanhuihui
216f116881 Fix history rollback cmd not meet the expectation 2024-06-15 11:07:16 +00:00
openeuler-ci-bot
5e31e3b21c
!71 Fix memory leak detected in get_best_solution() method
From: @xiao-zai-kylinos 
Reviewed-by: @anonymous_z, @zhuchunyi 
Signed-off-by: @anonymous_z, @zhuchunyi
2024-05-22 09:57:05 +00:00
肖在
651579b02e Fix memory leak detected in get_best_solution() method 2024-05-16 18:22:55 +08:00
openeuler-ci-bot
dbdd44d32b
!65 sync upstream patch
From: @chen-haixing-hw 
Reviewed-by: @anonymous_z 
Signed-off-by: @anonymous_z
2024-01-02 11:43:02 +00:00
chenhaixing
2fce2ae05b sync upstream patch 2024-01-02 09:26:56 +00:00
11 changed files with 845 additions and 1 deletions

View File

@ -0,0 +1,97 @@
From 4b016cee3ff42c36349714c1b38b394b4317174f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
Date: Mon, 25 Sep 2023 08:24:40 +0200
Subject: [PATCH] Avoid reinstalling installonly packages marked for ERASE
Without this patch reinstalling installonly pkg marked for ERASE might
be a valid smallest solution to our job.
For example when user wants to install through a provide we select all
packages that provide it and put them inside a `job install oneof ...`
if one of the providers is also marked for ERASE due to installonly
limit libsolv might decide to reinstall it.
To make sure it doesn't happen mark the available package also as ERASE.
https://github.com/openSUSE/libsolv/issues/540
https://issues.redhat.com/browse/RHEL-1253
(https://bugzilla.redhat.com/show_bug.cgi?id=2163474)
Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/commit/4b016cee3ff42c36349714c1b38b394b4317174f
---
libdnf/goal/Goal.cpp | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp
index 42c078286..269f6b398 100644
--- a/libdnf/goal/Goal.cpp
+++ b/libdnf/goal/Goal.cpp
@@ -643,6 +643,12 @@ erase_flags2libsolv(int flags)
return ret;
}
+static bool
+NameSolvableComparator(const Solvable * first, const Solvable * second)
+{
+ return first->name < second->name;
+}
+
Goal::Goal(const Goal & goal_src) : pImpl(new Impl(*goal_src.pImpl)) {}
Goal::Impl::Impl(const Goal::Impl & goal_src)
@@ -1436,10 +1442,24 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)
for (int i = 0; i < onlies->count; ++i) {
Id p, pp;
IdQueue q, installing;
+ std::vector<Solvable *> available_unused_providers;
+ // Add all providers of installonly provides that are marked for install
+ // to `q` IdQueue those that are not marked for install and are not already
+ // installed are added to available_unused_providers.
FOR_PKG_PROVIDES(p, pp, onlies->elements[i])
- if (solver_get_decisionlevel(solv, p) > 0)
+ // According to libsolv-bindings the decision level is positive for installs
+ // and negative for conflicts (conflicts with another package or dependency
+ // conflicts = dependencies cannot be met).
+ if (solver_get_decisionlevel(solv, p) > 0) {
q.pushBack(p);
+ } else {
+ Solvable *s = pool_id2solvable(pool, p);
+ if (s->repo != pool->installed) {
+ available_unused_providers.push_back(s);
+ }
+ }
+
if (q.size() <= (int) dnf_sack_get_installonly_limit(sack)) {
continue;
}
@@ -1457,6 +1477,7 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)
struct InstallonliesSortCallback s_cb = {pool, dnf_sack_running_kernel(sack)};
solv_sort(q.data(), q.size(), sizeof(q[0]), sort_packages, &s_cb);
+ std::sort(available_unused_providers.begin(), available_unused_providers.end(), NameSolvableComparator);
IdQueue same_names;
while (q.size() > 0) {
same_name_subqueue(pool, q.getQueue(), same_names.getQueue());
@@ -1466,8 +1487,18 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)
for (int j = 0; j < same_names.size(); ++j) {
Id id = same_names[j];
Id action = SOLVER_ERASE;
- if (j < (int) dnf_sack_get_installonly_limit(sack))
+ if (j < (int) dnf_sack_get_installonly_limit(sack)) {
action = SOLVER_INSTALL;
+ } else {
+ // We want to avoid reinstalling packages marked for ERASE, therefore
+ // if some unused provider is also available we need to mark it ERASE as well.
+ Solvable *s = pool_id2solvable(pool, id);
+ auto low = std::lower_bound(available_unused_providers.begin(), available_unused_providers.end(), s, NameSolvableComparator);
+ while (low != available_unused_providers.end() && (*low)->name == s->name) {
+ queue_push2(job, SOLVER_ERASE | SOLVER_SOLVABLE, pool_solvable2id(pool, *low));
+ ++low;
+ }
+ }
queue_push2(job, action | SOLVER_SOLVABLE, id);
}
}

View File

@ -0,0 +1,53 @@
From b245193e881912cf730b53ece74c410ef573e292 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
Date: Wed, 17 Jul 2024 09:30:59 +0200
Subject: [PATCH 1/1] Fix a memory leak in glob_for_cachedir()
Covscan complains:
Error: RESOURCE_LEAK (CWE-772): [#def1] [important]
libdnf-0.73.1/libdnf/hy-iutil.cpp:100:5: alloc_arg: "wordexp" allocates memory that is stored into "word_vector.we_wordv".
libdnf-0.73.1/libdnf/hy-iutil.cpp:102:9: leaked_storage: Variable "word_vector" going out of scope leaks the storage "word_vector.we_wordv" points to.
# 100| if (wordexp(p, &word_vector, 0)) {
# 101| g_free(p);
# 102|-> return ret;
# 103| }
# 104| for (guint i = 0; i < word_vector.we_wordc; ++i) {
The issue is that Covscan model thinks that word_vector should be
freed after failing wordexp(). glibc's manual does not explain whether
it is or isn't necessary. However, POSIX manual mentions that the
memory is valid on WRDE_NOSPACE (not enough memory) error. Reading
glibc sources confirms that wordexp() on any error except of
WRDE_NOSPACE cleans up and returns original, intact word_vector.
Therefore I recognize the missing wordfree() call as an error and
this patch fixed it.
---
libdnf/hy-iutil.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libdnf/hy-iutil.cpp b/libdnf/hy-iutil.cpp
index 43314c60..4848c9f7 100644
--- a/libdnf/hy-iutil.cpp
+++ b/libdnf/hy-iutil.cpp
@@ -89,7 +89,7 @@ glob_for_cachedir(char *path)
if (!g_str_has_suffix(path, "XXXXXX"))
return ret;
- wordexp_t word_vector;
+ wordexp_t word_vector = {0};
char *p = g_strdup(path);
const int len = strlen(p);
struct stat s;
@@ -98,6 +98,7 @@ glob_for_cachedir(char *path)
p[len-6] = '*';
p[len-5] = '\0';
if (wordexp(p, &word_vector, 0)) {
+ wordfree(&word_vector);
g_free(p);
return ret;
}
--
2.25.1

View File

@ -0,0 +1,130 @@
From cc95edd15b8a4fc4c381c85735e2f14a1dc0852e Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Wed, 8 May 2024 12:05:21 +0200
Subject: [PATCH] Fix countme bucket calculation
Actually use the system's installation time (if known) as the reference
point, instead of the first-ever countme event recorded for the given
repo.
This is what the dnf.conf(5) man page always said about the countme
option, the code just never lived up to that.
This makes bucket calculation more accurate:
1. System upgrades will no longer reset the bucket to 1 (this used to be
the case due to a new persistdir being created whenever $releasever
changed).
2. Systems that only reach out to the repos after an initial time period
after being installed will no longer appear younger than they really
are.
3. Prebuilt OS images that happen to include countme cookies created at
build time will no longer cause all the instances spawned from those
images (physical machines, VMs or containers) to appear older than
they really are.
Use the machine-id(5) file's mtime to infer the installation time. This
file is semantically tied to the system's lifetime since it's typically
populated at installation time or during the first boot by an installer
tool or init system, respectively, and remains unchanged.
The fact that it's a well-defined file with clear semantics ensures that
OS images won't accidentally include a prepopulated version of this file
with a timestamp corresponding to the image build, unlike our own cookie
files (see point 3 above).
In some cases, such as in OCI containers without an init system running,
the machine-id file may be missing or empty, even though the system is
still used long-term. To cover those, keep the original, relative epoch
as a fallback method. System upgrades aren't really a thing for such
systems so the above point 1 doesn't apply here.
Some containers, such as those created by toolbox(1), may also choose to
bind-mount the host's machine-id file, thus falling into the same bucket
as their host. Conveniently, that's what we want, since the purpose of
such containers is to blend with the host as much as possible.
Fixes: #1611
---
libdnf/repo/Repo-private.hpp | 1 +
libdnf/repo/Repo.cpp | 34 +++++++++++++++++++++++++++++++++-
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/libdnf/repo/Repo-private.hpp b/libdnf/repo/Repo-private.hpp
index 1f659e6f..88cadf7d 100644
--- a/libdnf/repo/Repo-private.hpp
+++ b/libdnf/repo/Repo-private.hpp
@@ -91,6 +91,7 @@ public:
void fetch(const std::string & destdir, std::unique_ptr<LrHandle> && h);
std::string getCachedir() const;
std::string getPersistdir() const;
+ time_t getSystemEpoch() const;
int getAge() const;
void expire();
bool isExpired() const;
diff --git a/libdnf/repo/Repo.cpp b/libdnf/repo/Repo.cpp
index 40b0b68e..ead98618 100644
--- a/libdnf/repo/Repo.cpp
+++ b/libdnf/repo/Repo.cpp
@@ -900,7 +900,7 @@ void Repo::Impl::addCountmeFlag(LrHandle *handle) {
// Load the cookie
std::string fname = getPersistdir() + "/" + COUNTME_COOKIE;
int ver = COUNTME_VERSION; // file format version (for future use)
- time_t epoch = 0; // position of first-ever counted window
+ time_t epoch = 0; // position of first observed window
time_t win = COUNTME_OFFSET; // position of last counted window
int budget = -1; // budget for this window (-1 = generate)
std::ifstream(fname) >> ver >> epoch >> win >> budget;
@@ -926,8 +926,15 @@ void Repo::Impl::addCountmeFlag(LrHandle *handle) {
// Compute the position of this window
win = now - (delta % COUNTME_WINDOW);
+
+ // Compute the epoch from this system's epoch or, if unknown, declare
+ // this window as the epoch (unless stored in the cookie previously).
+ time_t sysepoch = getSystemEpoch();
+ if (sysepoch)
+ epoch = sysepoch - ((sysepoch - COUNTME_OFFSET) % COUNTME_WINDOW);
if (!epoch)
epoch = win;
+
// Window step (0 at epoch)
int step = (win - epoch) / COUNTME_WINDOW;
@@ -1221,6 +1228,31 @@ std::string Repo::Impl::getPersistdir() const
return result;
}
+/* Returns this system's installation time ("epoch") as a UNIX timestamp.
+ *
+ * Uses the machine-id(5) file's mtime as a good-enough source of truth. This
+ * file is typically tied to the system's installation or first boot where it's
+ * populated by an installer tool or init system, respectively, and is never
+ * changed afterwards.
+ *
+ * Some systems, such as containers that don't run an init system, may have the
+ * file missing, empty or uninitialized, in which case this function returns 0.
+ */
+time_t Repo::Impl::getSystemEpoch() const
+{
+ std::string filename = "/etc/machine-id";
+ std::string id;
+ struct stat st;
+
+ if (stat(filename.c_str(), &st) != 0 || !st.st_size)
+ return 0;
+ std::ifstream(filename) >> id;
+ if (id == "uninitialized")
+ return 0;
+
+ return st.st_mtime;
+}
+
int Repo::Impl::getAge() const
{
return time(NULL) - mtime(getMetadataPath(MD_TYPE_PRIMARY).c_str());
--
2.33.0

View File

@ -0,0 +1,39 @@
From 9c6e1c90b96cdb44d0093e417bd5d2e710881f94 Mon Sep 17 00:00:00 2001
From: Michal Domonkos <mdomonko@redhat.com>
Date: Wed, 8 May 2024 12:05:16 +0200
Subject: [PATCH] Fix up some comments in addCountmeFlag()
The buckets aren't really an array that's indexed in the code, they're
just sequential numbers for the URL flag. Also clarify why we're using
"this window" instead of "the current position of the sliding window" in
the comments.
---
libdnf/repo/Repo.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libdnf/repo/Repo.cpp b/libdnf/repo/Repo.cpp
index 73a3d7b4..40b0b68e 100644
--- a/libdnf/repo/Repo.cpp
+++ b/libdnf/repo/Repo.cpp
@@ -873,6 +873,9 @@ void Repo::Impl::addCountmeFlag(LrHandle *handle) {
* This is to align the time window with an absolute point in time rather
* than the last counting event (which could facilitate tracking across
* multiple such events).
+ *
+ * In the below comments, the window's current position will be referred to
+ * as "this window" for brevity.
*/
auto logger(Log::getLogger());
@@ -933,7 +936,7 @@ void Repo::Impl::addCountmeFlag(LrHandle *handle) {
for (i = 0; i < COUNTME_BUCKETS.size(); ++i)
if (step < COUNTME_BUCKETS[i])
break;
- int bucket = i + 1; // Buckets are indexed from 1
+ int bucket = i + 1; // Buckets are numbered from 1
// Set the flag
std::string flag = "countme=" + std::to_string(bucket);
--
2.33.0

View File

@ -0,0 +1,172 @@
From 54823d82a1369c25ba1a68c18ea2a67c41f4fbe7 Mon Sep 17 00:00:00 2001
From: Jan Kolarik <jkolarik@redhat.com>
Date: Mon, 26 Feb 2024 09:58:33 +0000
Subject: [PATCH] MergedTransaction: Calculate RPM difference between two same
versions as no-op
If a package of a particular version is installed and would still be installed after a list of transactions, it's more user friendly to treat the whole situation as "do nothing".
Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/commit/54823d82a1369c25ba1a68c18ea2a67c41f4fbe7
---
libdnf/transaction/MergedTransaction.cpp | 38 ++++++++++++-------
libdnf/transaction/MergedTransaction.hpp | 6 +--
.../transaction/MergedTransactionTest.cpp | 7 +---
3 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp
index a8d878cb51..8f26882f71 100644
--- a/libdnf/transaction/MergedTransaction.cpp
+++ b/libdnf/transaction/MergedTransaction.cpp
@@ -192,7 +192,7 @@ static bool transaction_item_sort_function(const std::shared_ptr<TransactionItem
* Actions are merged using following rules:
* (old action) -> (new action) = (merged action)
*
- * Erase/Obsolete -> Install/Obsoleting = Reinstall/Downgrade/Upgrade
+ * Erase/Obsolete -> Install/Obsoleting = Downgrade/Upgrade
*
* Reinstall/Reason change -> (new action) = (new action)
*
@@ -210,6 +210,9 @@ static bool transaction_item_sort_function(const std::shared_ptr<TransactionItem
*
* With complete transaction pair we need to get a new Upgrade/Downgrade package and
* compare versions with original package from pair.
+ *
+ * Additionally, if a package is installed both before and after the list of transactions
+ * with the same version, no action will be taken.
*/
std::vector< TransactionItemBasePtr >
MergedTransaction::getItems()
@@ -261,13 +264,16 @@ getItemIdentifier(ItemPtr item)
/**
* Resolve the difference between RPMs in the first and second transaction item
- * and create a ItemPair of Upgrade, Downgrade or reinstall.
+ * and create a ItemPair of Upgrade, Downgrade or drop the item from the merged
+ * transaction set in case of both packages are of the same version.
* Method is called when original package is being removed and than installed again.
+ * \param itemPairMap merged transaction set
* \param previousItemPair original item pair
* \param mTransItem new transaction item
*/
void
-MergedTransaction::resolveRPMDifference(ItemPair &previousItemPair,
+MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap,
+ ItemPair &previousItemPair,
TransactionItemBasePtr mTransItem)
{
auto firstItem = previousItemPair.first->getItem();
@@ -277,11 +283,10 @@ MergedTransaction::resolveRPMDifference(ItemPair &previousItemPair,
auto secondRPM = std::dynamic_pointer_cast< RPMItem >(secondItem);
if (firstRPM->getVersion() == secondRPM->getVersion() &&
- firstRPM->getEpoch() == secondRPM->getEpoch()) {
- // reinstall
- mTransItem->setAction(TransactionItemAction::REINSTALL);
- previousItemPair.first = mTransItem;
- previousItemPair.second = nullptr;
+ firstRPM->getEpoch() == secondRPM->getEpoch() &&
+ firstRPM->getRelease() == secondRPM->getRelease()) {
+ // Drop the item from merged transaction
+ itemPairMap.erase(getItemIdentifier(firstItem));
return;
} else if ((*firstRPM) < (*secondRPM)) {
// Upgrade to secondRPM
@@ -296,7 +301,9 @@ MergedTransaction::resolveRPMDifference(ItemPair &previousItemPair,
}
void
-MergedTransaction::resolveErase(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem)
+MergedTransaction::resolveErase(ItemPairMap &itemPairMap,
+ ItemPair &previousItemPair,
+ TransactionItemBasePtr mTransItem)
{
/*
* The original item has been removed - it has to be installed now unless the rpmdb
@@ -306,7 +313,7 @@ MergedTransaction::resolveErase(ItemPair &previousItemPair, TransactionItemBaseP
if (mTransItem->getAction() == TransactionItemAction::INSTALL) {
if (mTransItem->getItem()->getItemType() == ItemType::RPM) {
// resolve the difference between RPM packages
- resolveRPMDifference(previousItemPair, mTransItem);
+ resolveRPMDifference(itemPairMap, previousItemPair, mTransItem);
} else {
// difference between comps can't be resolved
mTransItem->setAction(TransactionItemAction::REINSTALL);
@@ -323,11 +330,14 @@ MergedTransaction::resolveErase(ItemPair &previousItemPair, TransactionItemBaseP
* transaction - new package is used to complete the pair. Items are stored in pairs (Upgrade,
* Upgrade) or (Downgraded, Downgrade). With complete transaction pair we need to get the new
* Upgrade/Downgrade item and compare its version with the original item from the pair.
+ * \param itemPairMap merged transaction set
* \param previousItemPair original item pair
* \param mTransItem new transaction item
*/
void
-MergedTransaction::resolveAltered(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem)
+MergedTransaction::resolveAltered(ItemPairMap &itemPairMap,
+ ItemPair &previousItemPair,
+ TransactionItemBasePtr mTransItem)
{
auto newState = mTransItem->getAction();
auto firstState = previousItemPair.first->getAction();
@@ -369,7 +379,7 @@ MergedTransaction::resolveAltered(ItemPair &previousItemPair, TransactionItemBas
} else {
if (mTransItem->getItem()->getItemType() == ItemType::RPM) {
// resolve the difference between RPM packages
- resolveRPMDifference(previousItemPair, mTransItem);
+ resolveRPMDifference(itemPairMap, previousItemPair, mTransItem);
} else {
// difference between comps can't be resolved
previousItemPair.second->setAction(TransactionItemAction::REINSTALL);
@@ -405,7 +415,7 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT
switch (firstState) {
case TransactionItemAction::REMOVE:
case TransactionItemAction::OBSOLETED:
- resolveErase(previousItemPair, mTransItem);
+ resolveErase(itemPairMap, previousItemPair, mTransItem);
break;
case TransactionItemAction::INSTALL:
// the original package has been installed -> it may be either Removed, or altered
@@ -432,7 +442,7 @@ MergedTransaction::mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr mT
case TransactionItemAction::UPGRADE:
case TransactionItemAction::UPGRADED:
case TransactionItemAction::OBSOLETE:
- resolveAltered(previousItemPair, mTransItem);
+ resolveAltered(itemPairMap, previousItemPair, mTransItem);
break;
case TransactionItemAction::REINSTALLED:
break;
diff --git a/libdnf/transaction/MergedTransaction.hpp b/libdnf/transaction/MergedTransaction.hpp
index dbb8af1183..f85b133a87 100644
--- a/libdnf/transaction/MergedTransaction.hpp
+++ b/libdnf/transaction/MergedTransaction.hpp
@@ -76,9 +76,9 @@ class MergedTransaction {
typedef std::map< std::string, ItemPair > ItemPairMap;
void mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr transItem);
- void resolveRPMDifference(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
- void resolveErase(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
- void resolveAltered(ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+ void resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+ void resolveErase(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+ void resolveAltered(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
};
} // namespace libdnf
diff --git a/tests/libdnf/transaction/MergedTransactionTest.cpp b/tests/libdnf/transaction/MergedTransactionTest.cpp
index 52507700bc..35fb4250e4 100644
--- a/tests/libdnf/transaction/MergedTransactionTest.cpp
+++ b/tests/libdnf/transaction/MergedTransactionTest.cpp
@@ -822,12 +822,7 @@ MergedTransactionTest::test_downgrade_upgrade_remove()
// test merging trans1, trans2
merged.merge(trans2);
auto items2 = merged.getItems();
- CPPUNIT_ASSERT_EQUAL(1, (int)items2.size());
- auto item2 = items2.at(0);
- CPPUNIT_ASSERT_EQUAL(std::string("tour-4.8-1.noarch"), item2->getItem()->toStr());
- CPPUNIT_ASSERT_EQUAL(std::string("repo1"), item2->getRepoid());
- CPPUNIT_ASSERT_EQUAL(TransactionItemAction::REINSTALL, item2->getAction());
- CPPUNIT_ASSERT_EQUAL(TransactionItemReason::USER, item2->getReason());
+ CPPUNIT_ASSERT_EQUAL(0, (int)items2.size());
// test merging trans1, trans2, trans3
merged.merge(trans3);

View File

@ -0,0 +1,86 @@
From 90d2ffad964a91a7a798b81e15c16eb1e840f257 Mon Sep 17 00:00:00 2001
From: Jan Kolarik <jkolarik@redhat.com>
Date: Tue, 23 Apr 2024 14:11:19 +0000
Subject: [PATCH] MergedTransaction: Fix invalid memory access when dropping
items
When an item is dropped from the merged transaction, the `ItemPair` reference becomes invalid and should no longer be used.
Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/commit/90d2ffad964a91a7a798b81e15c16eb1e840f257
---
libdnf/transaction/MergedTransaction.cpp | 18 +++++++++++-------
libdnf/transaction/MergedTransaction.hpp | 2 +-
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/libdnf/transaction/MergedTransaction.cpp b/libdnf/transaction/MergedTransaction.cpp
index 8f26882f7..75d2c1e78 100644
--- a/libdnf/transaction/MergedTransaction.cpp
+++ b/libdnf/transaction/MergedTransaction.cpp
@@ -264,14 +264,15 @@ getItemIdentifier(ItemPtr item)
/**
* Resolve the difference between RPMs in the first and second transaction item
- * and create a ItemPair of Upgrade, Downgrade or drop the item from the merged
- * transaction set in case of both packages are of the same version.
- * Method is called when original package is being removed and than installed again.
+ * and create a ItemPair of Upgrade, Downgrade or remove the item from the merged
+ * transaction set in case of both packages are the same.
+ * Method is called when original package is being removed and then installed again.
* \param itemPairMap merged transaction set
* \param previousItemPair original item pair
* \param mTransItem new transaction item
+ * \return true if the original and new transaction item differ
*/
-void
+bool
MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap,
ItemPair &previousItemPair,
TransactionItemBasePtr mTransItem)
@@ -287,7 +288,7 @@ MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap,
firstRPM->getRelease() == secondRPM->getRelease()) {
// Drop the item from merged transaction
itemPairMap.erase(getItemIdentifier(firstItem));
- return;
+ return false;
} else if ((*firstRPM) < (*secondRPM)) {
// Upgrade to secondRPM
previousItemPair.first->setAction(TransactionItemAction::UPGRADED);
@@ -298,6 +299,7 @@ MergedTransaction::resolveRPMDifference(ItemPairMap &itemPairMap,
mTransItem->setAction(TransactionItemAction::DOWNGRADE);
}
previousItemPair.second = mTransItem;
+ return true;
}
void
@@ -308,12 +310,14 @@ MergedTransaction::resolveErase(ItemPairMap &itemPairMap,
/*
* The original item has been removed - it has to be installed now unless the rpmdb
* has changed. Resolve the difference between packages and mark it as Upgrade,
- * Reinstall or Downgrade
+ * Downgrade or remove it from the transaction
*/
if (mTransItem->getAction() == TransactionItemAction::INSTALL) {
if (mTransItem->getItem()->getItemType() == ItemType::RPM) {
// resolve the difference between RPM packages
- resolveRPMDifference(itemPairMap, previousItemPair, mTransItem);
+ if (!resolveRPMDifference(itemPairMap, previousItemPair, mTransItem)) {
+ return;
+ }
} else {
// difference between comps can't be resolved
mTransItem->setAction(TransactionItemAction::REINSTALL);
diff --git a/libdnf/transaction/MergedTransaction.hpp b/libdnf/transaction/MergedTransaction.hpp
index f85b133a8..50212159b 100644
--- a/libdnf/transaction/MergedTransaction.hpp
+++ b/libdnf/transaction/MergedTransaction.hpp
@@ -76,7 +76,7 @@ class MergedTransaction {
typedef std::map< std::string, ItemPair > ItemPairMap;
void mergeItem(ItemPairMap &itemPairMap, TransactionItemBasePtr transItem);
- void resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
+ bool resolveRPMDifference(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
void resolveErase(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
void resolveAltered(ItemPairMap &itemPairMap, ItemPair &previousItemPair, TransactionItemBasePtr mTransItem);
};

View File

@ -0,0 +1,26 @@
From 933f00f5366e9935c9f00f842a4bb60b7da87ad4 Mon Sep 17 00:00:00 2001
From: Alessandro Astone <ales.astone@gmail.com>
Date: Sun, 1 Oct 2023 19:18:54 +0200
Subject: [PATCH] dnf-repo: Fix utimes error message
Oops, syscall returns 0 on success
Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/commit/933f00f5366e9935c9f00f842a4bb60b7da87ad4
---
libdnf/dnf-repo.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
index c2495f564..ca3d1920a 100644
--- a/libdnf/dnf-repo.cpp
+++ b/libdnf/dnf-repo.cpp
@@ -1798,7 +1798,7 @@ dnf_repo_update(DnfRepo *repo,
if (repoImpl->isInSync()) {
/* reset timestamp */
ret = utimes(repoImpl->repomdFn.c_str(), NULL);
- if (!ret)
+ if (ret != 0)
g_debug("Failed to reset timestamp on repomd.xml");
ret = dnf_state_done(state, error);
if (!ret)

View File

@ -0,0 +1,95 @@
From e7cf3d198e7b107cffc788f96f51fde2d843dd82 Mon Sep 17 00:00:00 2001
From: Alessandro Astone <ales.astone@gmail.com>
Date: Thu, 28 Sep 2023 14:50:22 +0200
Subject: [PATCH] dnf-repo: Don't download repository if our local cache is up
to date
Verified by comparing the hash of repomd.xml
Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/commit/e7cf3d198e7b107cffc788f96f51fde2d843dd82
---
libdnf/dnf-repo.cpp | 34 ++++++++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp
index 48434fd9be..c2495f564e 100644
--- a/libdnf/dnf-repo.cpp
+++ b/libdnf/dnf-repo.cpp
@@ -969,6 +969,9 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, gboolean reloadFromGKeyFile, GError **e
dnf_repo_apply_setopts(*conf, repoId);
}
+ if (dnf_context_get_cache_dir(priv->context))
+ conf->basecachedir().set(libdnf::Option::Priority::REPOCONFIG, dnf_context_get_cache_dir(priv->context));
+
/* baseurl is optional; if missing, unset it */
g_auto(GStrv) baseurls = NULL;
auto & repoBaseurls = conf->baseurl().getValue();
@@ -1463,6 +1466,7 @@ dnf_repo_check_internal(DnfRepo *repo,
error_local->message);
return FALSE;
}
+ repoImpl->repomdFn = yum_repo->repomd;
/* get timestamp */
ret = lr_result_getinfo(priv->repo_result, &error_local,
@@ -1765,8 +1769,10 @@ dnf_repo_update(DnfRepo *repo,
if (!dnf_repo_set_keyfile_data(repo, TRUE, error))
return FALSE;
+ auto repoImpl = libdnf::repoGetImpl(priv->repo);
+
/* countme support */
- libdnf::repoGetImpl(priv->repo)->addCountmeFlag(priv->repo_handle);
+ repoImpl->addCountmeFlag(priv->repo_handle);
/* take lock */
ret = dnf_state_take_lock(state,
@@ -1784,6 +1790,28 @@ dnf_repo_update(DnfRepo *repo,
if (!ret)
goto out;
+ state_local = dnf_state_get_child(state);
+ dnf_state_action_start(state_local,
+ DNF_STATE_ACTION_DOWNLOAD_METADATA, NULL);
+
+ try {
+ if (repoImpl->isInSync()) {
+ /* reset timestamp */
+ ret = utimes(repoImpl->repomdFn.c_str(), NULL);
+ if (!ret)
+ g_debug("Failed to reset timestamp on repomd.xml");
+ ret = dnf_state_done(state, error);
+ if (!ret)
+ goto out;
+
+ /* skip check */
+ ret = dnf_state_finished(state, error);
+ goto out;
+ }
+ } catch (std::exception & ex) {
+ g_debug("Failed to verify if metadata is in sync: \"%s\". Proceding with download", ex.what());
+ }
+
/* remove the temporary space if it already exists */
if (g_file_test(priv->location_tmp, G_FILE_TEST_EXISTS)) {
ret = dnf_remove_recursive(priv->location_tmp, error);
@@ -1842,7 +1870,7 @@ dnf_repo_update(DnfRepo *repo,
goto out;
/* Callback to display progress of downloading */
- state_local = updatedata.state = dnf_state_get_child(state);
+ updatedata.state = state_local;
ret = lr_handle_setopt(priv->repo_handle, error,
LRO_PROGRESSDATA, &updatedata);
if (!ret)
@@ -1867,8 +1895,6 @@ dnf_repo_update(DnfRepo *repo,
}
lr_result_clear(priv->repo_result);
- dnf_state_action_start(state_local,
- DNF_STATE_ACTION_DOWNLOAD_METADATA, NULL);
ret = lr_handle_perform(priv->repo_handle,
priv->repo_result,
&error_local);

View File

@ -0,0 +1,76 @@
From 8a8548de607e0488fd4b8ab05373749545a29342 Mon Sep 17 00:00:00 2001
From: Mark Johnston <markj@FreeBSD.org>
Date: Thu, 24 Aug 2023 17:43:36 -0400
Subject: [PATCH] python bindings: Load all modules with RTLD_GLOBAL
libdnf's python bindings are implemented by a set of C++ shared objects
generated by swig. Some generated code is duplicated between modules,
in particular the SwigPyIterator class templates, which use exceptions
of type swig::stop_iteration to signal an end-of-iteration condition.
The modules do not depend on each other and thus belong to different
DAGs from the perspective of the runtime linker.
It turns out that this stop_iteration exception can be thrown between
modules. This happens at least during dnf startup with python 3.9:
cli.py(935): subst.update_from_etc(from_root, varsdir=conf._get_value('varsdir'))
--- modulename: config, funcname: _get_value
config.py(102): method = getattr(self._config, name, None)
config.py(103): if method is None:
config.py(105): return method().getValue()
--- modulename: conf, funcname: varsdir
conf.py(1183): return _conf.ConfigMain_varsdir(self)
--- modulename: conf, funcname: getValue
conf.py(512): return _conf.OptionStringList_getValue(self)
--- modulename: substitutions, funcname: update_from_etc
substitutions.py(47): for vars_path in varsdir:
--- modulename: module, funcname: __iter__
module.py(557): return self.iterator()
--- modulename: module, funcname: iterator
module.py(555): return _module.VectorString_iterator(self)
--- modulename: transaction, funcname: __next__
transaction.py(94): return _transaction.SwigPyIterator___next__(self)
In particular, the module and transaction modules are somehow both
involved: module returns the iterator, and transaction advances the
iterator. Both modules contain the same iterator code, so I'm not sure
why it works this way. The behaviour is sensitive to import order; for
example, if transaction is imported before module, then the code above
ends up using module's implementation of SwigPyItreator___next__.
In any case, the use of swig::stop_iteration is broken in the above
scenario since the exception is thrown by module with module.so's copy
of the swig::stop_iteration type info, and caught by transaction.so
using transaction.so's copy of the type info, resulting in an uncaught
exception.
Work around the problem by loading all modules with RTLD_GLOBAL to
ensure that RTTI is unique. This is required when throwing exceptions
across DSO boundaries, see https://gcc.gnu.org/faq.html#dso for example.
Conflict:NA
Reference:https://github.com/rpm-software-management/libdnf/commit/8a8548de607e0488fd4b8ab05373749545a29342
---
bindings/python/__init__.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/bindings/python/__init__.py b/bindings/python/__init__.py
index 3bfd3a9441..07cf1959d5 100644
--- a/bindings/python/__init__.py
+++ b/bindings/python/__init__.py
@@ -6,11 +6,14 @@
import sys, os
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
from . import error
-sys.setdlopenflags(os.RTLD_NOW)
+# Other modules also need to be loaded with RTLD_GLOBAL to preserve uniqueness
+# of RTTI. There are code paths where an exception thrown in one module is
+# supposed to be caught in another.
from . import common_types
from . import conf
from . import module
from . import repo
from . import transaction
from . import utils
+sys.setdlopenflags(os.RTLD_NOW)

View File

@ -0,0 +1,29 @@
From fd284bda6f7430b2e939f95c6836c972e22a2eb4 Mon Sep 17 00:00:00 2001
From: Marek Blaha <mblaha@redhat.com>
Date: Tue, 26 Mar 2024 14:09:47 +0100
Subject: [PATCH 293/300] subject-py: Fix memory leak
Posible memory leak was detected in get_best_solution() method.
---
python/hawkey/subject-py.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/python/hawkey/subject-py.cpp b/python/hawkey/subject-py.cpp
index a88d572a..3e1919e7 100644
--- a/python/hawkey/subject-py.cpp
+++ b/python/hawkey/subject-py.cpp
@@ -361,8 +361,10 @@ get_best_solution(_SubjectObject *self, PyObject *args, PyObject *kwds)
HyNevra nevra{nullptr};
UniquePtrPyObject q(get_solution(self, args, kwds, &nevra));
- if (!q)
+ if (!q) {
+ delete nevra;
return NULL;
+ }
PyObject *ret_dict = PyDict_New();
PyDict_SetItem(ret_dict, PyString_FromString("query"), q.get());
if (nevra) {
--
2.33.0

View File

@ -18,7 +18,7 @@
Name: libdnf
Version: 0.70.2
Release: 1
Release: 6
Summary: Library providing simplified C and Python API to libsolv
License: LGPL-2.1-or-later
URL: https://github.com/rpm-software-management/libdnf
@ -44,6 +44,17 @@ Obsoletes: python2-libdnf-debuginfo < %{version}-%{release}
Patch6001: 0001-libdnf-0.65.0-add-loongarch-support.patch
%endif
Patch6002: backport-python-bindings-Load-all-modules-with-RTLD_GLOBAL.patch
Patch6003: backport-Avoid-reinstalling-installonly-packages-marked-for-ERASE.patch
Patch6004: backport-dnf-repo-do-not-download-repository-if-our-local-cache-is-up-to-date.patch
Patch6005: backport-dnf-repo-Fix-utimes-error-messages.patch
Patch6006: backport-subject-py-Fix-memory-leak.patch
Patch6007: backport-MergedTransaction-Calculate-RPM-difference-between-two-same-versions-as-no-op.patch
Patch6008: backport-MergedTransaction-Fix-invalid-memory-access-when-dropping.patch
Patch6009: backport-Fix-countme-bucket-calculation.patch
Patch6010: backport-Fix-up-some-comments-in-addCountmeFlag.patch
Patch6011: backport-Fix-a-memory-leak-in-glob_for_cachedir.patch
%description
A Library providing simplified C and Python API to libsolv.
@ -122,6 +133,36 @@ popd
%{python3_sitearch}/hawkey/
%changelog
* Mon Jul 29 2024 Wenhua Huang <huangwenhua@Kylinos.cn> - 0.70.2-6
- Fix a memory leak in glob_for_cachedir()
* Tue Jul 02 2024 wangziliang <wangziliang@kylinos.cn> - 0.70.2-5
- Type:bugfix
- CVE:NA
- SUG:NA
- DESC: Fix countme bucket calculation
* Fri Jun 14 2024 hanhuihui <hanhuihui5@huawei.com> - 0.70.2-4
- Type:bugfix
- CVE:NA
- SUG:NA
- DESC:Fix history rollback cmd not meet the expectation
* Thu May 16 2024 xiaozai <xiaozai@kylinos.cn> - 0.70.2-3
- Type:bugfix
- CVE:NA
- SUG:NA
- DESC: Fix memory leak detected in get_best_solution() method
* Tue Jan 02 2024 chenhaixing <chenhaixing@huawei.com> - 0.70.2-2
- Type:bugfix
- CVE:NA
- SUG:NA
- DESC:libdnf:Avoid reinstalling installonly packages marked for ERASE
Fix utimes error message in dnf-repo
Do not download repository if our local cache is up to date in dnf-repo
python bindings:Load all modules with RTLD_GLOBAL
* Sat Jul 29 2023 zhangrui <zhangrui182@huawei.com> - 0.70.2-1
- Type:bugfix
- CVE:NA