aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPhilipp Stephani2025-01-30 16:12:49 +0100
committerPhilipp Stephani2025-02-28 01:45:35 +0100
commit32da093e524d5e28945557701f7c50d7c4a898cd (patch)
tree00275d27c38ef719d99b03b4ccb68023fae71571 /src
parentea715b0183f6a19d491cad36eb18c2c9cf0f0dd3 (diff)
downloademacs-32da093e524d5e28945557701f7c50d7c4a898cd.tar.gz
emacs-32da093e524d5e28945557701f7c50d7c4a898cd.zip
Don't overwrite non-local exit symbol and data (Bug#65796).
The previous approach would incorrectly invalidate the returned module values if another non-local exit occurred while dealing with a non-local exit. See Bug#65796. Instead, allocate the values from the usual environment storage, and return statically-allocated objects if that fails. * src/emacs-module.c (struct emacs_env_private): Turn non-local exit symbol and data into normal Lisp objects. (initialize_environment): Initialize them. (mark_module_environment): Prevent them from being garbage-collected. (module_signal_or_throw, module_non_local_exit_signal_1) (module_non_local_exit_throw_1): Adapt uses. (value_to_lisp): No longer scan for them with module assertions enabled. (module_out_of_memory_signal, module_out_of_memory_data): New statically-allocated module values to return in case of allocation failure. (syms_of_module): Initialize them. (module_non_local_exit_get): Allocate module values normally. If that fails, return statically-allocated values. * doc/lispref/internals.texi (Module Nonlocal): Document new behavior.
Diffstat (limited to 'src')
-rw-r--r--src/emacs-module.c63
1 files changed, 43 insertions, 20 deletions
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 0a67433ec70..ab6b900df8d 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -167,7 +167,7 @@ struct emacs_env_private
167 /* Dedicated storage for non-local exit symbol and data so that 167 /* Dedicated storage for non-local exit symbol and data so that
168 storage is always available for them, even in an out-of-memory 168 storage is always available for them, even in an out-of-memory
169 situation. */ 169 situation. */
170 struct emacs_value_tag non_local_exit_symbol, non_local_exit_data; 170 Lisp_Object non_local_exit_symbol, non_local_exit_data;
171 171
172 struct emacs_value_storage storage; 172 struct emacs_value_storage storage;
173}; 173};
@@ -500,6 +500,9 @@ module_non_local_exit_clear (emacs_env *env)
500 env->private_members->pending_non_local_exit = emacs_funcall_exit_return; 500 env->private_members->pending_non_local_exit = emacs_funcall_exit_return;
501} 501}
502 502
503static struct emacs_value_tag module_out_of_memory_symbol;
504static struct emacs_value_tag module_out_of_memory_data;
505
503static enum emacs_funcall_exit 506static enum emacs_funcall_exit
504module_non_local_exit_get (emacs_env *env, 507module_non_local_exit_get (emacs_env *env,
505 emacs_value *symbol, emacs_value *data) 508 emacs_value *symbol, emacs_value *data)
@@ -507,12 +510,23 @@ module_non_local_exit_get (emacs_env *env,
507 module_assert_thread (); 510 module_assert_thread ();
508 module_assert_env (env); 511 module_assert_env (env);
509 struct emacs_env_private *p = env->private_members; 512 struct emacs_env_private *p = env->private_members;
510 if (p->pending_non_local_exit != emacs_funcall_exit_return) 513 enum emacs_funcall_exit ret = p->pending_non_local_exit;
514 if (ret != emacs_funcall_exit_return)
511 { 515 {
512 *symbol = &p->non_local_exit_symbol; 516 emacs_value sym
513 *data = &p->non_local_exit_data; 517 = allocate_emacs_value (env, p->non_local_exit_symbol);
518 emacs_value dat
519 = allocate_emacs_value (env, p->non_local_exit_data);
520 if (sym == NULL || dat == NULL)
521 {
522 sym = &module_out_of_memory_symbol;
523 dat = &module_out_of_memory_data;
524 ret = emacs_funcall_exit_signal;
525 }
526 *symbol = sym;
527 *data = dat;
514 } 528 }
515 return p->pending_non_local_exit; 529 return ret;
516} 530}
517 531
518/* Like for `signal', DATA must be a list. */ 532/* Like for `signal', DATA must be a list. */
@@ -1185,11 +1199,11 @@ module_signal_or_throw (struct emacs_env_private *env)
1185 case emacs_funcall_exit_return: 1199 case emacs_funcall_exit_return:
1186 return; 1200 return;
1187 case emacs_funcall_exit_signal: 1201 case emacs_funcall_exit_signal:
1188 xsignal (value_to_lisp (&env->non_local_exit_symbol), 1202 xsignal (env->non_local_exit_symbol,
1189 value_to_lisp (&env->non_local_exit_data)); 1203 env->non_local_exit_data);
1190 case emacs_funcall_exit_throw: 1204 case emacs_funcall_exit_throw:
1191 Fthrow (value_to_lisp (&env->non_local_exit_symbol), 1205 Fthrow (env->non_local_exit_symbol,
1192 value_to_lisp (&env->non_local_exit_data)); 1206 env->non_local_exit_data);
1193 default: 1207 default:
1194 eassume (false); 1208 eassume (false);
1195 } 1209 }
@@ -1389,8 +1403,8 @@ module_non_local_exit_signal_1 (emacs_env *env, Lisp_Object sym,
1389 if (p->pending_non_local_exit == emacs_funcall_exit_return) 1403 if (p->pending_non_local_exit == emacs_funcall_exit_return)
1390 { 1404 {
1391 p->pending_non_local_exit = emacs_funcall_exit_signal; 1405 p->pending_non_local_exit = emacs_funcall_exit_signal;
1392 p->non_local_exit_symbol.v = sym; 1406 p->non_local_exit_symbol = sym;
1393 p->non_local_exit_data.v = data; 1407 p->non_local_exit_data = data;
1394 } 1408 }
1395} 1409}
1396 1410
@@ -1402,8 +1416,8 @@ module_non_local_exit_throw_1 (emacs_env *env, Lisp_Object tag,
1402 if (p->pending_non_local_exit == emacs_funcall_exit_return) 1416 if (p->pending_non_local_exit == emacs_funcall_exit_return)
1403 { 1417 {
1404 p->pending_non_local_exit = emacs_funcall_exit_throw; 1418 p->pending_non_local_exit = emacs_funcall_exit_throw;
1405 p->non_local_exit_symbol.v = tag; 1419 p->non_local_exit_symbol = tag;
1406 p->non_local_exit_data.v = value; 1420 p->non_local_exit_data = value;
1407 } 1421 }
1408} 1422}
1409 1423
@@ -1439,13 +1453,6 @@ value_to_lisp (emacs_value v)
1439 { 1453 {
1440 const emacs_env *env = pdl->unwind_ptr.arg; 1454 const emacs_env *env = pdl->unwind_ptr.arg;
1441 struct emacs_env_private *priv = env->private_members; 1455 struct emacs_env_private *priv = env->private_members;
1442 /* The value might be one of the nonlocal exit values. Note
1443 that we don't check whether a nonlocal exit is currently
1444 pending, because the module might have cleared the flag
1445 in the meantime. */
1446 if (&priv->non_local_exit_symbol == v
1447 || &priv->non_local_exit_data == v)
1448 goto ok;
1449 if (value_storage_contains_p (&priv->storage, v, &num_values)) 1456 if (value_storage_contains_p (&priv->storage, v, &num_values))
1450 goto ok; 1457 goto ok;
1451 ++num_environments; 1458 ++num_environments;
@@ -1536,6 +1543,8 @@ mark_module_environment (void *ptr)
1536{ 1543{
1537 emacs_env *env = ptr; 1544 emacs_env *env = ptr;
1538 struct emacs_env_private *priv = env->private_members; 1545 struct emacs_env_private *priv = env->private_members;
1546 mark_object (priv->non_local_exit_symbol);
1547 mark_object (priv->non_local_exit_data);
1539 for (struct emacs_value_frame *frame = &priv->storage.initial; frame != NULL; 1548 for (struct emacs_value_frame *frame = &priv->storage.initial; frame != NULL;
1540 frame = frame->next) 1549 frame = frame->next)
1541 for (int i = 0; i < frame->offset; ++i) 1550 for (int i = 0; i < frame->offset; ++i)
@@ -1561,6 +1570,8 @@ initialize_environment (emacs_env *env, struct emacs_env_private *priv)
1561 } 1570 }
1562 1571
1563 priv->pending_non_local_exit = emacs_funcall_exit_return; 1572 priv->pending_non_local_exit = emacs_funcall_exit_return;
1573 priv->non_local_exit_symbol = Qnil;
1574 priv->non_local_exit_data = Qnil;
1564 initialize_storage (&priv->storage); 1575 initialize_storage (&priv->storage);
1565 env->size = sizeof *env; 1576 env->size = sizeof *env;
1566 env->private_members = priv; 1577 env->private_members = priv;
@@ -1711,6 +1722,18 @@ syms_of_module (void)
1711 Vmodule_refs_hash 1722 Vmodule_refs_hash
1712 = make_hash_table (&hashtest_eq, DEFAULT_HASH_SIZE, Weak_None); 1723 = make_hash_table (&hashtest_eq, DEFAULT_HASH_SIZE, Weak_None);
1713 1724
1725 DEFSYM (Qmodule_out_of_memory, "module-out-of-memory");
1726 Fput (Qmodule_out_of_memory, Qerror_conditions,
1727 list2 (Qmodule_out_of_memory, Qerror));
1728 Fput (Qmodule_out_of_memory, Qerror_message,
1729 build_unibyte_string ("Module out of memory"));
1730
1731 staticpro (&module_out_of_memory_symbol.v);
1732 module_out_of_memory_symbol.v = Qmodule_out_of_memory;
1733
1734 staticpro (&module_out_of_memory_data.v);
1735 module_out_of_memory_data.v = Qnil;
1736
1714 DEFSYM (Qmodule_load_failed, "module-load-failed"); 1737 DEFSYM (Qmodule_load_failed, "module-load-failed");
1715 Fput (Qmodule_load_failed, Qerror_conditions, 1738 Fput (Qmodule_load_failed, Qerror_conditions,
1716 list (Qmodule_load_failed, Qerror)); 1739 list (Qmodule_load_failed, Qerror));