Skip to content

Fix segfault at exit: close PacDrive USB handles before libusb_exit() - #64

Closed
MizterB wants to merge 1 commit into
vpinball:masterfrom
MizterB:fix/pacdrive-libusb-shutdown
Closed

MizterB wants to merge 1 commit into
vpinball:masterfrom
MizterB:fix/pacdrive-libusb-shutdown

Conversation

@MizterB

@MizterB MizterB commented Aug 16, 2026

Copy link
Copy Markdown

Any process that opens a PacDrive/PacLed64 segfaults at exit inside libusb_close:

segfault at 14c ... in libusb-1.0.so.0[7363,...]     # libusb_close+0x43, dev->ctx == 0

IOConfigurator::Shutdown() calls libusb_exit() while PacDriveSingleton still holds open handles. That singleton is static, so its destructor runs at process exit and closes handles whose context is already gone.

Same bug you fixed for hidapi in 7a61d55, which put Pinscape::ClearDevices() ahead of hid_exit() in this function. The libusb branch never got the equivalent.

ReacquireContext() isn't cosmetic: without it the singleton stays empty after the first teardown and a second DOF instance silently finds no PacLed64 — a crash traded for missing outputs.

Repro: Init(), Finish(), destroy, exit, with a PacLed64 attached. Everything logs a clean shutdown, then the process dies with signal 11. 3/3 before, 0/3 after.

Tested on Debian 13 x64 against a PacLed64 and a LedWiz on an Ultimarc board, standalone and under a frontend doing repeated start/stop cycles. Only the libusb/PacDrive path — no FTDI, PinOne, or Pinscape hardware here, and no Windows/macOS build.

AI-generated fix, disclosed per CONTRIBUTING.md. I found and verified the bug on hardware; the patch itself was AI-generated, so it's a draft and a starting point rather than a finished contribution — treat the design as a proposal.

IOConfigurator::Shutdown() called libusb_exit() while PacDriveSingleton still held
open handles. That singleton is static, so its destructor ran at process exit and
closed handles whose context was already freed, segfaulting in libusb_close.

Same shape as 7a61d55, which put Pinscape::ClearDevices() ahead of hid_exit() in
this function. ReacquireContext() re-enumerates after libusb_init so a second DOF
instance still finds its devices.
@MizterB

MizterB commented Sep 2, 2026

Copy link
Copy Markdown
Author

Resolved by 69b10bd

@MizterB MizterB closed this Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant