From f8bc386fec4784d3d18852e6271caaaa8e0dc98c Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 11:46:30 +0200 Subject: [PATCH 1/2] fix(curl): Statically initialize linked function table The linked curl path populated g_curl on every SDK initialization. Options can outlive sentry_close() through references held by telemetry producers, allowing a previous curl client to be freed concurrently with the next initialization. This raced teardown reads of easy_cleanup and global_cleanup against writes to the same function pointers. Initialize the linked table at compile time and make it immutable. The runtime-loaded path is not subject to this race. After its first successful symbol resolution, g_curl.handle remains set for the process lifetime, so later initializations return without rewriting the table. Resolution failures occur before a client can use the resolved entries. --- src/transports/sentry_http_transport_curl.c | 30 ++++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/transports/sentry_http_transport_curl.c b/src/transports/sentry_http_transport_curl.c index 83378f549..32296facb 100644 --- a/src/transports/sentry_http_transport_curl.c +++ b/src/transports/sentry_http_transport_curl.c @@ -45,7 +45,24 @@ typedef struct { void (*slist_free_all)(struct curl_slist *list); } curl_table_t; +#ifdef SENTRY_LINK_CURL +static const curl_table_t g_curl = { + .global_init = curl_global_init, + .version_info = curl_version_info, + .global_cleanup = curl_global_cleanup, + .easy_init = curl_easy_init, + .easy_cleanup = curl_easy_cleanup, + .easy_reset = curl_easy_reset, + .easy_setopt = curl_easy_setopt, + .easy_getinfo = curl_easy_getinfo, + .easy_perform = curl_easy_perform, + .easy_strerror = curl_easy_strerror, + .slist_append = curl_slist_append, + .slist_free_all = curl_slist_free_all, +}; +#else static curl_table_t g_curl; +#endif #ifndef SENTRY_LINK_CURL static void @@ -165,19 +182,6 @@ curl_load(void) static int curl_load(void) { - g_curl.global_init = curl_global_init; - g_curl.version_info = curl_version_info; - g_curl.global_cleanup = curl_global_cleanup; - g_curl.easy_init = curl_easy_init; - g_curl.easy_cleanup = curl_easy_cleanup; - g_curl.easy_reset = curl_easy_reset; - g_curl.easy_setopt = curl_easy_setopt; - g_curl.easy_getinfo = curl_easy_getinfo; - g_curl.easy_perform = curl_easy_perform; - g_curl.easy_strerror = curl_easy_strerror; - g_curl.slist_append = curl_slist_append; - g_curl.slist_free_all = curl_slist_free_all; - return 0; } #endif From 299e8a92c187c3bc1117bcf29e25cd032b4e89e7 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 11:58:44 +0200 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc36e0513..86d6f8412 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Wine: fix OS version detection and cross-compiling Windows builds from Linux. ([#2001](https://github.com/getsentry/sentry-native/pull/2001)) - Destroy condition variables as approriate when no longer needed. ([#2004](https://github.com/getsentry/sentry-native/pull/2004)) - Crashpad/Windows: preserve module CodeView UUIDs for minimal PDB70 records with empty PDB filenames. ([#2003](https://github.com/getsentry/sentry-native/pull/2003)) +- Prevent a race between SDK reinitialization and cleanup of the previous curl client when libcurl is linked directly. ([#2015](https://github.com/getsentry/sentry-native/pull/2015)) ## 0.16.3