Closed jeff-h closed 2 years ago
It's looking like it crashes when I call any route that has an async
handler. I'll experiment with that theory more in the morning.
You're correct, the stack trace makes it clear this is crashing while doing the setup work to call an async
handler.
I did a bit of investigation, and unfortunately the answer is this can't work due to Apple failing to fully back port Swift concurrency. See this Apple Developer Forums discussion. As a result of this, I'll improve the documentation for SecureXPC, but only Apple can actually fix the issue.
The bottom line is whether or not your helper tool installed with SMJobBless
uses SecureXPC, it can't use Swift concurrency on Catalina and Big Sur.
Here's what's going on:
SMJobBless
must be command line tools, not app bundleslibswift_Concurrency.dylib
as a framework to any app bundles targeting Catalina or Big Sur as their minimum versionlibswift_Concurrency.dylib
as a framework for command line toolsThe reason none of the testing caught this is async
routes can be used on Catalina and Big Sur, but not from a command line tool. They work fine in XPC services, as anonymous servers inside of apps, in login items, etc. which are all app bundles. (All of the automated testing uses anonymous servers which run inside of Xcode's test harness.)
Wow, that makes sense. Thanks so much for your analysis — I really appreciate your time digging into it.
I did notice the bundled libswift_Concurrency.dylib
in my app, and wondered how the helper handled that but put it down to lack of knowledge on my part :) I still don't quite understand why the helper tool can't have a dependency on libswift_Concurrency.dylib
— I guess it's just a dylib path problem (ie where could it find this dylib?)
I'll just go through and convert my async
handlers to use callbacks.
ps crikey, do you ever sleep? 🤪
I still don't quite understand why the helper tool can't have a dependency on libswift_Concurrency.dylib — I guess it's just a dylib path problem (ie where could it find this dylib?)
The helper tool once installed by SMJobBless
is copied from your app bundle to /Library/PrivilegedHelperTools/
. Once it's been relocated, there's no way for it to reference the libswift_Concurrency.dylib
in your app bundle as it doesn't know about the app it was copied from. I find the overall design of SMJobBless
questionable, but unfortunately it's the only supported way Apple provides to generically run as root.
I'll just go through and convert my async handlers to use callbacks.
Yeah, unfortunately that does seem to be the only option.
ps crikey, do you ever sleep? 🤪
Oh, I'm not in New Zealand at the moment.
Sorry to prolong this, but I'm confused :( I've just re-read the documentation more carefully and realised it states that both async
and closures
will only work in the helper in Monterey and later. So converting my async handlers to use callbacks isn't going to help... or am I misunderstanding what's meant by the docs?
My Process
handlers will be slow; if I can't use async
nor callbacks, should I just use process.waitUntilExit
and rely on SecureXPC calling the handlers asynchronously?
I've just played with the SwiftAuthorizationSample code and confirmed that I'm wrong above; without async
handlers, SecureXPC calls the handlers synchronously (as one would expect). Multiple calls to slow handlers (eg running a slow process.waitUntilExit
) will each wait for the the preceding to complete. Pretty much by definition of being not async
.
Is there actually a closure-based alternative to async
handlers? Or is the closure-based API only available on the client side?
I'm really hoping I've not misunderstood the implication of this issue. It's pretty critical for my helper to run multiple Process
es simultaneously.
Interestingly enough, Xcode already compiles the helper with a dynamic link to @rpath/libswift_Concurrency.dylib
, and thus copying the dylib into /Library/PrivilegedHelperTools
made the whole problem go away in Big Sur. However I'm doubting there's a clean way to "install" a copy of libswift_Concurrency.dylib
somewhere safe at runtime though.
Sorry to prolong this, but I'm confused :( I've just re-read the documentation more carefully and realised it states that both async and closures will only work in the helper in Monterey and later. So converting my async handlers to use callbacks isn't going to help... or am I misunderstanding what's meant by the docs?
Assuming you mean the sentence "On macOS 10.15 and later async functions and closures..." then the async
refers to both functions and closures - in other words "async
functions" and "async
closures". The usage of Swift closures works on all operating systems.
I've just played with the SwiftAuthorizationSample code and confirmed that I'm wrong above; without
async
handlers, SecureXPC calls the handlers synchronously (as one would expect). Multiple calls to slow handlers (eg running a slowprocess.waitUntilExit
) will each wait for the the preceding to complete. Pretty much by definition of being notasync
.
Have you set a concurrent DispatchQueue
for the server's targetQueue
property? The sample keeps things simple and does not do that (nor would it make sense for how the sample behaves).
Interestingly enough, Xcode already compiles the helper with a dynamic link to
@rpath/libswift_Concurrency.dylib
, and thus copying the dylib into/Library/PrivilegedHelperTools
made the whole problem go away in Big Sur. However I'm doubting there's a clean way to "install" a copy oflibswift_Concurrency.dylib
somewhere safe at runtime though.
Indeed, there is not.
I think the original issue topic here is sorted; the reasons for the crashing are now well-identified. In case it helps anyone else who comes across this, there's a related issue regarding handler concurrency at https://github.com/trilemma-dev/SecureXPC/issues/92
As per title, my helper is crashing in Catalina & Big Sur. It is fine in Monterey. After launching it runs a bunch of route requests fine, but then crashes with EXC_BAD_ACCESS.
It doesn't seem to crash in any of my route handling code nor on any particular route call, so I'm assuming it must be something to do with my route definitions, although I can't see what. I am wondering if anything jumps out to you in the crash log?
Click to expand crash log (truncated to fit allowed GitHub post size):
``` Process: com.test.AppHelper.Debug [3028] Path: /Library/PrivilegedHelperTools/com.test.AppHelper.Debug Identifier: com.test.AppHelper.Debug Version: 1.0.0-beta.4 (100) Code Type: X86-64 (Native) Parent Process: launchd [1] Responsible: com.test.AppHelper.Debug [3028] User ID: 0 Date/Time: 2022-05-01 18:11:55.299 +1200 OS Version: macOS 11.6 (20G165) Report Version: 12 Anonymous UUID: DDCC3E05-CCE8-DB38-43E5-8378F721024C Sleep/Wake UUID: C6BAE207-875A-4EB8-BF73-823D7FDC7C8E Time Awake Since Boot: 15000 seconds Time Since Wake: 6900 seconds System Integrity Protection: enabled Crashed Thread: 1 Dispatch queue: com.apple.root.default-qos.overcommit Exception Type: EXC_BAD_ACCESS (SIGABRT) Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY VM Regions Near 0: --> __TEXT 10027c000-10070c000 [ 4672K] r-x/r-x SM=COW /Library/PrivilegedHelperTools/*.Debug Application Specific Information: ================================================================= ==3028==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7fff2ca35dc7 bp 0x7000037a0820 sp 0x7000037a0800 T2) ==3028==The signal is caused by a READ memory access. ==3028==Hint: address points to the zero page. #0 0x7fff2ca35dc7 in swift::ResolveAsSymbolicReference::operator()(swift::Demangle::__runtime::SymbolicReferenceKind, swift::Demangle::__runtime::Directness, int, void const*)+0x37 (libswiftCore.dylib:x86_64+0x33cdc7) #1 0x7fff2ca582dc in swift::Demangle::__runtime::Demangler::demangleSymbolicReference(unsigned char)+0x8c (libswiftCore.dylib:x86_64+0x35f2dc) #2 0x7fff2ca552a7 in swift::Demangle::__runtime::Demangler::demangleType(__swift::__runtime::llvm::StringRef, std::__1::function