From 5cd7785b0a042f48823dd0f38fac4d3b2e7b3d9c Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 24 May 2026 08:06:46 +0000 Subject: [PATCH 1/4] Fix use-after-free in Ffuncall_with_delayed_message (bug#81108) * src/eval.c (with_delayed_message_display): (with_delayed_message_cancel): (Ffuncall_with_delayed_message): Use new temporary data structure. Cancel timer at most once. --- src/eval.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/eval.c b/src/eval.c index b61bda4a024..bd3b119107b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1220,17 +1220,34 @@ usage: (while TEST BODY...) */) return Qnil; } +struct funcall_with_delayed_message_data +{ + Lisp_Object *message; + struct atimer *timer; +}; + static void with_delayed_message_display (struct atimer *timer) { - message3 (build_string (timer->client_data)); + struct funcall_with_delayed_message_data *data + = timer->client_data; + if (data->timer) + { + message3 (*data->message); + data->timer = NULL; + } } static void -with_delayed_message_cancel (void *timer) +with_delayed_message_cancel (void *datap) { - xfree (((struct atimer *) timer)->client_data); - cancel_atimer (timer); + struct funcall_with_delayed_message_data *data + = datap; + if (data->timer) + { + cancel_atimer (data->timer); + data->timer = NULL; + } } DEFUN ("funcall-with-delayed-message", @@ -1251,10 +1268,12 @@ is not displayed. */) /* Set up the atimer. */ struct timespec interval = dtotimespec (XFLOATINT (timeout)); - struct atimer *timer = start_atimer (ATIMER_RELATIVE, interval, - with_delayed_message_display, - xstrdup (SSDATA (message))); - record_unwind_protect_ptr (with_delayed_message_cancel, timer); + struct funcall_with_delayed_message_data data + = { .message = &message }; + data.timer = start_atimer (ATIMER_RELATIVE, interval, + with_delayed_message_display, + &data); + record_unwind_protect_ptr (with_delayed_message_cancel, &data); Lisp_Object result = calln (function); From 90314895ddcdb565e638d4bea0f05e0c4d432671 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sun, 24 May 2026 08:17:33 +0000 Subject: [PATCH 2/4] Don't cancel random timers in x_get_foreign_selection (bug#81108) * src/pgtkselect.c (pgtk_display_selection_waiting_message): (pgtk_cancel_atimer): (pgtk_get_foreign_selection): * src/xselect.c (x_display_selection_waiting_message): (x_cancel_atimer): (x_get_foreign_selection): Use a pointer to a timer variable, which is cleared when the timer runs or is otherwise cancelled. Don't cancel the timer twice. --- src/pgtkselect.c | 15 +++++++++++---- src/xselect.c | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/pgtkselect.c b/src/pgtkselect.c index 425da3b8fd4..49569046caa 100644 --- a/src/pgtkselect.c +++ b/src/pgtkselect.c @@ -981,15 +981,22 @@ static void pgtk_display_selection_waiting_message (struct atimer *timer) { Lisp_Object val; + struct atimer **atimerp = timer->client_data; val = build_string ("Waiting for reply from selection owner..."); message3_nolog (val); + *atimerp = NULL; } static void -pgtk_cancel_atimer (void *atimer) +pgtk_cancel_atimer (void *atimerp) { - cancel_atimer (atimer); + struct atimer **atimer = atimerp; + if (*atimer) + { + cancel_atimer (*atimer); + *atimer = NULL; + } } @@ -1044,8 +1051,8 @@ pgtk_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_typ message_interval = make_timespec (1, 0); delayed_message = start_atimer (ATIMER_RELATIVE, message_interval, pgtk_display_selection_waiting_message, - NULL); - record_unwind_protect_ptr (pgtk_cancel_atimer, delayed_message); + &delayed_message); + record_unwind_protect_ptr (pgtk_cancel_atimer, &delayed_message); /* This allows quits. Also, don't wait forever. */ intmax_t timeout = max (0, pgtk_selection_timeout); diff --git a/src/xselect.c b/src/xselect.c index 93057c2d6c5..4c7a95fb945 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -1624,15 +1624,22 @@ static void x_display_selection_waiting_message (struct atimer *timer) { Lisp_Object val; + struct atimer **atimerp = timer->client_data; val = build_string ("Waiting for reply from selection owner..."); message3_nolog (val); + *atimerp = NULL; } static void -x_cancel_atimer (void *atimer) +x_cancel_atimer (void *atimerp) { - cancel_atimer (atimer); + struct atimer **atimer = atimerp; + if (*atimer) + { + cancel_atimer (*atimer); + *atimer = NULL; + } } @@ -1701,8 +1708,8 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, message_interval = make_timespec (1, 0); delayed_message = start_atimer (ATIMER_RELATIVE, message_interval, x_display_selection_waiting_message, - NULL); - record_unwind_protect_ptr (x_cancel_atimer, delayed_message); + &delayed_message); + record_unwind_protect_ptr (x_cancel_atimer, &delayed_message); /* This allows quits. Also, don't wait forever. */ intmax_t timeout = max (0, x_selection_timeout); From 3106dc7766778ceb2462531ee0be3e13693e6cb5 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Sat, 6 Jun 2026 10:14:47 +0000 Subject: [PATCH 3/4] Assert we don't double-free timers (bug#81108) * src/atimer.c (cancel_atimer): Assert that we found the timer. --- src/atimer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/atimer.c b/src/atimer.c index c205f658d74..c87b93697b5 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -205,6 +205,9 @@ cancel_atimer (struct atimer *timer) } } + /* We shouldn't be called with timers which aren't on either list. */ + eassert (i != 2); + unblock_atimers (&oldset); } From df2508a8f61dc084071f0071cc3933bcf901d887 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 7 Jun 2026 09:52:30 +0300 Subject: [PATCH 4/4] Remove from CC Mode code that modifies 'major-mode-remap-defaults' * lisp/progmodes/cc-mode.el: Remove code that adds to 'major-mode-remap-defaults', as enabling and disabling tree-sitter based modes now goes through 'treesit-enabled-modes'. --- lisp/progmodes/cc-mode.el | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 6eed5b53c19..f930d2d34f3 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -3401,22 +3401,6 @@ Key bindings: (insert (format "Buffer Style: %s\nc-emacs-features: %s\n" style c-features))))))) - -;; Make entries in `major-mode-remap-defaults' to ensure that when CC -;; Mode has been loaded, the symbols `c-mode' etc., will call CC Mode's -;; modes rather than c-ts-mode etc.. -(when (boundp 'major-mode-remap-defaults) - (add-to-list 'major-mode-remap-defaults '(c++-mode . c++-ts-mode)) - (add-to-list 'major-mode-remap-defaults '(c-mode . c-ts-mode)) - (add-to-list 'major-mode-remap-defaults '(c-or-c++-mode . c-or-c++-ts-mode)) - (let (entry) - (dolist (mode '(c-mode c++-mode c-or-c++-mode)) - (if (and (setq entry (assq mode major-mode-remap-defaults)) - (null (cdr entry))) - (setq major-mode-remap-defaults - (delq entry major-mode-remap-defaults))) - (push (cons mode nil) major-mode-remap-defaults)))) - (cc-provide 'cc-mode)