From d46cbbac4851ce6e49d8dacb0daa328453eb8a84 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 22 Feb 2022 11:45:38 +0100 Subject: [PATCH] core: Install first context as implicit default There was a behaviour change in libusb, which triggers issues when the API is misused. This caused gutenprint to crash, see https://bugzilla.redhat.com/show_bug.cgi?id=2055504 For now, work around this by installing an implicit default. But, change the code to log an error in case this "feature" is being used. --- libusb/core.c | 16 +++++++++++++--- libusb/libusbi.h | 15 ++++++++++++++- tests/umockdev.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/libusb/core.c b/libusb/core.c index 1c1ada1..c75ddae 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -41,6 +41,7 @@ static libusb_log_cb log_handler; #endif struct libusb_context *usbi_default_context; +struct libusb_context *usbi_fallback_context; static int default_context_refcnt; static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER; static struct usbi_option default_context_options[LIBUSB_OPTION_MAX]; @@ -2284,7 +2285,7 @@ int API_EXPORTED libusb_init(libusb_context **ctx) usbi_mutex_static_lock(&default_context_lock); - if (!ctx && usbi_default_context) { + if (!ctx && default_context_refcnt > 0) { usbi_dbg(usbi_default_context, "reusing default context"); default_context_refcnt++; usbi_mutex_static_unlock(&default_context_lock); @@ -2354,9 +2355,15 @@ int API_EXPORTED libusb_init(libusb_context **ctx) goto err_io_exit; } - if (ctx) + if (ctx) { *ctx = _ctx; + if (!usbi_fallback_context) { + usbi_fallback_context = _ctx; + usbi_warn(usbi_fallback_context, "installing new context as implicit default"); + } + } + usbi_mutex_static_unlock(&default_context_lock); return 0; @@ -2429,6 +2436,8 @@ void API_EXPORTED libusb_exit(libusb_context *ctx) if (!ctx) usbi_default_context = NULL; + if (ctx == usbi_fallback_context) + usbi_fallback_context = NULL; usbi_mutex_static_unlock(&default_context_lock); @@ -2575,7 +2584,8 @@ static void log_v(struct libusb_context *ctx, enum libusb_log_level level, #else enum libusb_log_level ctx_level; - ctx = usbi_get_context(ctx); + ctx = ctx ? ctx : usbi_default_context; + ctx = ctx ? ctx : usbi_fallback_context; if (ctx) ctx_level = ctx->debug; else diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 5f0d5c2..580add8 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -436,13 +436,26 @@ struct libusb_context { }; extern struct libusb_context *usbi_default_context; +extern struct libusb_context *usbi_fallback_context; extern struct list_head active_contexts_list; extern usbi_mutex_static_t active_contexts_lock; static inline struct libusb_context *usbi_get_context(struct libusb_context *ctx) { - return ctx ? ctx : usbi_default_context; + static int warned = 0; + + if (!ctx) { + ctx = usbi_default_context; + } + if (!ctx) { + ctx = usbi_fallback_context; + if (ctx && warned == 0) { + usbi_err(ctx, "API misuse! Using non-default context as implicit default."); + warned = 1; + } + } + return ctx; } enum usbi_event_flags { diff --git a/tests/umockdev.c b/tests/umockdev.c index b2af512..0e73f94 100644 --- a/tests/umockdev.c +++ b/tests/umockdev.c @@ -551,6 +551,32 @@ test_open_close(UMockdevTestbedFixture * fixture, UNUSED_DATA) libusb_close(handle); } +static void +test_implicit_default(UMockdevTestbedFixture * fixture, UNUSED_DATA) +{ + libusb_device **devs = NULL; + + clear_libusb_log(fixture, LIBUSB_LOG_LEVEL_INFO); + g_assert_cmpint(libusb_get_device_list(NULL, &devs), ==, 1); + libusb_free_device_list(devs, TRUE); + assert_libusb_log_msg(fixture, LIBUSB_LOG_LEVEL_ERROR, "\\[usbi_get_context\\].*implicit default"); + + /* Only warns once */ + g_assert_cmpint(libusb_get_device_list(NULL, &devs), ==, 1); + libusb_free_device_list(devs, TRUE); + clear_libusb_log(fixture, LIBUSB_LOG_LEVEL_INFO); + + libusb_init(NULL); + g_assert_cmpint(libusb_get_device_list(NULL, &devs), ==, 1); + libusb_exit(NULL); + + /* We free late, causing a warning from libusb_exit. However, + * we never see this warning (i.e. test success) because it is on a + * different context. + */ + libusb_free_device_list(devs, TRUE); +} + static void test_close_flying(UMockdevTestbedFixture * fixture, UNUSED_DATA) { @@ -932,6 +958,11 @@ main(int argc, char **argv) test_open_close, test_fixture_teardown); + g_test_add("/libusb/implicit-default", UMockdevTestbedFixture, NULL, + test_fixture_setup_with_canon, + test_implicit_default, + test_fixture_teardown); + g_test_add("/libusb/close-flying", UMockdevTestbedFixture, NULL, test_fixture_setup_with_canon, test_close_flying, -- 2.35.1