From 0c9b835919b687931d619303958aeee186669a69 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Tue, 7 Oct 2025 12:41:21 +0300 Subject: [PATCH] Fixed segfault error when cleaning up libcurl --- include/Helpers/FileDownloader.cpp | 45 +++++++++++++----------------- include/Helpers/FileDownloader.hpp | 10 ++----- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/include/Helpers/FileDownloader.cpp b/include/Helpers/FileDownloader.cpp index 916eafd..007c1ab 100644 --- a/include/Helpers/FileDownloader.cpp +++ b/include/Helpers/FileDownloader.cpp @@ -8,7 +8,7 @@ std::mutex FileDownloader::newDownloadsMutex; std::vector FileDownloader::newDownloads; std::atomic FileDownloader::shutdownThread; -FileDownloader::MultiHandle FileDownloader::mHandle; +CURLM* FileDownloader::mHandle; std::vector FileDownloader::currentDownloads; std::unique_ptr FileDownloader::downloadThread; @@ -22,10 +22,11 @@ std::shared_ptr FileDownloader::download_data_from auto downloadData = std::make_shared(); h.data = downloadData; h.data->status = DownloadData::Status::IN_PROGRESS; - h.eHandle = create_easy_handle(); - curl_easy_setopt(h.eHandle.get(), CURLOPT_URL, url.data()); - disable_ssl_verification(h.eHandle.get()); - save_to_string(h.eHandle.get(), &h.data->str); + h.eHandle = curl_easy_init(); + curl_easy_setopt(h.eHandle, CURLOPT_URL, url.data()); + curl_easy_setopt(h.eHandle, CURLOPT_NOSIGNAL, 1); + disable_ssl_verification(h.eHandle); + save_to_string(h.eHandle, &h.data->str); { std::scoped_lock newDownloadsLock(newDownloadsMutex); @@ -41,7 +42,7 @@ std::shared_ptr FileDownloader::download_data_from void FileDownloader::add_new_handlers_to_multi() { std::scoped_lock newDownloadsLock(newDownloadsMutex); for(auto& handler : newDownloads) { - curl_multi_add_handle(mHandle.get(), handler.eHandle.get()); + curl_multi_add_handle(mHandle, handler.eHandle); currentDownloads.emplace_back(std::move(handler)); } newDownloads.clear(); @@ -50,7 +51,7 @@ void FileDownloader::add_new_handlers_to_multi() { void FileDownloader::download_thread_update() { int stillRunning = 0; - mHandle = create_multi_handle(); + mHandle = curl_multi_init(); add_new_handlers_to_multi(); do { @@ -60,36 +61,42 @@ void FileDownloader::download_thread_update() { CURLMcode mc; int numfds; - mc = curl_multi_perform(mHandle.get(), &stillRunning); + mc = curl_multi_perform(mHandle, &stillRunning); for(;;) { int msgCount; - CURLMsg* eHandleMsg = curl_multi_info_read(mHandle.get(), &msgCount); + CURLMsg* eHandleMsg = curl_multi_info_read(mHandle, &msgCount); if(!eHandleMsg) break; if(eHandleMsg->msg == CURLMSG_DONE) { auto it = std::find_if(currentDownloads.begin(), currentDownloads.end(), [eHandleMsg](auto& d) { - return eHandleMsg->easy_handle == d.eHandle.get(); + return eHandleMsg->easy_handle == d.eHandle; }); if(it != currentDownloads.end()) { DownloadHandler& download = *it; download.data->status = eHandleMsg->data.result == CURLE_OK ? DownloadData::Status::SUCCESS : DownloadData::Status::FAILURE; + curl_multi_remove_handle(mHandle, download.eHandle); + curl_easy_cleanup(download.eHandle); currentDownloads.erase(it); } } } if(mc == CURLM_OK) - curl_multi_poll(mHandle.get(), nullptr, 0, 1000, &numfds); + curl_multi_poll(mHandle, nullptr, 0, 1000, &numfds); else { std::cout << "curl_multi failed" << std::endl; break; } } while(stillRunning); - for(auto& download : currentDownloads) + for(auto& download : currentDownloads) { download.data->status = DownloadData::Status::FAILURE; + curl_multi_remove_handle(mHandle, download.eHandle); + curl_easy_cleanup(download.eHandle); + } currentDownloads.clear(); + curl_multi_cleanup(mHandle); } void FileDownloader::save_to_string(CURL* curl, std::string* str) { @@ -102,20 +109,6 @@ void FileDownloader::disable_ssl_verification(CURL* curl) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); } -FileDownloader::EasyHandle FileDownloader::create_easy_handle() { - auto easyHandle = EasyHandle(curl_easy_init(), curl_easy_cleanup); - if(!easyHandle) - throw std::runtime_error("[FileDownloader::create_easy_handle] Failed to create CURL easy handle"); - return easyHandle; -} - -FileDownloader::MultiHandle FileDownloader::create_multi_handle() { - auto multiHandle = EasyHandle(curl_multi_init(), curl_multi_cleanup); - if(!multiHandle) - throw std::runtime_error("[FileDownloader::create_multi_handle] Failed to create CURL multi handle"); - return multiHandle; -} - size_t FileDownloader::write_to_string(void* contents, size_t size, size_t nmemb, void* userp) { size_t realsize = size * nmemb; auto str = reinterpret_cast(userp); diff --git a/include/Helpers/FileDownloader.hpp b/include/Helpers/FileDownloader.hpp index 06f0c96..0e00811 100644 --- a/include/Helpers/FileDownloader.hpp +++ b/include/Helpers/FileDownloader.hpp @@ -24,21 +24,18 @@ class FileDownloader { static std::shared_ptr download_data_from_url(std::string_view url); static void cleanup(); private: - typedef std::unique_ptr> EasyHandle; - typedef std::unique_ptr> MultiHandle; - static void add_new_handlers_to_multi(); static void download_thread_update(); struct DownloadHandler { - EasyHandle eHandle; + CURL* eHandle; std::shared_ptr data; }; static std::mutex newDownloadsMutex; static std::vector newDownloads; static std::atomic shutdownThread; - static MultiHandle mHandle; + static CURLM* mHandle; static std::vector currentDownloads; static std::unique_ptr downloadThread; @@ -48,9 +45,6 @@ class FileDownloader { static timeval get_timeout(CURLM* mCurl); static int wait_if_needed(CURLM* mCurl, timeval& timeout); - static EasyHandle create_easy_handle(); - static MultiHandle create_multi_handle(); - static size_t write_to_string(void* contents, size_t size, size_t nmemb, void* userp); };