mirror of
https://github.com/shadps4-emu/ext-libusb.git
synced 2026-01-31 00:55:21 +01:00
core: Avoid possible data race in log_v()
The logging function usbi_dbg() called from udev event thread needs to safely get the log level of the default context or the fallback context. This is not trivial because udev thread may log events while contexts are created and destroyed. Locking the default context mutex is not an option because usbi_dbg() may be called from code that already holds this mutex, which would lead to a deadlock. The solution implemented in this commit is to maintain a separate atomic global variable with the default debug level. The issue was found with ThreadSanitizer, although no actual bugs have been observed. libusb_set_debug() was also changed to call libusb_set_option() instead of doing its own option setting which had fewer checks. Closes #1332
This commit is contained in:
committed by
Tormod Volden
parent
dfed0d1695
commit
9de0fefb31
@@ -43,6 +43,9 @@ static libusb_log_cb log_handler;
|
||||
struct libusb_context *usbi_default_context;
|
||||
struct libusb_context *usbi_fallback_context;
|
||||
static int default_context_refcnt;
|
||||
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
|
||||
static usbi_atomic_t default_debug_level = -1;
|
||||
#endif
|
||||
static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
|
||||
static struct usbi_option default_context_options[LIBUSB_OPTION_MAX];
|
||||
|
||||
@@ -2207,16 +2210,7 @@ int API_EXPORTED libusb_set_auto_detach_kernel_driver(
|
||||
*/
|
||||
void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level)
|
||||
{
|
||||
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
|
||||
ctx = usbi_get_context(ctx);
|
||||
if (!ctx->debug_fixed) {
|
||||
level = CLAMP(level, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG);
|
||||
ctx->debug = (enum libusb_log_level)level;
|
||||
}
|
||||
#else
|
||||
UNUSED(ctx);
|
||||
UNUSED(level);
|
||||
#endif
|
||||
libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, level);
|
||||
}
|
||||
|
||||
static void libusb_set_log_cb_internal(libusb_context *ctx, libusb_log_cb cb,
|
||||
@@ -2300,6 +2294,7 @@ int API_EXPORTEDV libusb_set_option(libusb_context *ctx,
|
||||
int arg = 0, r = LIBUSB_SUCCESS;
|
||||
libusb_log_cb log_cb = NULL;
|
||||
va_list ap;
|
||||
int is_default_context = (NULL == ctx);
|
||||
|
||||
va_start(ap, option);
|
||||
|
||||
@@ -2343,8 +2338,11 @@ int API_EXPORTEDV libusb_set_option(libusb_context *ctx,
|
||||
switch (option) {
|
||||
case LIBUSB_OPTION_LOG_LEVEL:
|
||||
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
|
||||
if (!ctx->debug_fixed)
|
||||
if (!ctx->debug_fixed) {
|
||||
ctx->debug = (enum libusb_log_level)arg;
|
||||
if (is_default_context)
|
||||
usbi_atomic_store(&default_debug_level, CLAMP(arg, LIBUSB_LOG_LEVEL_NONE, LIBUSB_LOG_LEVEL_DEBUG));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -2503,6 +2501,9 @@ int API_EXPORTED libusb_init_context(libusb_context **ctx, const struct libusb_i
|
||||
if (!ctx) {
|
||||
usbi_default_context = _ctx;
|
||||
default_context_refcnt = 1;
|
||||
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
|
||||
usbi_atomic_store(&default_debug_level, _ctx->debug);
|
||||
#endif
|
||||
usbi_dbg(usbi_default_context, "created default context");
|
||||
}
|
||||
|
||||
@@ -2530,6 +2531,10 @@ int API_EXPORTED libusb_init_context(libusb_context **ctx, const struct libusb_i
|
||||
*ctx = _ctx;
|
||||
|
||||
if (!usbi_fallback_context) {
|
||||
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
|
||||
if (usbi_atomic_load(&default_debug_level) == -1)
|
||||
usbi_atomic_store(&default_debug_level, _ctx->debug);
|
||||
#endif
|
||||
usbi_fallback_context = _ctx;
|
||||
usbi_dbg(usbi_fallback_context, "installing new context as implicit default");
|
||||
}
|
||||
@@ -2756,13 +2761,14 @@ static void log_v(struct libusb_context *ctx, enum libusb_log_level level,
|
||||
UNUSED(ctx);
|
||||
#else
|
||||
enum libusb_log_level ctx_level;
|
||||
long default_level_value;
|
||||
|
||||
ctx = ctx ? ctx : usbi_default_context;
|
||||
ctx = ctx ? ctx : usbi_fallback_context;
|
||||
if (ctx)
|
||||
if (ctx) {
|
||||
ctx_level = ctx->debug;
|
||||
else
|
||||
ctx_level = get_env_debug_level();
|
||||
} else {
|
||||
default_level_value = usbi_atomic_load(&default_debug_level);
|
||||
ctx_level = default_level_value < 0 ? get_env_debug_level() : (enum libusb_log_level)default_level_value;
|
||||
}
|
||||
|
||||
if (ctx_level < level)
|
||||
return;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define LIBUSB_NANO 11825
|
||||
#define LIBUSB_NANO 11826
|
||||
|
||||
Reference in New Issue
Block a user