Skip to content

fix(screencapture): USB discovery/activation robustness (infinite retry loop, fatal-on-close, handle leak, Linux --udid) - #164

Open
LWHikarik wants to merge 1 commit into
danielpaulus:mainfrom
LWHikarik:fix/screencapture-hardening
Open

fix(screencapture): USB discovery/activation robustness (infinite retry loop, fatal-on-close, handle leak, Linux --udid)#164
LWHikarik wants to merge 1 commit into
danielpaulus:mainfrom
LWHikarik:fix/screencapture-hardening

Conversation

@LWHikarik

Copy link
Copy Markdown

Four small, independent fixes in screencapture/, found while running qvh
against iPhones on macOS and Linux. No API or behaviour changes beyond making
failures non-fatal and bounded.

1. EnableQTConfig could loop forever holding the device

The retry counter i++ and the i > 10 cap were placed after the continue
that handles a failed ReOpen. A device that consistently fails to re-enumerate
into the QuickTime configuration therefore never incremented the counter, and
the loop spun indefinitely at 500ms per iteration, keeping the device occupied.
The counter and cap now run before the failure path. The freshly created context
is also closed when giving up, instead of being leaked.

2. A USB context-close error killed the whole process

createContext's cleanup called log.Fatalf when ctx.Close() returned an
error, which calls os.Exit — terminating the process and tearing down any live
video stream. A close error is not worth killing the process over; it is now
logged as a warning.

3. Device handle leak in mapToIosDevice

Handles were only closed on the success path. A transient SerialNumber() or
Product() read error — which happens under USB contention — returned early and
leaked every handle opened so far. Those leaked handles are what made the
deferred ctx.Close() fail, which then triggered the log.Fatalf in fix #2.
All handles are now closed via defer on every return path.

4. --udid did not match on Linux

macOS libusb NUL-pads 24-character serials (iPhone Xr/Xs and newer) to 40 bytes,
whereas Linux libusb returns them bare. Since ValidateUdid emits the padded
form, the direct == comparison in FindIosDevice never matched on Linux, and
--udid silently failed to find the device. Both sides are now NUL-trimmed
before comparison.

Verified with go build ./... and go vet ./screencapture/ on macOS (arm64,
libusb 1.0.29). The fixes are base-agnostic — the two touched files are
identical on main and externalizeGST.

…on USB close, fix handle leak and Linux --udid match

Four robustness fixes in the USB discovery/activation path. Two of them
compound into the same failure: a leaked device handle makes the deferred
context close fail, and that close error used to call log.Fatalf.

- EnableQTConfig: the retry counter and its cap sat after the failure
  `continue`, so a persistently failing ReOpen never incremented it and the
  loop spun forever at 500ms/iteration, holding the device. Count every
  attempt before the continue, and close the freshly opened context when
  giving up.

- createContext: a USB context-close error called log.Fatalf, which exits the
  process and tears down a live stream. Downgraded to a warning.

- mapToIosDevice: device handles were only closed on the happy path, so a
  transient SerialNumber()/Product() read error (common under USB contention)
  leaked them. Close all handles via defer on every return path.

- FindIosDevice: macOS libusb NUL-pads 24-character serials to 40 bytes while
  Linux returns them bare. ValidateUdid emits the padded form, so the direct
  comparison never matched on Linux. Trim NUL padding on both sides.
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