Crash on macOS when the subclassing adapter is dropped while the view has key-value observers
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 35/100
Direzione di ricerca
Start in adapters/macos/src/subclass.rs, especially SubclassingAdapter::drop, and inspect the linked pull request #822 for current work. Reproduce with the supplied observer example and trace how the view’s Objective-C class changes while observers are registered. Done means dropping the adapter leaves observers removable without raising an exception.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
What happens
An app that uses the macOS SubclassingAdapter is terminated by an uncaught exception every time its window is closed. In our case this is an eframe/egui 0.36 app (winit 0.30, accesskit_winit 0.32, accesskit_macos 0.26.3) on macOS 27.0.1, on a MacBook Pro with a Touch Bar (MacBookPro17,1):
*** Terminating app due to uncaught exception 'NSRangeException', reason:
'Cannot remove an observer <_NSTouchBarFinderObservation 0x…> for the key path
"nextResponder" from <WinitView 0x…> because it is not registered as an observer.'
-[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:]
-[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:]
-[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:context:]
-[_NSTouchBarFinderObservation invalidate]
___NSTouchBarFinderSetNeedsUpdateOnMain_block_invoke_2
NSDisplayCycleObserverInvoke
NSDisplayCycleFlush
I haven't checked other macOS versions or Macs without a Touch Bar.
Cause
SubclassingAdapter::drop calls object_setClass(view, prev_class) unconditionally. AppKit registers key-value observers on the window's first responder (_NSTouchBarFinderObservation, key paths nextResponder and touchBar), so by the time the adapter is dropped, the view's real class is NSKVONotifying_AccessKitSubclassOfWinitView. Resetting the class discards KVO's subclass while the observers are still registered, and AppKit's later removeObserver:forKeyPath: raises.
Tracing addObserver:/removeObserver: in a debugger showed the observers being added while the view's class was AccessKitSubclassOfWinitView, and removed after it had been reset to WinitView.
adapters/macos/src/subclass.rs on main has the same code as 0.26.3.
What should happen
Dropping the adapter shouldn't break observers that other code has registered on the view.
How to reproduce
This program does what AppKit does, with an observer of its own. With accesskit_macos 0.27.1 it aborts at the last line (fatal runtime error: Rust cannot catch foreign exceptions, aborting).
[dependencies]
accesskit = "0.25"
accesskit_macos = "0.27.1"
objc2 = "0.5.1"
objc2-app-kit = { version = "0.2.0", features = ["NSResponder", "NSView"] }
objc2-foundation = { version = "0.2.0", features = ["NSString"] }
use std::ffi::c_void;
use accesskit::{ActionHandler, ActionRequest, ActivationHandler, TreeUpdate};
use accesskit_macos::SubclassingAdapter;
use objc2::rc::Id;
use objc2::{class, msg_send, msg_send_id};
use objc2_app_kit::NSView;
use objc2_foundation::{NSObject, NSString};
struct NoTree;
impl ActivationHandler for NoTree {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
None
}
}
struct NoActions;
impl ActionHandler for NoActions {
fn do_action(&mut self, _request: ActionRequest) {}
}
fn main() {
let view: Id<NSView> = unsafe { msg_send_id![class!(NSView), new] };
let adapter = unsafe {
SubclassingAdapter::new(&*view as *const NSView as *mut c_void, NoTree, NoActions)
};
// Stand-in for AppKit's own observers on the first responder.
let observer = NSObject::new();
let key_path = NSString::from_str("nextResponder");
let context: *mut c_void = std::ptr::null_mut();
let _: () = unsafe {
msg_send![&view, addObserver: &*observer, forKeyPath: &*key_path, options: 0usize, context: context]
};
drop(adapter);
// Raises NSRangeException.
let _: () = unsafe { msg_send![&view, removeObserver: &*observer, forKeyPath: &*key_path] };
}
- Lingua principale
- Rust
- Stelle
- 1.5k
- Fork
- 122
- Merge medio
- 1h 7m
- PR unite (30g)
- 18
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di AccessKit/accesskit
-
Document sub-treesAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
Document `Role::ColorWell`Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
AccessKit/accesskit#802 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
AccessKit/accesskit#778 · 24 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
AccessKit/accesskit#749 · 9 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di AccessKit/accesskit
Issue simili
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 75/100
RustCrypto/SSH#596 ·
-
proxy: SQL-over-HTTP turns empty arrays into [""] or [false], or HTTP 500 for int and float arraysAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
neondatabase/neon#12965 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
goauthentik/authentik#26867 ·
I maintainer di solito rispondono entro 1 giorno
-
Table and code-block right borders are clipped when the TOC panel is resized wider than the defaultAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
I maintainer di solito rispondono entro 1 giorno
-
api bug macos maintainer-needed p2 triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno