Skip to content

Fix hit_test function superclass lookup - #311

Open
Johnjackbogart wants to merge 1 commit into
RustAudio:masterfrom
Johnjackbogart:patch-1
Open

Fix hit_test function superclass lookup#311
Johnjackbogart wants to merge 1 commit into
RustAudio:masterfrom
Johnjackbogart:patch-1

Conversation

@Johnjackbogart

@Johnjackbogart Johnjackbogart commented Aug 9, 2026

Copy link
Copy Markdown

Hi RustAudio team!

I was working with baseview on a simple plugin and started running into crashing caused by recursion and stack overflow issues, and had Claude help me resolve this as I am not a Rust expert.

I'm on MacOS 26.6 and there seems to be a regression in the hit_test function. When launching my plugin, it immediately crashes. I attached the crash report at the bottom of this PR as well as Claude's synopsis.

The change stops dynamically looking up the superclass of the view in favor of hardcoding NSView::class(), the same value base view is registering as this view's superclass. This resolved the issue for me, but I worry about downstream issues as this doesn't seem to be a robust fix.

claude synopsis.rtf

crash report.rtf

Refactor hit_test function to use statically-known NSView class for superclass lookup avoiding infinite recursion issues.
@Johnjackbogart

Johnjackbogart commented Aug 9, 2026

Copy link
Copy Markdown
Author

More info, via Claude (this was computed using lldb):

That's it — confirmed with hard evidence, not theory this time. Here's what the live introspection showed:

Root cause, confirmed

│ What │ Value │

│ Receiver's actual runtime class (object_getClass) │ NSKVONotifying_BaseviewNSView_15265A13-...


│ superclass (buggy computed value, this.view.class().superclass()) │ BaseviewNSView_15265A13-... — baseview's own class, not NSView │


│ Real NSView class (objc_getClass("NSView")) │ a completely different address │


│ superclass_addr == receiver's own class addr │ True (once corrected for the KVO layer) │


│ superclass_addr == real NSView addr │ False │


What's happening: at some point after the window is created, AppKit installs a KVO observer on the view (almost certainly watching something like layer or effectiveAppearance
for cursor/appearance updates — this is normal, expected AppKit behavior, not a baseview mistake). Installing a KVO observer isa-swizzles the instance: its actual runtime class
becomes a synthetic NSKVONotifying_BaseviewNSView_ subclass that AppKit generates on the fly, whose superclass is baseview's original registered class.

So when hit_test ran this.view.class().superclass():

  • .class() → the swizzled proxy, NSKVONotifying_BaseviewNSView_...
  • .superclass() of that → not NSView, but baseview's own BaseviewNSView_...

Then msg_send![super(this.view, superclass), hitTest:] starts the method search at baseview's own class — which is exactly where the hitTest: override lives — so it calls itself
again. Infinite recursion, exactly matching the crash report's perfectly uniform self-recursion.

This corrects something I'd only guessed at before: I'd assumed -class would "lie" the standard KVO way (hide the swizzle, report the original class) — but empirically here it
reports the swizzled class. Either way, the fix is unaffected: hardcoding NSView::class() sidesteps this entirely since it never asks the (potentially swizzled) instance
anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant