git: 58734b18794b - stable/14 - libusb: fix hotplug sigbus

From: Baptiste Daroussin <bapt_at_FreeBSD.org>
Date: Tue, 07 Jan 2025 09:03:08 UTC
The branch stable/14 has been updated by bapt:

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

commit 58734b18794b772a2f964bf08863808680f0c81a
Author:     Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2025-01-03 09:50:30 +0000
Commit:     Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2025-01-07 09:02:57 +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
    
    (cherry picked from commit ba5834b8e11fd002a663d083a464e397e76cb3a9)
---
 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 */