Revert "patches: add 0009 resource safety hardening + update 0007/0008"
This reverts commit acc2a2985e.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
From 8712cf8f567f3b0c02cc70a93aff931faa3a2df3 Mon Sep 17 00:00:00 2001
|
||||
From 6e907a1000a8b138976d6a906e40449fdf1a61c5 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 14:46:25 +0100
|
||||
Subject: [PATCH 1/3] ns: announce overlay completion candidates for VoiceOver
|
||||
Subject: [PATCH 1/2] ns: announce overlay completion candidates for VoiceOver
|
||||
|
||||
Completion frameworks such as Vertico, Ivy, and Icomplete render
|
||||
candidates via overlay before-string/after-string properties rather
|
||||
@@ -52,8 +52,8 @@ Independent overlay branch, BUF_CHARS_MODIFF gating, candidate
|
||||
announcement with overlay Zoom rect storage.
|
||||
---
|
||||
src/nsterm.h | 3 +
|
||||
src/nsterm.m | 333 +++++++++++++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 300 insertions(+), 36 deletions(-)
|
||||
src/nsterm.m | 331 +++++++++++++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 298 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/src/nsterm.h b/src/nsterm.h
|
||||
index 51c30ca..5c15639 100644
|
||||
@@ -77,7 +77,7 @@ index 51c30ca..5c15639 100644
|
||||
BOOL font_panel_active;
|
||||
NSFont *font_panel_result;
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 1780194..c1fc3cb 100644
|
||||
index 1780194..143e784 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -3258,7 +3258,12 @@ ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
|
||||
@@ -403,7 +403,7 @@ index 1780194..c1fc3cb 100644
|
||||
self.cachedPoint = point;
|
||||
|
||||
NSDictionary *change = @{
|
||||
@@ -8789,16 +8938,128 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem,
|
||||
@@ -8789,16 +8938,126 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem,
|
||||
BOOL markActive = !NILP (BVAR (b, mark_active));
|
||||
|
||||
/* --- Text changed (edit) --- */
|
||||
@@ -428,7 +428,6 @@ index 1780194..c1fc3cb 100644
|
||||
+ if (chars_modiff != self.cachedCharsModiff)
|
||||
+ {
|
||||
+ self.cachedCharsModiff = chars_modiff;
|
||||
+ if (self.emacsView)
|
||||
+ self.emacsView->overlayZoomActive = NO;
|
||||
+ [self postTextChangedNotification:point];
|
||||
+ textDidChange = YES;
|
||||
@@ -517,7 +516,6 @@ index 1780194..c1fc3cb 100644
|
||||
+ (minibuffer exit, C-g, etc.) or overlay has no
|
||||
+ recognizable selection face. Return Zoom to the
|
||||
+ text cursor. */
|
||||
+ if (self.emacsView)
|
||||
+ self.emacsView->overlayZoomActive = NO;
|
||||
+ }
|
||||
}
|
||||
@@ -536,7 +534,7 @@ index 1780194..c1fc3cb 100644
|
||||
{
|
||||
ptrdiff_t oldPoint = self.cachedPoint;
|
||||
BOOL oldMarkActive = self.cachedMarkActive;
|
||||
@@ -8966,7 +9227,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem,
|
||||
@@ -8966,7 +9225,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem,
|
||||
|
||||
|
||||
/* ===================================================================
|
||||
@@ -545,7 +543,7 @@ index 1780194..c1fc3cb 100644
|
||||
=================================================================== */
|
||||
|
||||
/* Scan visible range of window W for interactive spans.
|
||||
@@ -9157,7 +9418,7 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
@@ -9157,7 +9416,7 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
- (BOOL) isAccessibilityFocused
|
||||
{
|
||||
/* Read the cached point stored by EmacsAccessibilityBuffer on the main
|
||||
@@ -554,7 +552,7 @@ index 1780194..c1fc3cb 100644
|
||||
EmacsAccessibilityBuffer *pb = self.parentBuffer;
|
||||
if (!pb)
|
||||
return NO;
|
||||
@@ -9174,7 +9435,7 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
@@ -9174,7 +9433,7 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
dispatch_async (dispatch_get_main_queue (), ^{
|
||||
/* lwin is a Lisp_Object captured by value. This is GC-safe
|
||||
because Lisp_Objects are tagged integers/pointers that
|
||||
@@ -563,7 +561,7 @@ index 1780194..c1fc3cb 100644
|
||||
Emacs. The WINDOW_LIVE_P check below guards against the
|
||||
window being deleted between capture and execution. */
|
||||
if (!WINDOWP (lwin) || NILP (Fwindow_live_p (lwin)))
|
||||
@@ -9200,7 +9461,7 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
@@ -9200,7 +9459,7 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
|
||||
@end
|
||||
|
||||
@@ -572,7 +570,7 @@ index 1780194..c1fc3cb 100644
|
||||
Methods are kept here (same .m file) so they access the ivars
|
||||
declared in the @interface ivar block. */
|
||||
@implementation EmacsAccessibilityBuffer (InteractiveSpans)
|
||||
@@ -11922,7 +12183,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -11922,7 +12181,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
|
||||
if (WINDOW_LEAF_P (w))
|
||||
{
|
||||
@@ -581,7 +579,7 @@ index 1780194..c1fc3cb 100644
|
||||
EmacsAccessibilityBuffer *elem
|
||||
= [existing objectForKey:[NSValue valueWithPointer:w]];
|
||||
if (!elem)
|
||||
@@ -11956,7 +12217,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -11956,7 +12215,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -590,7 +588,7 @@ index 1780194..c1fc3cb 100644
|
||||
Lisp_Object child = w->contents;
|
||||
while (!NILP (child))
|
||||
{
|
||||
@@ -12068,7 +12329,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -12068,7 +12327,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
accessibilityUpdating = YES;
|
||||
|
||||
/* Detect window tree change (split, delete, new buffer). Compare
|
||||
@@ -599,7 +597,7 @@ index 1780194..c1fc3cb 100644
|
||||
Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe);
|
||||
if (!EQ (curRoot, lastRootWindow))
|
||||
{
|
||||
@@ -12077,12 +12338,12 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -12077,12 +12336,12 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
}
|
||||
|
||||
/* If tree is stale, rebuild FIRST so we don't iterate freed
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
From 7d20ec80aa0d4ca97fa789f9b85389e25d2ff719 Mon Sep 17 00:00:00 2001
|
||||
From 8564e4989f5f358092bd1494c3894a42974ee6e1 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 16:01:29 +0100
|
||||
Subject: [PATCH 2/3] ns: announce child frame completion candidates for
|
||||
Subject: [PATCH 2/2] ns: announce child frame completion candidates for
|
||||
VoiceOver
|
||||
|
||||
Completion frameworks such as Corfu, Company-box, and similar
|
||||
@@ -43,8 +43,8 @@ childFrameCompletionActive flag.
|
||||
refocus parent buffer element when child frame closes.
|
||||
---
|
||||
src/nsterm.h | 2 +
|
||||
src/nsterm.m | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 305 insertions(+), 3 deletions(-)
|
||||
src/nsterm.m | 279 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 278 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/nsterm.h b/src/nsterm.h
|
||||
index 5c15639..8b34300 100644
|
||||
@@ -67,7 +67,7 @@ index 5c15639..8b34300 100644
|
||||
@end
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index c1fc3cb..abecb4c 100644
|
||||
index 143e784..da1a319 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -7066,6 +7066,110 @@ ns_ax_selected_overlay_text (struct buffer *b,
|
||||
@@ -181,7 +181,7 @@ index c1fc3cb..abecb4c 100644
|
||||
/* Build accessibility text for window W, skipping invisible text.
|
||||
Populates *OUT_START with the buffer start charpos.
|
||||
Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS
|
||||
@@ -12313,6 +12417,146 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -12311,6 +12415,122 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
The existing elements carry cached state (modiff, point) from the
|
||||
previous redisplay cycle. Rebuilding first would create fresh
|
||||
elements with current values, making change detection impossible. */
|
||||
@@ -289,30 +289,6 @@ index c1fc3cb..abecb4c 100644
|
||||
+static EMACS_INT lastChildFrameModiff;
|
||||
+static char *lastChildFrameCandidate;
|
||||
+
|
||||
+/* Child frame completion dedup state. File-scope so that
|
||||
+ lastChildFrameBuffer can be staticpro'd against GC. */
|
||||
+static Lisp_Object lastChildFrameBuffer;
|
||||
+static EMACS_INT lastChildFrameModiff;
|
||||
+static char *lastChildFrameCandidate;
|
||||
+
|
||||
+/* Reset the re-entrance guard when unwinding past
|
||||
+ postAccessibilityUpdates due to a Lisp signal (longjmp).
|
||||
+ Without this, a signal during Lisp calls (e.g. Fget_char_property
|
||||
+ in overlay or child frame scanning) would leave
|
||||
+ accessibilityUpdating = YES permanently, suppressing all future
|
||||
+ accessibility notifications. */
|
||||
+static void
|
||||
+ns_ax_reset_accessibility_updating (void *view)
|
||||
+{
|
||||
+ ((EmacsView *)view)->accessibilityUpdating = NO;
|
||||
+}
|
||||
+
|
||||
+/* Child frame completion dedup state. File-scope so that
|
||||
+ lastChildFrameBuffer can be staticpro'd against GC. */
|
||||
+static Lisp_Object lastChildFrameBuffer;
|
||||
+static EMACS_INT lastChildFrameModiff;
|
||||
+static char *lastChildFrameCandidate;
|
||||
+
|
||||
+/* Reset the re-entrance guard when unwinding past
|
||||
+ postAccessibilityUpdates due to a Lisp signal (longjmp).
|
||||
+ Without this, a signal during Lisp calls (e.g. Fget_char_property
|
||||
@@ -328,7 +304,7 @@ index c1fc3cb..abecb4c 100644
|
||||
- (void)postAccessibilityUpdates
|
||||
{
|
||||
NSTRACE ("[EmacsView postAccessibilityUpdates]");
|
||||
@@ -12323,10 +12567,60 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -12321,10 +12541,60 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
|
||||
/* Re-entrance guard: VoiceOver callbacks during notification posting
|
||||
can trigger redisplay, which calls ns_update_end, which calls us
|
||||
@@ -390,7 +366,7 @@ index c1fc3cb..abecb4c 100644
|
||||
|
||||
/* Detect window tree change (split, delete, new buffer). Compare
|
||||
FRAME_ROOT_WINDOW --- if it changed, the tree structure changed. */
|
||||
@@ -12357,7 +12651,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -12355,7 +12625,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
NSAccessibilityFocusedUIElementChangedNotification);
|
||||
|
||||
lastSelectedWindow = emacsframe->selected_window;
|
||||
@@ -399,7 +375,7 @@ index c1fc3cb..abecb4c 100644
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12401,7 +12695,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
@@ -12399,7 +12669,7 @@ ns_ax_collect_windows (Lisp_Object window, EmacsView *view,
|
||||
NSAccessibilityFocusedUIElementChangedNotification);
|
||||
}
|
||||
|
||||
@@ -408,15 +384,12 @@ index c1fc3cb..abecb4c 100644
|
||||
}
|
||||
|
||||
/* ---- Cursor position for Zoom (via accessibilityBoundsForRange:) ----
|
||||
@@ -14343,6 +14637,12 @@ syms_of_nsterm (void)
|
||||
@@ -14341,6 +14611,9 @@ syms_of_nsterm (void)
|
||||
DEFSYM (Qns_ax_completion, "completion");
|
||||
DEFSYM (Qns_ax_completions_highlight, "completions-highlight");
|
||||
DEFSYM (Qns_ax_backtab, "backtab");
|
||||
+
|
||||
+ lastChildFrameBuffer = Qnil;
|
||||
+ staticpro (&lastChildFrameBuffer);
|
||||
+
|
||||
+ lastChildFrameBuffer = Qnil;
|
||||
+ staticpro (&lastChildFrameBuffer);
|
||||
/* Qmouse_face and Qkeymap are defined in textprop.c / keymap.c. */
|
||||
Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
From 0812e650c24f90bda79368078fa0ad45c18f39d2 Mon Sep 17 00:00:00 2001
|
||||
From: T <t@t>
|
||||
Date: Sat, 28 Feb 2026 18:45:14 +0100
|
||||
Subject: [PATCH 3/3] ns: harden VoiceOver accessibility resource safety
|
||||
|
||||
Fix several resource safety issues found during maintainer review:
|
||||
|
||||
* Announcement coalescing: add 50ms minimum interval between
|
||||
AnnouncementRequested notifications to prevent VoiceOver speech
|
||||
synthesizer stalls from rapid-fire high-priority interruptions
|
||||
(e.g. holding C-n in a completion list).
|
||||
|
||||
* cachedText thread safety: return [[cachedText retain] autorelease]
|
||||
from accessibilityValue to prevent use-after-free when the main
|
||||
thread replaces cachedText while the AX server thread is still
|
||||
using the previous value.
|
||||
|
||||
* EmacsView dealloc safety: nil out emacsView back-references on
|
||||
all accessibility elements before releasing them. Queued
|
||||
dispatch_async blocks that hold a retained element reference would
|
||||
otherwise access a dangling emacsView pointer.
|
||||
|
||||
* Nil guards: add emacsView nil checks in accessibilityParent,
|
||||
accessibilityWindow, accessibilityTopLevelUIElement, and
|
||||
overlayZoomActive access sites.
|
||||
|
||||
* src/nsterm.m (ns_ax_post_notification_with_info): Add timestamp
|
||||
coalescing for AnnouncementRequested.
|
||||
(accessibilityValue): Return retained+autoreleased cachedText.
|
||||
(dealloc): Nil out emacsView on all accessibility elements.
|
||||
(accessibilityParent, accessibilityWindow)
|
||||
(accessibilityTopLevelUIElement): Add nil guards.
|
||||
---
|
||||
src/nsterm.m | 38 +++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 37 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index abecb4c..3724b05 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -7521,11 +7521,32 @@ ns_ax_post_notification (id element,
|
||||
});
|
||||
}
|
||||
|
||||
+/* Minimum interval between AnnouncementRequested notifications
|
||||
+ (in seconds). VoiceOver can stall if overwhelmed with rapid-fire
|
||||
+ high-priority announcements that each interrupt the previous
|
||||
+ utterance. 50ms lets the speech synthesizer start before the
|
||||
+ next interruption. */
|
||||
+#define NS_AX_ANNOUNCE_MIN_INTERVAL 0.05
|
||||
+
|
||||
static inline void
|
||||
ns_ax_post_notification_with_info (id element,
|
||||
NSAccessibilityNotificationName name,
|
||||
NSDictionary *info)
|
||||
{
|
||||
+ /* Coalesce AnnouncementRequested: skip if the previous one was
|
||||
+ less than NS_AX_ANNOUNCE_MIN_INTERVAL seconds ago. Prevents
|
||||
+ speech synthesizer stalls from rapid-fire high-priority
|
||||
+ interruptions (e.g. holding C-n in a completion list). */
|
||||
+ if ([name isEqualToString:
|
||||
+ NSAccessibilityAnnouncementRequestedNotification])
|
||||
+ {
|
||||
+ static CFAbsoluteTime lastAnnouncementTime;
|
||||
+ CFAbsoluteTime now = CFAbsoluteTimeGetCurrent ();
|
||||
+ if (now - lastAnnouncementTime < NS_AX_ANNOUNCE_MIN_INTERVAL)
|
||||
+ return;
|
||||
+ lastAnnouncementTime = now;
|
||||
+ }
|
||||
+
|
||||
dispatch_async (dispatch_get_main_queue (), ^{
|
||||
NSAccessibilityPostNotificationWithUserInfo (element, name, info);
|
||||
});
|
||||
@@ -7571,16 +7592,22 @@ ns_ax_post_notification_with_info (id element,
|
||||
|
||||
- (id)accessibilityParent
|
||||
{
|
||||
+ if (!self.emacsView)
|
||||
+ return nil;
|
||||
return NSAccessibilityUnignoredAncestor (self.emacsView);
|
||||
}
|
||||
|
||||
- (id)accessibilityWindow
|
||||
{
|
||||
+ if (!self.emacsView)
|
||||
+ return nil;
|
||||
return [self.emacsView window];
|
||||
}
|
||||
|
||||
- (id)accessibilityTopLevelUIElement
|
||||
{
|
||||
+ if (!self.emacsView)
|
||||
+ return nil;
|
||||
return [self.emacsView window];
|
||||
}
|
||||
|
||||
@@ -8143,7 +8170,7 @@ ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem,
|
||||
return result;
|
||||
}
|
||||
[self ensureTextCache];
|
||||
- return cachedText ? cachedText : @"";
|
||||
+ return cachedText ? [[cachedText retain] autorelease] : @"";
|
||||
}
|
||||
|
||||
- (NSInteger)accessibilityNumberOfCharacters
|
||||
@@ -9659,6 +9686,15 @@ ns_ax_scan_interactive_spans (struct window *w,
|
||||
[layer release];
|
||||
#endif
|
||||
|
||||
+ /* Nil out back-references before releasing elements. Queued
|
||||
+ dispatch_async blocks may still hold a retained reference to
|
||||
+ an element; without this they would access a dangling
|
||||
+ emacsView pointer after EmacsView is freed. */
|
||||
+ for (id elem in accessibilityElements)
|
||||
+ {
|
||||
+ if ([elem respondsToSelector:@selector (setEmacsView:)])
|
||||
+ [elem setEmacsView:nil];
|
||||
+ }
|
||||
[accessibilityElements release];
|
||||
[[self menu] release];
|
||||
[super dealloc];
|
||||
--
|
||||
2.43.0
|
||||
|
||||
Reference in New Issue
Block a user