From 699440301416d6228769094ab9c54edcc0986b6b Mon Sep 17 00:00:00 2001 From: Daneel Date: Fri, 27 Feb 2026 14:55:03 +0100 Subject: [PATCH] =?UTF-8?q?patches:=20complete=20thread=20safety=20?= =?UTF-8?q?=E2=80=94=20dispatch=5Fsync=20on=20ALL=20AX=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add dispatch_sync guard to: Buffer accessibilityFrame, accessibilityLabel, accessibilityRole, accessibilityRoleDescription, accessibilityPlaceholderValue, isAccessibilityFocused. ModeLine accessibilityValue, accessibilityFrame, accessibilityLabel. setAccessibilitySelectedTextRange now uses record_unwind_current_buffer + unbind_to. --- ...oundsForRange-for-macOS-Zoom-cursor-.patch | 119 ++++++++++++++---- 1 file changed, 94 insertions(+), 25 deletions(-) diff --git a/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch b/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch index d023ee9..463c8b4 100644 --- a/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch +++ b/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch @@ -1,25 +1,22 @@ -From 4871f48958e63cbf1d0086ba1cc0c15fabb6f7df Mon Sep 17 00:00:00 2001 +From 6878620f894a738eb11f9742a3920434cfb00e1e Mon Sep 17 00:00:00 2001 From: Martin Sukany -Date: Fri, 27 Feb 2026 14:49:27 +0100 +Date: Fri, 27 Feb 2026 14:54:57 +0100 Subject: [PATCH] ns: implement VoiceOver accessibility -All AX getter methods now consistently dispatch_sync to the main -thread when called from the AX server thread, eliminating the mixed -threading strategy (some dispatch_sync, some @synchronized, some -neither) that could cause use-after-free on cachedText. +All AX protocol methods now dispatch_sync to the main thread, +including accessibilityFrame, accessibilityLabel, accessibilityRole, +accessibilityRoleDescription, accessibilityPlaceholderValue, +isAccessibilityFocused on EmacsAccessibilityBuffer, and +accessibilityValue/accessibilityFrame/accessibilityLabel on +EmacsAccessibilityModeLine. setAccessibilitySelectedTextRange +uses record_unwind_current_buffer for exception safety. -* src/nsterm.m: Add dispatch_sync guards to accessibilityNumberOfCharacters, -accessibilitySelectedText, accessibilityStringForRange:, -accessibilityLineForIndex:, accessibilityRangeForLine:, -accessibilityRangeForIndex:, accessibilityVisibleCharacterRange, -setAccessibilitySelectedTextRange:. Document GC safety of -Lisp_Object capture in setAccessibilityFocused: GCD block. -* etc/NEWS: Announce VoiceOver accessibility on macOS. +* src/nsterm.m, src/nsterm.h, etc/NEWS: As described. --- etc/NEWS | 11 + src/nsterm.h | 108 ++ - src/nsterm.m | 2798 +++++++++++++++++++++++++++++++++++++++++++++++--- - 3 files changed, 2775 insertions(+), 142 deletions(-) + src/nsterm.m | 2870 +++++++++++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 2847 insertions(+), 142 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 7367e3c..0e4480a 100644 @@ -177,7 +174,7 @@ index 7c1ee4c..6455547 100644 diff --git a/src/nsterm.m b/src/nsterm.m -index 932d209..2e47899 100644 +index 932d209..078465a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -46,6 +46,7 @@ Updated by Christian Limpach (chris@nice.ch) @@ -243,7 +240,7 @@ index 932d209..2e47899 100644 ns_focus (f, NULL, 0); NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; -@@ -6849,213 +6891,2332 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg +@@ -6849,213 +6891,2404 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg /* ========================================================================== @@ -1428,6 +1425,14 @@ index 932d209..2e47899 100644 + +- (NSAccessibilityRole)accessibilityRole +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSAccessibilityRole result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityRole]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (w && MINI_WINDOW_P (w)) + return NSAccessibilityTextFieldRole; @@ -1436,6 +1441,14 @@ index 932d209..2e47899 100644 + +- (NSString *)accessibilityPlaceholderValue +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSString *result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityPlaceholderValue]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (!w || !MINI_WINDOW_P (w)) + return nil; @@ -1447,6 +1460,14 @@ index 932d209..2e47899 100644 + +- (NSString *)accessibilityRoleDescription +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSString *result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityRoleDescription]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (w && MINI_WINDOW_P (w)) + return @"minibuffer"; @@ -1455,6 +1476,14 @@ index 932d209..2e47899 100644 + +- (NSString *)accessibilityLabel +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSString *result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityLabel]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (w && WINDOW_LEAF_P (w)) + { @@ -1474,6 +1503,14 @@ index 932d209..2e47899 100644 + +- (BOOL)isAccessibilityFocused +{ ++ if (![NSThread isMainThread]) ++ { ++ __block BOOL result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self isAccessibilityFocused]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (!w) + return NO; @@ -1593,6 +1630,9 @@ index 932d209..2e47899 100644 + + [self ensureTextCache]; + ++ specpdl_ref count = SPECPDL_INDEX (); ++ record_unwind_current_buffer (); ++ + /* Convert accessibility index to buffer charpos via mapping. */ + ptrdiff_t charpos = [self charposForAccessibilityIndex:range.location]; + @@ -1604,9 +1644,7 @@ index 932d209..2e47899 100644 + + block_input (); + -+ /* Move point directly in the buffer. Use set_point_both which -+ operates on the current buffer — temporarily switch if needed. */ -+ struct buffer *oldb = current_buffer; ++ /* Move point directly in the buffer. */ + if (b != current_buffer) + set_buffer_internal_1 (b); + @@ -1626,8 +1664,7 @@ index 932d209..2e47899 100644 + else + bset_mark_active (b, Qnil); + -+ if (b != oldb) -+ set_buffer_internal_1 (oldb); ++ unbind_to (count, Qnil); + + unblock_input (); + @@ -1953,6 +1990,14 @@ index 932d209..2e47899 100644 + +- (NSRect)accessibilityFrame +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSRect result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityFrame]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (!w) + return NSZeroRect; @@ -2452,6 +2497,14 @@ index 932d209..2e47899 100644 + +- (NSString *)accessibilityLabel +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSString *result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityLabel]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (w && WINDOW_LEAF_P (w)) + { @@ -2471,6 +2524,14 @@ index 932d209..2e47899 100644 + +- (id)accessibilityValue +{ ++ if (![NSThread isMainThread]) ++ { ++ __block id result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityValue]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (!w) + return @""; @@ -2479,6 +2540,14 @@ index 932d209..2e47899 100644 + +- (NSRect)accessibilityFrame +{ ++ if (![NSThread isMainThread]) ++ { ++ __block NSRect result; ++ dispatch_sync (dispatch_get_main_queue (), ^{ ++ result = [self accessibilityFrame]; ++ }); ++ return result; ++ } + struct window *w = [self validWindow]; + if (!w || !w->current_matrix) + return NSZeroRect; @@ -2718,7 +2787,7 @@ index 932d209..2e47899 100644 #define NS_KEYLOG 0 - (void)keyDown: (NSEvent *)theEvent -@@ -8237,6 +10398,31 @@ - (void)windowDidBecomeKey /* for direct calls */ +@@ -8237,6 +10470,31 @@ - (void)windowDidBecomeKey /* for direct calls */ XSETFRAME (event.frame_or_window, emacsframe); kbd_buffer_store_event (&event); ns_send_appdefined (-1); // Kick main loop @@ -2750,7 +2819,7 @@ index 932d209..2e47899 100644 } -@@ -9474,6 +11660,322 @@ - (int) fullscreenState +@@ -9474,6 +11732,322 @@ - (int) fullscreenState return fs_state; } @@ -3073,7 +3142,7 @@ index 932d209..2e47899 100644 @end /* EmacsView */ -@@ -11303,6 +13805,18 @@ Convert an X font name (XLFD) to an NS font name. +@@ -11303,6 +13877,18 @@ Convert an X font name (XLFD) to an NS font name. DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic"); DEFSYM (Qns_handle_drag_motion, "ns-handle-drag-motion");