Mac app crashing in CF_IS_OBJC function on macOS Sonoma

I have an Electron app on macOS Sonoma (Intel arch). It has a native addon (app.node) using node-addon-api. Recently it crashed, with the stack trace (given below). What is the CF_IS_OBJC function inside the CFDataGetBytePtr function, and why did it crash there?

[NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^(NSEvent *event) {
 // code using CFDataGetBytePtr function
}];
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^NSEvent *_Nullable(NSEvent *event) {
 // code using CFDataGetBytePtr function
 return event;
}];

I have key events monitors attached using addGlobalMonitorForEventsMatchingMask and addLocalMonitorForEventsMatchingMask in my native code and they use the CFDataGetBytePtr function there. So I think the issue happened in the key event monitor handler when calling the CFDataGetBytePtr function because my native addon app.node is also present in the trace. Also from the third and fourth entry in the stack trace, it seems like it happened while the app was updating.

OS Version: macOS 14.4 (23E214)
Report Version: 104

Crashed Thread: 5490

Application Specific Information:
Fatal Error: EXC_BAD_ACCESS / KERN_INVALID_ADDRESS / 0x0

Thread 5490 Crashed:
0   CoreFoundation                  0x19c970118         CF_IS_OBJC
1   CoreFoundation                  0x19c83b280         CFDataGetBytePtr
2   .app.desktop.1inmRz     0x104a5bec0         <unknown>
3   .app.desktop.1inmRz     0x104a57b28         <unknown>
4   app.node                  0x104a80a7c         [inlined] Napi::details::CallbackData<T>::Wrapper::lambda::operator() (napi-inl.h:117)
5   app.node                  0x104a80a7c         Napi::details::WrapCallback<T> (napi-inl.h:79)
6   app.node                  0x104a80a24         Napi::details::CallbackData<T>::Wrapper (napi-inl.h:112)
7   Electron Framework              0x11472e5e0         v8impl::(anonymous namespace)::FunctionCallbackWrapper::Invoke (js_native_api_v8.cc:441)
8   <unknown>                       0x147e105f8         <unknown>
9   <unknown>                       0x1401d0814         <unknown>
10  <unknown>                       0x1401d0a9c         <unknown>
11  <unknown>                       0x147f19368         <unknown>
12  <unknown>                       0x147e0aab0         <unknown>
13  <unknown>                       0x1401d0e00         <unknown>
14  <unknown>                       0x1401d1ac0         <unknown>
15  <unknown>                       0x147f19368         <unknown>
16  <unknown>                       0x147e0aab0         <unknown>
17  <unknown>                       0x1401d1494         <unknown>
18  <unknown>                       0x1401d20dc         <unknown>
19  <unknown>                       0x147e4c1b4         <unknown>
20  <unknown>                       0x147f1b5f8         <unknown>
21  <unknown>                       0x147e3b754         <unknown>
22  <unknown>                       0x147e0b618         <unknown>
23  Electron Framework              0x10ee0c49c         v8::internal::(anonymous namespace)::Invoke (simulator.h:178)
24  Electron Framework              0x10ee0d08c         v8::internal::(anonymous namespace)::InvokeWithTryCatch (execution.cc:475)
25  Electron Framework              0x10ee0d1e0         v8::internal::Execution::TryRunMicrotasks (execution.cc:576)
26  Electron Framework              0x10ee37364         v8::internal::MicrotaskQueue::PerformCheckpoint (microtask-queue.cc:176)
27  Electron Framework              0x1146cce9c         node::InternalCallbackScope::Close (callback.cc:137)
28  Electron Framework              0x1146ccb64         node::InternalCallbackScope::~InternalCallbackScope (callback.cc:92)
29  Electron Framework              0x1147112b4         node::Environment::RunTimers (env.cc:1376)
30  Electron Framework              0x10daf9980         uv__run_timers (timer.c:178)
31  Electron Framework              0x10dafcb3c         uv_run (core.c:465)
32  Electron Framework              0x10dc944d4         electron::NodeBindings::UvRunOnce (node_bindings.cc:891)
33  Electron Framework              0x110e2016c         base::TaskAnnotator::RunTaskImpl (callback.h:156)
34  Electron Framework              0x110e3cea4         base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork (task_annotator.h:89)
35  Electron Framework              0x110e8851c         base::MessagePumpCFRunLoopBase::RunWorkSource (message_pump_apple.mm:444)
36  Electron Framework              0x10da7ad7c         base::apple::CallWithEHFrame
37  Electron Framework              0x110e876a4         base::MessagePumpCFRunLoopBase::RunWorkSource (message_pump_apple.mm:415)
38  CoreFoundation                  0x19c89deac         __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
39  CoreFoundation                  0x19c89de40         __CFRunLoopDoSource0
40  CoreFoundation                  0x19c89dbb0         __CFRunLoopDoSources0
41  CoreFoundation                  0x19c89c79c         __CFRunLoopRun
42  CoreFoundation                  0x19c89be08         CFRunLoopRunSpecific
43  HIToolbox                       0x1a7036ffc         RunCurrentEventLoopInMode
44  HIToolbox                       0x1a7036e38         ReceiveNextEventCommon
45  HIToolbox                       0x1a7036b90         _BlockUntilNextEventMatchingListInModeWithFilter
46  AppKit                          0x1a00f496c         _DPSNextEvent
47  AppKit                          0x1a08e6de8         -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
48  AppKit                          0x1a00e7cb4         -[NSApplication run]
49  Electron Framework              0x110e89244         base::MessagePumpNSApplication::DoRun (message_pump_apple.mm:805)
50  Electron Framework              0x110e87068         base::MessagePumpCFRunLoopBase::Run (message_pump_apple.mm:156)
51  Electron Framework              0x110e3d9a0         base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run (thread_controller_with_message_pump_impl.cc:646)
52  Electron Framework              0x110e05a98         base::RunLoop::Run (run_loop.cc:134)
53  Electron Framework              0x10ffcbcd0         content::BrowserMainLoop::RunMainMessageLoop (browser_main_loop.cc:1094)
54  Electron Framework              0x10ffcd744         content::BrowserMainRunnerImpl::Run (browser_main_runner_impl.cc:158)
55  Electron Framework              0x10ffc964c         content::BrowserMain (browser_main.cc:34)
56  Electron Framework              0x10de12aa8         content::RunBrowserProcessMain (content_main_runner_impl.cc:712)
57  Electron Framework              0x10de13b1c         content::ContentMainRunnerImpl::RunBrowser (content_main_runner_impl.cc:1299)
...

Replies

What is the CF_IS_OBJC function inside the CFDataGetBytePtr function, and why did it crash there?

Certain Core Foundation types are toll-free bridged to their Foundation equivalent. That means that you can pass the NS object to a CF routine and vice versa. For example, NSData and CFData as so bridged, so you can pass an NSData object to a CF routine like CFDataGetBytePtr. However, if you pass an invalid point to CFDataGetBytePtr, it can crash in this way. I’ve explained this many times in the past, but today I decided to write it down properly. See Crashes on the Toll-Free Bridge.

Your crash is a clear example of this problem:

0   CoreFoundation      … CF_IS_OBJC
1   CoreFoundation      … CFDataGetBytePtr
2   .app.desktop.1inmRz … <unknown>

You need to identify the code in frame 2 and then look at how it’s managing the value it passes to CFDataGetBytePtr.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo Thanks for the response. I am passing the return value of TISGetInputSourceProperty after static casting it to CFDataRef to the CFDataGetBytePtr function.

I am passing the return value of TISGetInputSourceProperty after static casting it to CFDataRef to the CFDataGetBytePtr function.

That is a ‘selector based’ API, that is, the result you get back depends on the selector (propertyKey) you pass in. What key are you using?

As an aside, if you want to trap problems like this early, check the type at runtime using CFGetTypeID:

let tis: TISInputSource = …
let someProperty: CFString = ;
guard let raw = TISGetInputSourceProperty(tis, someProperty) else {
    …
}
let data = Unmanaged<CFData>.fromOpaque(raw).takeUnretainedValue()
assert( CFGetTypeID(data) == CFDataGetTypeID() )
…

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I am using kTISPropertyUnicodeKeyLayoutData as the property key. This function call with the same code works for our users every time. However, it failed just this once with this issue. Do you know how that is possible?

However, it failed just this once with this issue.

I’d like to clarify that. Does it mean that you have a single crash report like this? Or a single user who’s experiencing it regularly? Or something else?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, I only got a single crash report like this.

OK. That limits your options. The most likely cause is a very rare memory management issues. My general advice on that front is that you run your product with the standard memory debugging tools to see if you can get the problem to reproduce more frequently.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"