dnfdaemon: Fix a crash under dnf5daemon::DownloadCB::create_signal_download()

The compiler decides when the variables are freed at the end of the function
and when the `user_data` is freed before the `downloader`, then the `downloader`
uses just freed `user_data` in the callbacks. The free order can be different
when the function is left due to an exception.

Fixes https://github.com/rpm-software-management/dnf5/issues/2015
This commit is contained in:
Milan Crha 2025-07-03 18:54:38 +02:00 committed by Petr Pisar
parent 2b466777a8
commit 3fb6c85464
1 changed files with 16 additions and 12 deletions

View File

@ -325,20 +325,24 @@ bool Session::check_authorization(
}
void Session::download_transaction_packages() {
libdnf5::repo::PackageDownloader downloader(base->get_weak_ptr());
// container is owner of package callbacks user_data
// container is owner of package callbacks user_data;
std::vector<std::unique_ptr<dnf5daemon::DownloadUserData>> user_data;
for (auto & tspkg : transaction->get_transaction_packages()) {
if (transaction_item_action_is_inbound(tspkg.get_action()) &&
tspkg.get_package().get_repo()->get_type() != libdnf5::repo::Repo::Type::COMMANDLINE) {
auto & data = user_data.emplace_back(std::make_unique<dnf5daemon::DownloadUserData>());
data->download_id = "package:" + std::to_string(tspkg.get_package().get_id().id);
downloader.add(tspkg.get_package(), data.get());
}
}
// make sure the user_data is freed after the downloader, because the
// downloader can call download_end signal during its destructor
{
libdnf5::repo::PackageDownloader downloader(base->get_weak_ptr());
downloader.download();
for (auto & tspkg : transaction->get_transaction_packages()) {
if (transaction_item_action_is_inbound(tspkg.get_action()) &&
tspkg.get_package().get_repo()->get_type() != libdnf5::repo::Repo::Type::COMMANDLINE) {
auto & data = user_data.emplace_back(std::make_unique<dnf5daemon::DownloadUserData>());
data->download_id = "package:" + std::to_string(tspkg.get_package().get_id().id);
downloader.add(tspkg.get_package(), data.get());
}
}
downloader.download();
}
}
void Session::store_transaction_offline() {