[PATCH] Prevent a crash if the ASCII charset registries match nothing

Aidan Kehoe kehoea
Sat Nov 11 08:14:24 EST 2006


 Ar an deichi? l? de m? na Samhain, scr?obh stephen at xemacs.org: 

 >  > Not "*", rather "*really broken-registry and charset", after someone
 >  > had done:
 >  > 
 >  >   (set-charset-registries 'ascii ["really broken-registry and charset"])
 > 
 > Hey, if users want to do that, they can live with it.  We should
 > defend against server waywardness, not against users pointing a .44 at
 > their kneecap.

Eh, still, XEmacs shouldn?t be crashable from Lisp. The below has a bit more
testing, with X11 and GTK; I intend committing it this evening.

SUPERSEDES 17746.1739.273694.339710 at parhasard.net

src/ChangeLog addition:

2006-11-11  Aidan Kehoe  <kehoea at parhasard.net>

	* charset.h:
	* mule-charset.c (set_charset_registries):
	Provide a C-accessible version of set-charset-registries that
	doesn't error. Called from x_find_charset_font. 

	* faces.c (ensure_face_cachel_contains_charset):
	Correct my spelling. 
	
	* faces.c (update_EmacsFrame):
	Don't update the frame if it isn't live. 
	
	* faces.h:
	Add some documentation on FACE_FONT. 

	* frame-gtk.c (gtk_update_frame_external_traits):
	* frame-x.c (x_update_frame_external_traits):
	In the event that FACE_FONT has deleted the frame, don't
	manipulate it further in update_frame_external_traits.

	* mule-charset.c:

	* mule-charset.c (Fset_charset_registries):
	Don't allow XLFD wildcards in charset registries. Call the
	factored-out C-callable version to 

	* objects-gtk.c:
	#include "charset.h"

	* objects-xlike-inc.c (x_find_charset_font,
	gtk_find_charset_font): In the event that the charset is ASCII and
	we haven't matched anything up to now, even with a pattern of "*",
	add "iso8859-1" to the charset's registry and try again.
	
	* window.c (window_pixel_width_to_char_width):
	The default width of a face may be zero; only divide by it if it's
	nonzero. 
	

XEmacs Trunk source patch:
Diff command:   cvs -q diff -Nu
Files affected: src/window.c
===================================================================
RCS src/objects-xlike-inc.c
===================================================================
RCS src/objects-gtk.c
===================================================================
RCS src/mule-charset.c
===================================================================
RCS src/frame-x.c
===================================================================
RCS src/frame-gtk.c
===================================================================
RCS src/faces.h
===================================================================
RCS src/faces.c
===================================================================
RCS src/charset.h
===================================================================
RCS

Index: src/charset.h
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/charset.h,v
retrieving revision 1.15
diff -u -u -r1.15 charset.h
--- src/charset.h	2006/11/05 22:31:43	1.15
+++ src/charset.h	2006/11/11 12:31:00
@@ -574,6 +574,8 @@
 			  int USED_IF_MULE (l), unsigned_char_dynarr *dst,
 			  enum unicode_type type, unsigned int little_endian);
 
+void set_charset_registries(Lisp_Object charset, Lisp_Object registries);
+
 EXFUN (Funicode_to_char, 2);
 EXFUN (Fchar_to_unicode, 1); 
 
Index: src/faces.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/faces.c,v
retrieving revision 1.50
diff -u -u -r1.50 faces.c
--- src/faces.c	2006/11/05 22:31:43	1.50
+++ src/faces.c	2006/11/11 12:31:08
@@ -1162,7 +1162,7 @@
     /* Lookup the face again, this time allowing the fallback. If this
        succeeds, it'll give a font intended for the script in question,
        which is preferable to translating to ISO10646-1 and using the
-       fixed-with fallback.  */
+       fixed-width fallback.  */
     new_val = face_property_matching_instance (face, Qfont,
 					       charset, domain,
 					       ERROR_ME_DEBUG_WARN, 0,
@@ -1840,6 +1840,9 @@
 update_EmacsFrame (Lisp_Object frame, Lisp_Object name)
 {
   struct frame *frm = XFRAME (frame);
+
+  if (!FRAME_LIVE_P(frm))
+    return;
 
   if (EQ (name, Qfont))
     MARK_FRAME_SIZE_SLIPPED (frm);
Index: src/faces.h
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/faces.h,v
retrieving revision 1.18
diff -u -u -r1.18 faces.h
--- src/faces.h	2006/11/05 22:31:43	1.18
+++ src/faces.h	2006/11/11 12:31:11
@@ -386,6 +386,10 @@
   FACE_PROPERTY_INSTANCE (face, Qforeground, domain, 0, Qzero)
 #define FACE_BACKGROUND(face, domain)					\
   FACE_PROPERTY_INSTANCE (face, Qbackground, domain, 0, Qzero)
+
+/* Calling this function on the default face with the ASCII character set
+   may delete any X11 frames; see the code at the end of
+   x_find_charset_font. */
 #define FACE_FONT(face, domain, charset)				\
   face_property_matching_instance (face, Qfont, charset, domain,	\
 				   ERROR_ME_DEBUG_WARN, 0, Qzero,	\
Index: src/frame-gtk.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/frame-gtk.c,v
retrieving revision 1.22
diff -u -u -r1.22 frame-gtk.c
--- src/frame-gtk.c	2005/11/25 01:42:02	1.22
+++ src/frame-gtk.c	2006/11/11 12:31:15
@@ -1430,6 +1430,17 @@
    {
      Lisp_Object font = FACE_FONT (Vdefault_face, frame, Vcharset_ascii);
 
+     /* It may be that instantiating the font has deleted the frame (will
+	happen if the user has specified a charset registry for ASCII that
+	isn't available on the server, and our fallback of iso8859-1 isn't
+	available; something vanishingly rare.) In that case, return from
+	this function. */
+
+     if (!FRAME_LIVE_P(frm))
+       {
+	 return;
+       }
+
      if (!EQ (font, Vthe_null_font_instance))
      {
 	 /* #### BILL!!! The X code set the XtNfont property of the
Index: src/frame-x.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/frame-x.c,v
retrieving revision 1.75
diff -u -u -r1.75 frame-x.c
--- src/frame-x.c	2006/06/19 18:49:23	1.75
+++ src/frame-x.c	2006/11/11 12:31:23
@@ -2734,6 +2734,17 @@
    {
      Lisp_Object font = FACE_FONT (Vdefault_face, frame, Vcharset_ascii);
 
+     /* It may be that instantiating the font has deleted the frame (will
+	happen if the user has specified a charset registry for ASCII that
+	isn't available on the server, and our fallback of iso8859-1 isn't
+	available; something vanishingly rare.) In that case, return from
+	this function without further manipulation of the dead frame. */
+
+     if (!FRAME_LIVE_P(frm))
+       {
+	 return;
+       }
+
      /* #### what to do about Xft?  I don't think the font is actually used
 	to compute cell size for computing frame pixel dimensions (see call
 	to EmacsFrameRecomputeCellSize() below); where is it used? -- sjt
Index: src/mule-charset.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/mule-charset.c,v
retrieving revision 1.50
diff -u -u -r1.50 mule-charset.c
--- src/mule-charset.c	2006/11/07 14:04:56	1.50
+++ src/mule-charset.c	2006/11/11 12:31:25
@@ -883,6 +883,14 @@
   return Qnil;
 }
 
+void
+set_charset_registries(Lisp_Object charset, Lisp_Object registries)
+{
+  XCHARSET_REGISTRIES (charset) = registries;
+  invalidate_charset_font_caches (charset);
+  face_property_was_changed (Vdefault_face, Qfont, Qglobal);
+}
+
 DEFUN ("set-charset-registries", Fset_charset_registries, 2, 2, 0, /*
 Set the `registries' property of CHARSET to REGISTRIES.
 
@@ -913,11 +921,19 @@
 	  invalid_argument("Not an X11 REGISTRY-ENCODING combination", 
 			   XVECTOR_DATA(registries)[i]);
 	}
+
+      if (qxestrchr(XSTRING_DATA(XVECTOR_DATA(registries)[i]), '*') ||
+	  qxestrchr(XSTRING_DATA(XVECTOR_DATA(registries)[i]), '?'))
+	{
+	  invalid_argument
+	    ("XLFD wildcards not allowed in charset-registries", 
+	     XVECTOR_DATA(registries)[i]);
+
+	}
     }
 
-  XCHARSET_REGISTRIES (charset) = registries;
-  invalidate_charset_font_caches (charset);
-  face_property_was_changed (Vdefault_face, Qfont, Qglobal);
+  set_charset_registries(charset, registries);
+
   return Qnil;
 }
 
Index: src/objects-gtk.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/objects-gtk.c,v
retrieving revision 1.18
diff -u -u -r1.18 objects-gtk.c
--- src/objects-gtk.c	2006/11/05 22:31:44	1.18
+++ src/objects-gtk.c	2006/11/11 12:31:28
@@ -31,6 +31,7 @@
 #include "lisp.h"
 
 #include "buffer.h"
+#include "charset.h"
 #include "device-impl.h"
 #include "insdel.h"
 
Index: src/objects-xlike-inc.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/objects-xlike-inc.c,v
retrieving revision 1.3
diff -u -u -r1.3 objects-xlike-inc.c
--- src/objects-xlike-inc.c	2006/11/05 22:31:45	1.3
+++ src/objects-xlike-inc.c	2006/11/11 12:31:29
@@ -764,6 +764,92 @@
 					    charset, stage);
     }
 
+  /* In the event that the charset is ASCII and we haven't matched
+     anything up to now, even with a pattern of "*", add "iso8859-1"
+     to the charset's registry and try again. Not returning a result
+     for ASCII means our frame geometry calculations are
+     inconsistent, and that we may crash. */
+
+  if (1 == xlfd_length && EQ(charset, Vcharset_ascii) && NILP(result)
+      && ('*' == eigetch(ei_xlfd_without_registry, 0)))
+
+    {
+      int have_latin1 = 0;
+
+      /* Set this to, for example, is08859-1 if you want to see the
+	 error behaviour. */
+
+#define FALLBACK_ASCII_REGISTRY "iso8859-1" 
+
+      for (j = 0; j < registries_len; ++j)
+	{
+	  if (0 == qxestrcasecmp(XSTRING_DATA(XVECTOR_DATA(registries)[j]),
+				 FALLBACK_ASCII_REGISTRY))
+	    {
+	      have_latin1 = 1;
+	      break;
+	    }
+	}
+
+      if (!have_latin1)
+	{
+	  Lisp_Object new_registries = make_vector(registries_len + 1, Qnil);
+
+	  warn_when_safe (Qface, Qwarning,
+			  "Your ASCII charset registries contain  nothing "
+			  "sensible.  Adding `" FALLBACK_ASCII_REGISTRY "'.");
+
+	  XVECTOR_DATA(new_registries)[0]
+	    = build_string(FALLBACK_ASCII_REGISTRY);
+
+	  memcpy(XVECTOR_DATA(new_registries) + 1,
+		 XVECTOR_DATA(registries),
+		 sizeof XVECTOR_DATA(registries)[0] * 
+		 XVECTOR_LENGTH(registries));
+
+	  /* Calling set_charset_registries instead of overwriting the
+	     value directly, to allow the charset font caches to be
+	     invalidated and a change to the default face to be
+	     noted.  */
+	  set_charset_registries(charset, new_registries);
+
+	  /* And recurse. */
+	  result = 
+	    DEVMETH_OR_GIVEN (XDEVICE (device), find_charset_font,
+			      (device, font, charset, stage),
+			      result);
+	}
+      else
+	{
+	  DECLARE_EISTRING (ei_connection_name);
+
+	  /* We preserve a copy of the connection name for the error message
+	     after the device is deleted. */
+	  eicpy_lstr (ei_connection_name, 
+		      DEVICE_CONNECTION (XDEVICE(device)));
+
+	  stderr_out ("Cannot find a font for ASCII, deleting device on %s\n",
+		      eidata (ei_connection_name));
+
+	  io_error_delete_device (device);
+
+	  /* Do a normal warning in the event that we have other, non-X
+	     frames available. (If we don't, io_error_delete_device will
+	     have exited.) */
+	  warn_when_safe 
+	    (Qface, Qerror,
+	     "Cannot find a font for ASCII, deleting device on %s.\n"
+	     "\n"
+	     "Your X server fonts appear to be inconsistent; fix them, or\n"
+	     "the next frame you create on that DISPLAY will crash this\n"
+	     "XEmacs.   At a minimum, provide one font with an XLFD ending\n"
+	     "in `" FALLBACK_ASCII_REGISTRY "', so we can work out what size\n"
+	     "a frame should be. ",
+	     eidata (ei_connection_name));
+	}
+
+    }
+
   /* This function used to return the font spec, in the case where a font
      didn't exist on the X server but it did match the charset. We're not
      doing that any more, because none of the other platform code does, and
Index: src/window.c
===================================================================
RCS file: /pack/xemacscvs/XEmacs/xemacs/src/window.c,v
retrieving revision 1.92
diff -u -u -r1.92 window.c
--- src/window.c	2006/06/21 17:30:37	1.92
+++ src/window.c	2006/11/11 12:31:40
@@ -4250,7 +4250,7 @@
 				  int include_margins_p)
 {
   int avail_width;
-  int char_width;
+  int char_width = 0;
   int defheight, defwidth;
   Lisp_Object window = wrap_window (w);
 
@@ -4263,7 +4263,8 @@
 
   default_face_height_and_width (window, &defheight, &defwidth);
 
-  char_width = (avail_width / defwidth);
+  if (defwidth) 
+    char_width = (avail_width / defwidth);
 
   /* It's the calling function's responsibility to check these values
      and make sure they're not out of range.

-- 
Santa Maradona, priez pour moi!



More information about the XEmacs-Beta mailing list