GNU bug report logs -
#75520
Circular code or data can hang Emacs unquittably
Previous Next
Full log
View this message in rfc822 format
When evaluated in -Q, this code:
(funcall '(lambda () . #1=(t . #1#)))
causes an unquittable infloop.
IMHO, circular code isn't something we should support in any meaningful
way: it's perfectly okay for it to have unexpected results, and throw
any error message we can think of, or none, until I hit quit. However,
I do think the loops should be quittable.
The easiest way to ensure this is to move the maybe_quit call in
eval_sub to the top of the function. I mentioned this problem to Paul
Eggert and he provided the patch below, which also fixes two other cases
I'd overlooked.
There are similar issues with circular data: if Lisp code turns
process-environment into a circular structure, for example, call_process
will hang Emacs. If this should be fixed, please let me know so I can
create a separate bug report and look for similar issues.
From a2015ba2f81c67b1a77054f0715ba3d643504a98 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert <at> cs.ucla.edu>
Date: Sun, 5 Jan 2025 17:30:18 -0800
Subject: [PATCH] Some maybe_quit fixes in eval.c
* src/eval.c (skip_debugger):
Use FOR_EACH_TAIL to avoid unquittable infloops.
(eval_sub): Call maybe_quit earlier.
(funcall_lambda): Use FOR_EACH_TAIL rather than calling
maybe_quit each time through the loop.
---
src/eval.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/src/eval.c b/src/eval.c
index 3e899db4436..2fa60af90af 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2044,35 +2044,36 @@ wants_debugger (Lisp_Object list, Lisp_Object conditions)
static bool
skip_debugger (Lisp_Object conditions, Lisp_Object data)
{
- Lisp_Object tail;
- bool first_string = 1;
+ Lisp_Object tail = Vdebug_ignored_errors;
+ bool first_string = true;
Lisp_Object error_message;
error_message = Qnil;
- for (tail = Vdebug_ignored_errors; CONSP (tail); tail = XCDR (tail))
+
+ FOR_EACH_TAIL (tail)
{
if (STRINGP (XCAR (tail)))
{
if (first_string)
{
error_message = Ferror_message_string (data);
- first_string = 0;
+ first_string = false;
}
if (fast_string_match (XCAR (tail), error_message) >= 0)
- return 1;
+ return true;
}
else
{
- Lisp_Object contail;
+ Lisp_Object contail = conditions;
- for (contail = conditions; CONSP (contail); contail = XCDR (contail))
+ FOR_EACH_TAIL (contail)
if (EQ (XCAR (tail), XCAR (contail)))
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
/* Say whether SIGNAL is a `quit' error (or inherits from it). */
@@ -2470,6 +2471,11 @@ grow_specpdl_allocation (void)
Lisp_Object
eval_sub (Lisp_Object form)
{
+ /* Call maybe_quit now, rather than just before calling maybe_gc, so
+ that callers like Fand, Fprogn and Fsetq need not call maybe_quit
+ each time through their loops. */
+ maybe_quit ();
+
if (SYMBOLP (form))
{
/* Look up its binding in the lexical environment.
@@ -2483,8 +2489,6 @@ eval_sub (Lisp_Object form)
if (!CONSP (form))
return form;
- maybe_quit ();
-
maybe_gc ();
if (++lisp_eval_depth > max_lisp_eval_depth)
@@ -3262,10 +3266,8 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, Lisp_Object *arg_vector)
bool optional = false;
bool rest = false;
bool previous_rest = false;
- for (; CONSP (syms_left); syms_left = XCDR (syms_left))
+ FOR_EACH_TAIL (syms_left)
{
- maybe_quit ();
-
Lisp_Object next = maybe_remove_pos_from_symbol (XCAR (syms_left));
if (!BARE_SYMBOL_P (next))
xsignal1 (Qinvalid_function, fun);
--
2.45.2
This bug report was last modified 151 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.