1

I'm writing a macOS launch daemon (in C++). It works for the most part, except that I am noticing some random crashes via SIGABRT (in the log.)

I've asked earlier about the use of the Core Graphics framework, which it turns out was not allowed in a launch daemon. I removed it, but I still get very rare crashes.

Thus I'm wondering which of the following frameworks am I allowed to use from a launch daemon?

enter image description here

c00000fd
  • 20,994
  • 29
  • 177
  • 400

1 Answers1

2

There's no technical restriction on specific frameworks you're allowed or not allowed to link. Merely linking a library will not cause crashes. Some APIs need to be called from specific contexts, such as much of Core Graphics only making sense if a process is part of a windowing session, as you've found out. But even there, some of the off-screen drawing APIs which don't interface with the windowing system directly ought to work from a Launch Daemon context.

If you're seeing crashes calling specific APIs, you'll need to investigate those one by one. If you're seeing "random" crashes, I suspect you have a bug (memory overwrite? multithreading error?) in your code. Note that Apple's toolchain provides a bunch of different diagnostic options which you can use even when not running in the debugger, such as ASan, UBSan, and Thread Sanitizer. These may help you track down issues.

As you've specifically tagged this question with the IOKit tag and it's shown in your screenshot, I'll add that using IOKit from a launch daemon is very common. It's even possible to use IOKit matching events as a launch trigger for the daemon using XPC events/xpc_set_event_stream_handler - this way, your daemon can be started on-demand when a specific (type of) device is connected, for example. (As opposed to starting up at every system boot and consuming system resources even if it's not needed or doing anything.)

pmdj
  • 22,018
  • 3
  • 52
  • 103
  • It's hard to say where the issue originates. All I can tell is that the crash happens in one of the functions that frees memory from the heap (inside a system call.) So something corrupts that memory. It doesn't happen all the time. It almost always comes from within `CFDateFormatterCreateStringWithDate` when it tries to release memory. But there's really nothing in my date formatter code that could lead to it. I can see further down the callstack of that function that it crashes trying to free some internal memory. As for where that memory gets clobbered up - that's a million dollar question. – c00000fd Jan 21 '23 at 13:22
  • 1
    Yeah, sounds like a memory clobber or object over-release. Addess Sanitiser is definitely worth a try for debugging this. You can also try enabling zombie objects. Oh, and if you aren't already using it, the clang compiler's static analysis can also catch some kinds of retain/release bugs and a bunch of other types of issues. Product -> Analyze in Xcode. – pmdj Jan 21 '23 at 13:24
  • My guess is that I'm calling some system API from one of those libraries when I'm not supposed to, or if it releases internal buffer too early, that I didn't envision or called right. I don't have sufficient knowledge of macOS to figure out what exactly I'm not supposed to do in a launch daemon. My approach now is to eliminate some group of functions and see if the crashes continue. But that is fraught with danger because the absence of crashes in that case doesn't mean that I found the source - they could just be quite rare because of some internal race condition. Like it happened yesterday. – c00000fd Jan 21 '23 at 13:25
  • To be honest, given the information you've provided, I would not assume the code is crashing because it's running as a launch daemon. It seems equally if not more likely this is just a straight up programming error. – pmdj Jan 21 '23 at 13:27
  • Can I use all those debugging/profiling tools for a launch daemon? – c00000fd Jan 21 '23 at 13:27
  • As far as I'm aware, that shouldn't be a problem. They require some support libraries, so those need to be available on the system you're testing on - I think that means it needs the Xcode command line installed. You may also run into issues if the command line tools' version doesn't match the Xcode version used to produce the build. – pmdj Jan 21 '23 at 13:29
  • Another tip is to try to write unit tests for any chunks of code that can be isolated, then run those tests through all available diagnostic tools. (All of this can be controlled in Xcode's scheme editor.) Note that you can also attach a debugger to a running launch daemon, or set the debugger to attach as soon as the daemon launches. (Obviously this doesn't work for a daemon launching during early system boot.) – pmdj Jan 21 '23 at 13:30
  • Thanks, I'll try that. On an unrelated subject that you touched upon. Is XPC similar to RPC? I will need some IPC communication method between my launch agent(s) and a launch daemon (that is always running) - basically a pipe to send messages to the daemon and receive its response back. I don't need to start it on demand though. There are other things that it needs to do besides what I mentioned earlier. – c00000fd Jan 21 '23 at 13:33
  • 1
    XPC is a message-based IPC mechanism built on Mach messages. You can use it to send almost anything between 2 processes; you'll need to register the port name(s) of the "server" in its launchd plist so the clients can find it. – pmdj Jan 21 '23 at 13:35