summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Berg <bberg@redhat.com>2022-02-22 11:45:38 +0100
committerTormod Volden <debian.tormod@gmail.com>2022-03-20 10:55:17 +0100
commit6b29aeb9ca22ed5ea9768020895698bd452c2a85 (patch)
treeac04911dd136015c226fb414ec6179d7af8c4edc
parent66d3849974dbc93d8bad418dbf594b37c95416f9 (diff)
downloadlibusb-6b29aeb9ca22ed5ea9768020895698bd452c2a85.tar.gz
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
-rw-r--r--libusb/core.c16
-rw-r--r--libusb/libusbi.h15
-rw-r--r--libusb/version_nano.h2
-rw-r--r--tests/umockdev.c31
4 files changed, 59 insertions, 5 deletions
diff --git a/libusb/core.c b/libusb/core.c
index 3559470..ec429b7 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);
@@ -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
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 7618236..b1fc88c 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/libusb/version_nano.h b/libusb/version_nano.h
index 4271170..26ed7e7 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11711
+#define LIBUSB_NANO 11712
diff --git a/tests/umockdev.c b/tests/umockdev.c
index 1eda532..488edc2 100644
--- a/tests/umockdev.c
+++ b/tests/umockdev.c
@@ -559,6 +559,32 @@ test_open_close(UMockdevTestbedFixture * fixture, UNUSED_DATA)
}
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)
{
UsbChat chat[] = {
@@ -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,