core: Install first context as implicit default (and warn about its use)

There was a behaviour change in libusb 1.0.25 which triggers issues when
the API is misused. This caused for instance gutenprint to crash, see
https://bugzilla.redhat.com/show_bug.cgi?id=2055504

This seems to affect several applications "out in the wild".

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.

This will allow some grace time for developers to fix their
applications, before we at a later point revert to the stricter
behaviour.

Fixes #1089
This commit is contained in:
Benjamin Berg
2022-02-22 11:45:38 +01:00
committed by Tormod Volden
parent 66d3849974
commit 6b29aeb9ca
4 changed files with 59 additions and 5 deletions

View File

@@ -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);
@@ -2355,9 +2356,15 @@ int API_EXPORTED libusb_init(libusb_context **ctx)
/* Initialize hotplug after the initial enumeration is done. */
usbi_hotplug_init(_ctx);
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;
@@ -2430,6 +2437,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);
@@ -2576,7 +2585,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

View File

@@ -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 {

View File

@@ -1 +1 @@
#define LIBUSB_NANO 11711
#define LIBUSB_NANO 11712

View File

@@ -558,6 +558,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)
{
@@ -1101,6 +1127,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,