Thanks. So it sounds like the NSImage is getting over-released or being incorrectly deallocated, although it's unclear to me what exactly is trying to form a weak reference, since my code (as shown above) has a strong reference. Unfortunately, the higher up function calls are made by AppKit, which is not open source, so I cannot look it up.
Seeing that code wouldn't actually help. The thing that makes over-release issues (and most other memory crashes ) hard to debug is that the crash log you’re looking at is NOT why your app crashed. At some earlier point in your app, "something" happened in your app that caused an "extra" release that would not normally occur.
In other words, what the crash log shows is a "victim" of an underlying issue, not its direct cause.
As far as I understand, the link you posted helps investigating memory issues in Xcode, but since the crash reports are downloaded by Xcode from other users and I cannot reproduce it myself...
I should have posted more direct links, but most of the memory-related debug libraries Xcode includes are specifically designed with this issue in mind. That is, they're designed to try and find hard-to-reproduce memory issues, typically by "forcing" your app to crash under circumstances when it normally would not.
As the simplest to explain example, under normal circumstances, accessing a recently freed object often "works" fine. As long as the object hasn't been overwritten, the data will be exactly the same as it was before it was freed, so everything "works". However, what the Zombies instrument actually does is modify the "dealloc" method so that freeing an object doesn't ACTUALLY free that object, but instead replaces it with an intentionally invalid object ("the zombie"). That means that all accesses to that previously freed object will not crash and, conveniently, the zombie object can also track the object’s previous retain/release history, so you can see exactly where things went wrong.
Our lower-level tools like ASan, TSan, UBSan, and the Main Thread Checker are all designed with that same mindset— find a bug by forcing crashes to occur that would otherwise require very specific timing or circumstances.
I can't guarantee that any of these tools will find your bug, but issues like this can be extremely difficult to investigate, so any "easy" testing option is worth pursuing.
The Xcode statistics seem to show that it only happens with macOS 15.3 or newer. I don't know if it's because there's not enough space to show older releases, or if it's really a clue that it's a change introduced with macOS 15.3 that causes this issue.
The word "cause" is tricky here. As I talked about above, issues like this are often heavily dependent on the timing of activity inside your app. Because of that, it's not at all unusual for an issue to suddenly appear or increase with a particular system release or app change. However, that doesn't mean that a system or app update caused the issue or that the solution is to "undo" that change; it may just mean that those timing changes exposed an issue that was previously hidden.
From my perspective, it would make sense that it's a new issue with macOS 15.3.
There isn't really any way for me to know for certain that this isn't a bug in the system; however, I can say that this doesn't match any crash signature we're actively tracking or investigating. If it is a system bug, it's not a very common one.
Perhaps it helps to share how the image is created. The result of the method below is directly assigned to myEntity.image in the code I posted originally. Could any of the used APIs have a bug that causes the image to be released incorrectly?
What thread is myEntity.image accessed on? If it's assigned on one thread and accessed on another, then that can cause exactly the kind of crash you're seeing.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware