User crash report contains ??? instead of my app's symbols and no binary image base address

A user of my app sent me a crash report. I have never seen one like this before. All of my app's symbols are replaced with three question marks (???)

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ???                           	       0x10844eb40 ???
1   CoreFoundation                	    0x7ff80f155518 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 137

and the binary image as

0x0 - 0xffffffffffffffff ??? (*) <00000000-0000-0000-0000-000000000000> ???

so I cannot find out where exactly the crash happened.

What can cause this kind of crash report and can I do anything with it?

Answered by DTS Engineer in 878474022

Consider this:

Exception Type:    EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: KERN_MEMORY_ERROR at 0x000000010844eb40

and this:

Thread 0 crashed with X86 Thread State (64-bit):
  …
  rip: 0x000000010844eb40  …

(In Intel, RIP is the PC register.)

Your program has crashed to an unmapped memory exception and the crashing address is the PC. That is, the program has jumped to a bad address. That’s why you get this:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ???                           	       0x10844eb40 ???

because there is no code mapped at that location.

Notably, let’s look at more of that backtrace:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0 ???                0x10844eb40 ???
1 CoreFoundation  0x7ff80f155518 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 137
2 CoreFoundation  0x7ff80f1b864e ___CFXRegistrationPost_block_invoke + 88
3 CoreFoundation  0x7ff80f1b85a2 _CFXRegistrationPost + 515
4 CoreFoundation  0x7ff80f134dd6 _CFXNotificationPost + 763
5 Foundation      0x7ff810e22752 -[NSNotificationCenter postNotificationName:object:userInfo:] + 82
6 AppKit          0x7ff8130ca2e1 __postVolumeNotification_block_invoke + 64

Frame 6 is AppKit posting a volume notification. Frames 5 through 1 are notification infrastructure. Frame 0 is your crash.

The most likely causes of this are:

  • You’ve registered for a notification and then the underlying object has been deallocated.
  • Something has corrupted memory.

If you’re using volume notifications then I recommend that you focus your efforts there. Also engage the standard memory debugging tools to see if you can make this more reproducible. And do this all while generating volume notifications, for example, mounting and unmounting volumes.

Share and Enjoy

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

Another strange thing is that when dragging the crash report to the Xcode dock icon, the Xcode console logs this error:


User Command: command script import -s lldb.macosx.crashlog
User Command: crashlog --interactive --skip-status --no-parallel-image-loading "~/crash.ips"
Resolved symbols for 0A35BC69-660D-3BC0-8AB4-3FA8D922EECB /usr/lib/libobjc-trampolines.dylib...
Resolved symbols for 79EFE8B6-A212-3E98-B801-C9F2BF18EA68 /usr/lib/dyld...
Traceback (most recent call last):
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/macosx/crashlog.py", line 1444, in __call__
    SymbolicateCrashLogs(debugger, shlex.split(command), result, True)
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/macosx/crashlog.py", line 1855, in SymbolicateCrashLogs
    load_crashlog_in_scripted_process(
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/macosx/crashlog.py", line 1557, in load_crashlog_in_scripted_process
    process.GetScriptedImplementation().set_crashlog(crashlog)
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/macosx/crashlog_scripted_process.py", line 46, in set_crashlog
    self.threads[thread.index] = CrashLogScriptedThread(self, None, thread)
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/macosx/crashlog_scripted_process.py", line 171, in __init__
    super().__init__(process, args)
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/plugins/scripted_process.py", line 271, in __init__
    self.get_register_info()
  File "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/plugins/scripted_process.py", line 365, in get_register_info
    raise ValueError("Unknown architecture", self.originating_process.arch)
ValueError: ('Unknown architecture', 'x86_64h')

Consider this:

Exception Type:    EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: KERN_MEMORY_ERROR at 0x000000010844eb40

and this:

Thread 0 crashed with X86 Thread State (64-bit):
  …
  rip: 0x000000010844eb40  …

(In Intel, RIP is the PC register.)

Your program has crashed to an unmapped memory exception and the crashing address is the PC. That is, the program has jumped to a bad address. That’s why you get this:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ???                           	       0x10844eb40 ???

because there is no code mapped at that location.

Notably, let’s look at more of that backtrace:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0 ???                0x10844eb40 ???
1 CoreFoundation  0x7ff80f155518 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 137
2 CoreFoundation  0x7ff80f1b864e ___CFXRegistrationPost_block_invoke + 88
3 CoreFoundation  0x7ff80f1b85a2 _CFXRegistrationPost + 515
4 CoreFoundation  0x7ff80f134dd6 _CFXNotificationPost + 763
5 Foundation      0x7ff810e22752 -[NSNotificationCenter postNotificationName:object:userInfo:] + 82
6 AppKit          0x7ff8130ca2e1 __postVolumeNotification_block_invoke + 64

Frame 6 is AppKit posting a volume notification. Frames 5 through 1 are notification infrastructure. Frame 0 is your crash.

The most likely causes of this are:

  • You’ve registered for a notification and then the underlying object has been deallocated.
  • Something has corrupted memory.

If you’re using volume notifications then I recommend that you focus your efforts there. Also engage the standard memory debugging tools to see if you can make this more reproducible. And do this all while generating volume notifications, for example, mounting and unmounting volumes.

Share and Enjoy

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

Thanks for your explanations. Is the unmapped memory exception also the reason why the binary image address for my app is 0x0 - 0xffffffffffffffff?

I can confirm that the app registers for volume notifications using

let workspaceNotificationCenter = NSWorkspace.shared.notificationCenter
workspaceNotificationCenter.addObserver(self, selector: #selector(didWake(_:)), name: NSWorkspace.didWakeNotification, object: nil)
workspaceNotificationCenter.addObserver(self, selector: #selector(volumeDidMount(_:)), name: NSWorkspace.didMountNotification, object: nil)
workspaceNotificationCenter.addObserver(self, selector: #selector(volumeDidRename(_:)), name: NSWorkspace.didRenameVolumeNotification, object: nil)
workspaceNotificationCenter.addObserver(self, selector: #selector(volumeWillUnmount(_:)), name: NSWorkspace.willUnmountNotification, object: nil)
workspaceNotificationCenter.addObserver(self, selector: #selector(volumeDidUnmount(_:)), name: NSWorkspace.didUnmountNotification, object: nil)

The object that registers them also unregisters them in its deinit:

NSWorkspace.shared.notificationCenter.removeObserver(self)

Admittedly, I'm not sure if the unregistration works or if the deinit is prevented from being called by the notification center retaining the observer. I mainly added that code for "completeness", but in reality the observer is a let property of the app delegate, so it lives as long as the app lives.

Besides, the unregistration seems to be superfluous according to the documentation:

If your app targets iOS 9.0 and later or macOS 10.11 and later, you do not need to unregister an observer that you created with this function. If you forget or are unable to remove an observer, the system cleans up the next time it would have posted to it.

I also wasn't able to reproduce the crash with the tools you suggested, and I don't think I have seen this kind of crash before (my app has been on the App Store for many years).

Does this rule out the first most likely cause and shifts "Something has corrupted memory" from suspect number two to number one?

Is the unmapped memory exception also the reason why the binary image address for my app is 0x0 - 0xffffffffffffffff?

Sadly, it’s not that simple. I created a small test app with this code:

- (IBAction)testAction:(id)sender {
    #pragma unused(sender)
    NSLog(@"-[AppDelegate testAction:]");
    void * p = (void *) 0x123456789ab;
    typedef void (*FunctionPtr)(void);
    FunctionPtr f = (FunctionPtr) p;
    f();
}

and it produces a crash report like this:

Exception Type:    EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x00000123456789ab
Exception Codes:   0x0000000000000001, 0x00000123456789ab

…

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   ???        0x123456789ab ???
1   xxom         0x10e301bf3 -[AppDelegate testAction:] + 83
2   AppKit    0x7ff81fa612ea -[NSApplication(NSResponder) sendAction:to:from:] + 444

…

Thread 0 crashed with X86 Thread State (64-bit):
  …
  rip: 0x00000123456789ab  rfl: 0x0000000000010202  cr2: 0x00000123456789ab

which all matches what you’re seeing. But this is very different:

VM Region Info: 0x123456789ab is not in any region.  Bytes after previous region: 1246129965484  Bytes before following region: 104302116370005
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      mapped file                 118b94000-122454000    [152.8M] r--/rw- SM=COW  Object_id=275f869
--->  GAP OF 0x5ffeddbac000 BYTES
      MALLOC_NANO              600000000000-600020000000 [512.0M] rw-/rwx SM=PRV  

This indicates that the memory is completely unmapped, which makes sense in my case. But contrast this with your crash:

VM Region Info: 0x10844eb40 is in 0x108294000-0x10852e000;  …
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  mapped file                 108294000-10852e000    [ 2664K] r-x/r-x SM=COW  Object_id=4efa947e
      mapped file                 10852e000-108563000    [  212K] rw-/rw- SM=COW  Object_id=498b2d95

So memory is mapped at your address but the crash report isn’t able to identify it. Notably, this memory is mapped r-x, suggesting it’s an executable. Does the size of that mapping (so, 0x10852e000-0x108294000 which equals 0x0029a000) match the size of any Mach-O image within this version of your app?

Share and Enjoy

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

That mapping size 0x0029a000 is 2'727'936 in decimal, so I would say about 2.7 MB? The newest app version contains a Contents/MacOS/MyApp executable of 6’231’472 bytes (I'm assuming that's what you mean by Mach-O image).

I just noticed that the crash report only displays three question marks instead of the app version, but the user wrote to me that they started testing the app so I assume they have one of the newest versions, which are all about the same size.

I'm assuming that's what you mean by Mach-O image.

A Mach-O image is code that can be mapped into memory by the dynamic linker and then run directly, as opposed to something like a .o file that contains code that must be linked before it can be run. I talk more about this in An Apple Library Primer.

A Mach-O image is often stored within a universal binary, one image per architecture. So when looking at stuff like this you have to consider the image of the architecture that was running.

The other thing to considered is that the dynamic linker may only map in parts of your image.

A good way to see what actually gets mapped is to run the app and then run vmmap against it. Consider this:

% ls -lh "Pages Creator Studio.app/Contents/MacOS/Pages"
-rwxr-xr-x  1 root  wheel    45M 16 Jan 02:44 Pages Creator Studio.app/Contents/MacOS/Pages

The Pages executable is 45 MiB. And this:

% file "Pages Creator Studio.app/Contents/MacOS/Pages" 
…
…/Pages (for architecture x86_64)…
…/Pages (for architecture arm64)…
% otool -f "Pages Creator Studio.app/Contents/MacOS/Pages" 
Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
    …
architecture 1
    cputype 16777228
    cpusubtype 0
    capabilities 0x0
    offset 24657920
    size 22398960
    align 2^14 (16384)

which means that about half of that is the arm64 architecture. And if you run the app:

% open "Pages Creator Studio.app"
% vmmap "Pages"
…
==== Non-writable regions for process 14465
REGION TYPE      START - END         [ VSIZE  RSDNT  DIRTY   SWAP] PRT/MAX SHRMOD PURGE  REGION DETAIL
__TEXT        100988000-101bac000    [ 18.1M  4768K     0K     0K] r-x/r-x SM=COW        …/Pages
__DATA_CONST  101bac000-101c94000    [  928K   432K    16K     0K] r--/rw- SM=COW        …/Pages
__LINKEDIT    101e6c000-101f38000    [  816K   208K     0K     0K] r--/r-- SM=COW        …/Pages
…

==== Writable regions for process 14465
REGION TYPE      START - END         [ VSIZE  RSDNT  DIRTY   SWAP] PRT/MAX SHRMOD PURGE  REGION DETAIL
__DATA        101c94000-101e1c000    [ 1568K  1568K   640K     0K] rw-/rw- SM=COW        …/Pages
__DATA        101e1c000-101e6c000    [  320K   112K   112K     0K] rw-/rw- SM=PRV        …/Pages
…

you can see that the executable gets mapped in five different times, three read-only and two read/write. It’s that first one that’s most relevant here, because code lives in the __TEXT segment.

Share and Enjoy

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

When running those commands on my M1 Mac I get this:

% file /Applications/MyApp.app/Contents/MacOS/MyApp
/Applications/MyApp.app/Contents/MacOS/MyApp: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64]
/Applications/MyApp.app/Contents/MacOS/MyApp (for architecture x86_64):	Mach-O 64-bit executable x86_64
/Applications/MyApp.app/Contents/MacOS/MyApp (for architecture arm64):	Mach-O 64-bit executable arm64

and

% otool -f /Applications/MyApp.app/Contents/MacOS/MyApp
Fat headers
fat_magic 0xcafebabe
nfat_arch 2
architecture 0
    cputype 16777223
    cpusubtype 3
    capabilities 0x0
    offset 16384
    size 3190880
    align 2^14 (16384)
architecture 1
    cputype 16777228
    cpusubtype 0
    capabilities 0x0
    offset 3211264
    size 3069792
    align 2^14 (16384)

and

...
==== Non-writable regions for process 14835
REGION TYPE                    START - END         [ VSIZE  RSDNT  DIRTY   SWAP] PRT/MAX SHRMOD PURGE    REGION DETAIL
__TEXT                      10061c000-1008a0000    [ 2576K  2048K     0K     0K] r-x/r-x SM=COW          /Applications/MyApp.app/Contents/MacOS/MyApp
__DATA_CONST                1008a0000-1008b0000    [   64K    64K    64K     0K] r--/rw- SM=COW          /Applications/MyApp.app/Contents/MacOS/MyApp
__LINKEDIT                  1008f0000-100928000    [  224K    80K     0K     0K] r--/r-- SM=COW          /Applications/MyApp.app/Contents/MacOS/MyApp
...

The range of the __TEXT segment 10061c000-1008a0000 has length 0x0284000 (hex) = 2637824 (decimal).

But the crash report mentions the architexture x86_64, which I don't own myself anymore. I don't know if it makes sense to do so, but by using the formula arm64 __TEXT segment size / arm64 Mach-O size * x86_64 Mach-O size we get 2637824 / 3069792 * 3190880 =~ 2’741’873 ... which is about the previously mentioned 2'727'936?

User crash report contains ??? instead of my app's symbols and no binary image base address
 
 
Q