libusb icon indicating copy to clipboard operation
libusb copied to clipboard

[macOS 10.11.6-] libusb_claim_interface returns error -99 with "QueryInterface: unknown error"

Open jerry-belaston opened this issue 2 years ago • 13 comments

Hi all,

Since upgrading from libusb 1.0.23 to libusb 1.0.26, we got specifically on MacOS 10.11.6 El Captain and lower, the following error, when calling libusb_claim_interface:

Error code: -99
Log: libusb: error [darwin_claim_interface] QueryInterface: unknown error (0x80000004)

Therefore, obviously, I can't connect to my device. Please, does that ring a bell to anyone ?

Thanks in advance.

jerry-belaston avatar Aug 05 '22 09:08 jerry-belaston

Can you please attach a full debug log? See also https://github.com/libusb/libusb/wiki/Troubleshooting

tormodvolden avatar Aug 07 '22 10:08 tormodvolden

Here's the debug log of this issue debug-1.0.26.txt. I'm also interested in a fix.

parafin avatar Aug 12 '22 13:08 parafin

I think this happens when libusb is built with newer macOS SDK and run on older OS. The logic in libusb/os/darwin_usb.h doesn't take into account deployment target, but just checks if symbol is defined. So libusb ends up requesting kIOUSBInterfaceInterfaceID800 even on macOS < 10.12, where it's unavailable.

parafin avatar Aug 12 '22 14:08 parafin

Probably caused by 00688d059262b291d1bf9ef48865f0d3e0a48952

parafin avatar Aug 12 '22 14:08 parafin

Also see 0f59214f1253a36f27c3acbcd9601d026d4741b1

parafin avatar Aug 12 '22 14:08 parafin

Please see also commit d520f4d - is this still a problem on latest master?

tormodvolden avatar Aug 12 '22 16:08 tormodvolden

clock_gettime logic works fine - otherwise it wouldn’t even start in the case we’re discussing.

parafin avatar Aug 12 '22 16:08 parafin

I think 00688d0 should be reverted. I've looked at the linked PR #911 and have no idea how they are related. Pinging @osy (PR author), so that he could maybe explain it. Or maybe @hjelmn have an idea, since he reviewed and merged that PR.

parafin avatar Aug 19 '22 08:08 parafin

Okay I see what the issue is. There are a few different build settings:

  • The version of Xcode/macOS SDK that is being used
  • The minimum deployment macOS specified at build time
  • The version of the currently running macOS

Previously the logic was this: if the SDK supports the USB interface version AND the minimum deployment version supports it THEN use (highest) supported USB interface version.

I changed it to just checking if the SDK supports the USB interface version because I erroneously assumed that the macOS SDK version being used is the same as the currently running macOS. But obviously that's wrong because you can build with a newer SDK and set the deployment version to a lower macOS.

So it should be reverted but then we run into the error of libusb not working properly when deploying for other Apple systems like iOS and tvOS. An easy fix would be to OR in versions from iOS and tvOS and etc as well but perhaps there's a better solution?

osy avatar Aug 19 '22 08:08 osy

Another solution is to figure out the maximum supported interface version at runtime somehow. It will be the most flexible solution (one build supporting both old OS versions and features of new OSes, if they are available), but it's more code someone has to write (and test on various OS versions) and maintain.

parafin avatar Aug 19 '22 08:08 parafin

Hi guys, thanks for your quick feedback which confirms my suspicion regarding a probable bad management of deployment target. It's clearer now.

Don't really know your plan but if we go with your solution @parafin, it seems this issue won't be resolved in a close future because of the probable big amount of test to perform... Now, do you think this issue is major enough to be included in the next 1.0.27 milestone? Or do we now have to deal with a restricted range of macOS versions? What do you think ?

jerry-belaston avatar Aug 29 '22 13:08 jerry-belaston

Probably a good idea to first do a simple fix (or just revert) before considering runtime detection. And to me this bug is a major issue.

parafin avatar Aug 29 '22 13:08 parafin

Oh yep for sure, fixing it first at "compilation step" would be ideal and for that, @osy proposal (which, I confirm, works) seems for now the only "simple" solution. So ok, now I get what you think regarding the level of priority. Thanks again for your feedback.

jerry-belaston avatar Aug 29 '22 14:08 jerry-belaston

Is this an issue in master? I think I fixed up all the version checks some months ago...

seanm avatar Dec 18 '22 01:12 seanm

There were no relevant changes to darwin backend since the start of discussion of this bug. You’re probably referring to your changes about clock_gettime - those are working fine. To summarise - this is still not fixed.

parafin avatar Dec 18 '22 09:12 parafin

Oh, I see. I thought I fixed all this in https://github.com/libusb/libusb/commit/0f59214f1253a36f27c3acbcd9601d026d4741b1 but I see now subsequent changes since have regressed things.

I'll make a new patch...

seanm avatar Dec 19 '22 14:12 seanm

See also the discussion in issue #519.

tormodvolden avatar Jan 02 '23 12:01 tormodvolden

So it should be reverted but then we run into the error of libusb not working properly when deploying for other Apple systems like iOS and tvOS.

Is that even possible? I can't find IOUSBLib.h in any other Xcode SDK besides the macOS SDK:

% find /Applications/Xcode.app/Contents/Developer/Platforms -name IOUSBLib.h
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Versions/A/Headers/usb/IOUSBLib.h

seanm avatar Jan 16 '23 19:01 seanm

Is there a good way to do runtime detection? For some purposes, we want to know the version we're actually running against, not just what APIs are available. In particular, for whether we need to call ClearPipeStallBothEnds in libusb_cancel_transfer as introduced by #1117. That function is always available, but whether or not we need to run it depends on the OS version.

martinling avatar Jan 16 '23 20:01 martinling

Is there a good way to do runtime detection?

@martinling There are several ways, like @available and NSFoundationVersionNumber, but both these require Objective-C (or swift I guess).

From plain C there are some sysctls that could be used: https://stackoverflow.com/questions/5969485/getting-the-os-version-in-mac-os-x-using-standard-c


I'd still like to understand: from what I can tell from Apple's docs, IOKit is not available on all the other Darwin variants (except macOS), so what's the talk of using libusb on iOS and tvOS? Is it via hacks?

seanm avatar Mar 10 '23 21:03 seanm

I'd still like to understand: from what I can tell from Apple's docs, IOKit is not available on all the other Darwin variants (except macOS), so what's the talk of using libusb on iOS and tvOS? Is it via hacks?

Yes, they are currently only available to jailbroken devices. Although in the past Apple has moved older APIs to iOS in an update (CoreAudio for example).

osy avatar Mar 10 '23 22:03 osy

but both these require Objective-C (or swift I guess).

They do not.

HIDAPI uses something very similar in plain C: https://github.com/libusb/hidapi/blob/88a0f029b7f18fc7b3c3858d652494428b3ebc2e/mac/hid.c#L41

Youw avatar Mar 12 '23 09:03 Youw

Let me take a crack at addressing this. I think I have an idea of how to manage it.

hjelmn avatar Apr 03 '23 16:04 hjelmn

Mostly done but found an annoying edge case. I can't detect 10.8.3 with the method I am using so I can either use interface 550 always with 10.8.x (which would error for 10.8.0 -> 10.8.2) or just remove interface 550 support entirely (version 650 is in 10.9.0). I am leaning towards just removing it entirely since 10.8.x is 10+ years old now. We can discuss in the PR if needed.

hjelmn avatar Apr 03 '23 22:04 hjelmn

Almost final version up at https://github.com/libusb/libusb/pull/1266 . I need to clean some things up but would love comments.

hjelmn avatar Apr 04 '23 06:04 hjelmn

To close the loop the implementation uses sysctlbyname to get the running OS version. To avoid the weirdness with kern.osversion which requires some tweaking to get the right version from the kernel version I used kern.osproductversion instead. This gives the OS version after 10.13 or so. For earlier versions the code falls back on reading /System/Library/CoreServices/SystemVersion.plist to get the macOS/Mac OS X version. This is the source of truth for the deprecated Gestalt system call.

Tested only on macOS 13.3 so will need additional testing to make sure it works as expected.

hjelmn avatar Apr 04 '23 19:04 hjelmn

FWIW I have tested git master (with #1266 merged) on macOS 11.6.1 (on an MBP Mid 2010!), both natively built binaries as well as binaries built on a 13.6 system, and it seems to work fine (our tests/* and in particular examples/xusb claiming an interface). However I understand that the reported here is only on 10.11.6 and older. So someone else has to verify there.

tormodvolden avatar Dec 08 '23 20:12 tormodvolden