https://bugs.gentoo.org/939813 https://github.com/ostreedev/ostree/pull/3307 From 4d755a85225ea0a02d4580d088bb8a97138cb040 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 18 Sep 2024 13:41:59 -0400 Subject: [PATCH] curl: Make socket callback during cleanup into no-op Because curl_multi_cleanup may invoke callbacks, we effectively have some circular references going on here. See discussion in https://github.com/curl/curl/issues/14860 Basically what we do is the socket callback libcurl may invoke into a no-op when we detect we're finalizing. The data structures are owned by this object and not by the callbacks, and will be destroyed below. Note that e.g. g_hash_table_unref() may itself invoke callbacks, which is where some data is cleaned up. Signed-off-by: Colin Walters --- a/src/libostree/ostree-fetcher-curl.c +++ b/src/libostree/ostree-fetcher-curl.c @@ -78,6 +78,7 @@ struct OstreeFetcher struct curl_slist *extra_headers; int tmpdir_dfd; bool force_anonymous; + bool finalizing; // Set if we're in the process of teardown char *custom_user_agent; guint32 opt_low_speed_limit; guint32 opt_low_speed_time; @@ -180,6 +181,15 @@ _ostree_fetcher_finalize (GObject *object) { OstreeFetcher *self = OSTREE_FETCHER (object); + // Because curl_multi_cleanup may invoke callbacks, we effectively have + // some circular references going on here. See discussion in + // https://github.com/curl/curl/issues/14860 + // Basically what we do is make most callbacks libcurl may invoke into no-ops when + // we detect we're finalizing. The data structures are owned by this object and + // not by the callbacks, and will be destroyed below. Note that + // e.g. g_hash_table_unref() may itself invoke callbacks, which is where + // some data is cleaned up. + self->finalizing = true; curl_multi_cleanup (self->multi); g_free (self->remote_name); g_free (self->tls_ca_db_path); @@ -528,6 +538,10 @@ sock_cb (CURL *easy, curl_socket_t s, int what, void *cbp, void *sockp) OstreeFetcher *fetcher = cbp; SockInfo *fdp = (SockInfo *)sockp; + // We do nothing if we're in the process of teardown; see below. + if (fetcher->finalizing) + return 0; + if (what == CURL_POLL_REMOVE) { if (!g_hash_table_remove (fetcher->sockets, fdp))