memdebug: add mutex for thread safety

Protect modification to the `membuf` by different threads
via a mutex. This ensure that index updates are correct and
that data gets written in order.

Closes #19785
This commit is contained in:
Stefan Eissing 2025-12-01 13:22:25 +01:00 committed by Daniel Stenberg
parent c6c4a99300
commit a7bebd8502
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2

View file

@ -29,6 +29,7 @@
#include <curl/curl.h> #include <curl/curl.h>
#include "urldata.h" #include "urldata.h"
#include "curl_threads.h"
#include "curlx/fopen.h" /* for CURLX_FOPEN_LOW(), CURLX_FREOPEN_LOW() */ #include "curlx/fopen.h" /* for CURLX_FOPEN_LOW(), CURLX_FREOPEN_LOW() */
#ifdef USE_BACKTRACE #ifdef USE_BACKTRACE
@ -66,6 +67,11 @@ static struct backtrace_state *btstate;
static char membuf[KEEPSIZE]; static char membuf[KEEPSIZE];
static size_t memwidx = 0; /* write index */ static size_t memwidx = 0; /* write index */
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
static bool dbg_mutex_init = 0;
static curl_mutex_t dbg_mutex;
#endif
/* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected /* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected
on exit so the logfile must be closed explicitly or data could be lost. on exit so the logfile must be closed explicitly or data could be lost.
Though _exit() does not call atexit handlers such as this, LSAN's call to Though _exit() does not call atexit handlers such as this, LSAN's call to
@ -81,6 +87,12 @@ static void curl_dbg_cleanup(void)
fclose(curl_dbg_logfile); fclose(curl_dbg_logfile);
} }
curl_dbg_logfile = NULL; curl_dbg_logfile = NULL;
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
if(dbg_mutex_init) {
Curl_mutex_destroy(&dbg_mutex);
dbg_mutex_init = FALSE;
}
#endif
} }
#ifdef USE_BACKTRACE #ifdef USE_BACKTRACE
static void error_bt_callback(void *data, const char *message, static void error_bt_callback(void *data, const char *message,
@ -123,6 +135,12 @@ void curl_dbg_memdebug(const char *logname)
setbuf(curl_dbg_logfile, (char *)NULL); setbuf(curl_dbg_logfile, (char *)NULL);
#endif #endif
} }
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
if(!dbg_mutex_init) {
dbg_mutex_init = TRUE;
Curl_mutex_init(&dbg_mutex);
}
#endif
#ifdef USE_BACKTRACE #ifdef USE_BACKTRACE
btstate = backtrace_create_state(NULL, 0, error_bt_callback, NULL); btstate = backtrace_create_state(NULL, 0, error_bt_callback, NULL);
#endif #endif
@ -526,6 +544,11 @@ void curl_dbg_log(const char *format, ...)
nchars = (int)sizeof(buf) - 1; nchars = (int)sizeof(buf) - 1;
if(nchars > 0) { if(nchars > 0) {
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
bool lock_mutex = dbg_mutex_init;
if(lock_mutex)
Curl_mutex_acquire(&dbg_mutex);
#endif
if(KEEPSIZE - nchars < memwidx) { if(KEEPSIZE - nchars < memwidx) {
/* flush */ /* flush */
fwrite(membuf, 1, memwidx, curl_dbg_logfile); fwrite(membuf, 1, memwidx, curl_dbg_logfile);
@ -538,6 +561,10 @@ void curl_dbg_log(const char *format, ...)
} }
memcpy(&membuf[memwidx], buf, nchars); memcpy(&membuf[memwidx], buf, nchars);
memwidx += nchars; memwidx += nchars;
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
if(lock_mutex)
Curl_mutex_release(&dbg_mutex);
#endif
} }
} }