aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2025-10-27 15:54:10 +0200
committerEli Zaretskii2025-10-27 15:54:10 +0200
commit23d863357920d283b899fd3757ccfa387a95ffe6 (patch)
treee35ab4c448f9fc0488714c770551c3c512dea58d /src
parent42dab7e7855348abf2665acabddf737c3aec5de6 (diff)
downloademacs-23d863357920d283b899fd3757ccfa387a95ffe6.tar.gz
emacs-23d863357920d283b899fd3757ccfa387a95ffe6.zip
Avoid face inheritance cycles
* src/xfaces.c (face_inheritance_cycle): New function. (Finternal_set_lisp_face_attribute): Signal an error if the ':inherit' attribute of a face is modified in a way that will cause it to inherit from itself. (Bug#79672) * test/src/xfaces-tests.el (xfaces-test-circular-inheritance): New test. * etc/NEWS: Announce the incompatible change.
Diffstat (limited to 'src')
-rw-r--r--src/xfaces.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/src/xfaces.c b/src/xfaces.c
index 7626dfeb75c..ca1bee1d17a 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -2426,6 +2426,60 @@ face_inherited_attr (struct window *w, struct frame *f,
2426 return attr_val; 2426 return attr_val;
2427} 2427}
2428 2428
2429/* Chase the chain of inheritance for FACE on frame F, and return
2430 non-zero if FACE inherits from its CHILD face, directly or
2431 indirectly. FACE is either a symbol or a list of face symbols, which
2432 are two forms of values for the :inherit attribute of a face. CHILD
2433 must be a face symbol. */
2434static bool
2435face_inheritance_cycle (struct frame *f, Lisp_Object face, Lisp_Object child)
2436{
2437 Lisp_Object face_attrs[LFACE_VECTOR_SIZE];
2438 Lisp_Object parent_face;
2439 bool ok, cycle_found = false;
2440
2441 eassert (SYMBOLP (child));
2442 if (CONSP (face))
2443 {
2444 Lisp_Object tail;
2445 for (tail = face; !NILP (tail); tail = XCDR (tail))
2446 {
2447 ok = get_lface_attributes (NULL, f, XCAR (tail), face_attrs,
2448 false, NULL);
2449 if (!ok)
2450 break;
2451 parent_face = face_attrs[LFACE_INHERIT_INDEX];
2452 if (EQ (parent_face, child))
2453 cycle_found = true;
2454 else if (!NILP (parent_face)
2455 && !UNSPECIFIEDP (parent_face)
2456 && !IGNORE_DEFFACE_P (parent_face)
2457 && !RESET_P (parent_face))
2458 cycle_found = face_inheritance_cycle (f, parent_face, child);
2459 if (cycle_found)
2460 break;
2461 }
2462 }
2463 else
2464 {
2465 eassert (SYMBOLP (face));
2466 ok = get_lface_attributes (NULL, f, face, face_attrs, false, NULL);
2467 if (ok)
2468 {
2469 parent_face = face_attrs[LFACE_INHERIT_INDEX];
2470 if (EQ (parent_face, child))
2471 cycle_found = true;
2472 else if (!NILP (parent_face)
2473 && !UNSPECIFIEDP (parent_face)
2474 && !IGNORE_DEFFACE_P (parent_face)
2475 && !RESET_P (parent_face))
2476 cycle_found = face_inheritance_cycle (f, parent_face, child);
2477 }
2478 }
2479
2480 return cycle_found;
2481}
2482
2429/* Merge the named face FACE_NAME on frame F, into the vector of face 2483/* Merge the named face FACE_NAME on frame F, into the vector of face
2430 attributes TO. Use NAMED_MERGE_POINTS to detect loops in face 2484 attributes TO. Use NAMED_MERGE_POINTS to detect loops in face
2431 inheritance. Return true if FACE_NAME is a valid face name and 2485 inheritance. Return true if FACE_NAME is a valid face name and
@@ -3654,7 +3708,9 @@ FRAME 0 means change the face on all frames, and change the default
3654 for (tail = value; CONSP (tail); tail = XCDR (tail)) 3708 for (tail = value; CONSP (tail); tail = XCDR (tail))
3655 if (!SYMBOLP (XCAR (tail))) 3709 if (!SYMBOLP (XCAR (tail)))
3656 break; 3710 break;
3657 if (NILP (tail)) 3711 if (face_inheritance_cycle (f, value, face))
3712 signal_error ("Face inheritance results in inheritance cycle", value);
3713 else if (NILP (tail))
3658 ASET (lface, LFACE_INHERIT_INDEX, value); 3714 ASET (lface, LFACE_INHERIT_INDEX, value);
3659 else 3715 else
3660 signal_error ("Invalid face inheritance", value); 3716 signal_error ("Invalid face inheritance", value);