git: ba5834b8e11f - main - libusb: fix hotplug sigbus

From: Baptiste Daroussin <bapt_at_FreeBSD.org>
Date: Sat, 04 Jan 2025 10:21:45 UTC
The branch main has been updated by bapt:

URL: https://cgit.FreeBSD.org/src/commit/?id=ba5834b8e11fd002a663d083a464e397e76cb3a9

commit ba5834b8e11fd002a663d083a464e397e76cb3a9
Author:     Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2025-01-03 09:50:30 +0000
Commit:     Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2025-01-04 10:20:49 +0000

    libusb: fix hotplug sigbus
    
    When a hotplug callback has been registered, and the program using
    libusb is calling libusb_exit then the thread handler is set to
    NO_THREAD which result in the variable controlling the loop the be set
    to 0, it does a last pass through device available without having done
    a scan, which result in a sigbus after it tried to unregister all the
    devices.
    
    directly break the loop instead and cleanup the list of devices
    
    this fixes the tests with LGPLed libusb's hotplugtest program
    
    MFC After:      3 days
    Reviewed by:    kevans
    Differential Revision:  https://reviews.freebsd.org/D48298
---
 lib/libusb/libusb10_hotplug.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c
index 9d00b1dbe5a0..98903686f76b 100644
--- a/lib/libusb/libusb10_hotplug.c
+++ b/lib/libusb/libusb10_hotplug.c
@@ -112,22 +112,25 @@ libusb_hotplug_scan(void *arg)
 	libusb_device *temp;
 	libusb_device *adev;
 	libusb_device *bdev;
-	unsigned do_loop = 1;
 
-	while (do_loop) {
+	for (;;) {
 		usleep(4000000);
 
 		HOTPLUG_LOCK(ctx);
+		if (ctx->hotplug_handler == NO_THREAD) {
+			while ((adev = TAILQ_FIRST(&ctx->hotplug_devs)) != NULL) {
+				TAILQ_REMOVE(&ctx->hotplug_devs, adev, hotplug_entry);
+				libusb_unref_device(adev);
+			}
+			HOTPLUG_UNLOCK(ctx);
+			break;
+		}
 
 		TAILQ_INIT(&hotplug_devs);
 
-		if (ctx->hotplug_handler != NO_THREAD) {
-			if (libusb_hotplug_enumerate(ctx, &hotplug_devs) < 0) {
-				HOTPLUG_UNLOCK(ctx);
-				continue;
-			}
-		} else {
-			do_loop = 0;
+		if (libusb_hotplug_enumerate(ctx, &hotplug_devs) < 0) {
+			HOTPLUG_UNLOCK(ctx);
+			continue;
 		}
 
 		/* figure out which devices are gone */