Avoid buffer text relocations in calls to STRING_CHAR_* macros.
[bpt/emacs.git] / src / charset.c
index 29f98f2..d287fc0 100644 (file)
@@ -1,5 +1,5 @@
 /* Basic character set support.
-   Copyright (C) 2001-2011  Free Software Foundation, Inc.
+   Copyright (C) 2001-2012  Free Software Foundation, Inc.
    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
      2005, 2006, 2007, 2008, 2009, 2010, 2011
      National Institute of Advanced Industrial Science and Technology (AIST)
@@ -61,7 +61,7 @@ Lisp_Object Vcharset_hash_table;
 /* Table of struct charset.  */
 struct charset *charset_table;
 
-static int charset_table_size;
+static ptrdiff_t charset_table_size;
 static int charset_table_used;
 
 Lisp_Object Qcharsetp;
@@ -162,13 +162,13 @@ static struct
   /* 1 iff the following table is used for encoder.  */
   short for_encoder;
 
-  /* When the following table is used for encoding, mininum and
-     maxinum character of the current charset.  */
+  /* When the following table is used for encoding, minimum and
+     maximum character of the current charset.  */
   int min_char, max_char;
 
-  /* A Unicode character correspoinding to the code indice 0 (i.e. the
+  /* A Unicode character corresponding to the code index 0 (i.e. the
      minimum code-point) of the current charset, or -1 if the code
-     indice 0 is not a Unicode character.  This is checked when
+     index 0 is not a Unicode character.  This is checked when
      table.encoder[CHAR] is zero.  */
   int zero_index_char;
 
@@ -419,7 +419,7 @@ load_charset_map (struct charset *charset, struct charset_map_entries *entries,
    paying attention to comment character '#'.  */
 
 static inline unsigned
-read_hex (FILE *fp, int *eof)
+read_hex (FILE *fp, int *eof, int *overflow)
 {
   int c;
   unsigned n;
@@ -441,15 +441,16 @@ read_hex (FILE *fp, int *eof)
       *eof = 1;
       return 0;
     }
-  *eof = 0;
   n = 0;
-  if (c == 'x')
-    while ((c = getc (fp)) != EOF && isxdigit (c))
+  while (isxdigit (c = getc (fp)))
+    {
+      if (UINT_MAX >> 4 < n)
+       *overflow = 1;
       n = ((n << 4)
-          | (c <= '9' ? c - '0' : c <= 'F' ? c - 'A' + 10 : c - 'a' + 10));
-  else
-    while ((c = getc (fp)) != EOF && isdigit (c))
-      n = (n * 10) + c - '0';
+          | (c - ('0' <= c && c <= '9' ? '0'
+                  : 'A' <= c && c <= 'F' ? 'A' - 10
+                  : 'a' - 10)));
+    }
   if (c != EOF)
     ungetc (c, fp);
   return n;
@@ -479,7 +480,6 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co
   unsigned max_code = CHARSET_MAX_CODE (charset);
   int fd;
   FILE *fp;
-  int eof;
   Lisp_Object suffixes;
   struct charset_map_entries *head, *entries;
   int n_entries, count;
@@ -504,22 +504,27 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co
   memset (entries, 0, sizeof (struct charset_map_entries));
 
   n_entries = 0;
-  eof = 0;
   while (1)
     {
-      unsigned from, to;
-      int c;
+      unsigned from, to, c;
       int idx;
+      int eof = 0, overflow = 0;
 
-      from = read_hex (fp, &eof);
+      from = read_hex (fp, &eof, &overflow);
       if (eof)
        break;
       if (getc (fp) == '-')
-       to = read_hex (fp, &eof);
+       to = read_hex (fp, &eof, &overflow);
       else
        to = from;
-      c = (int) read_hex (fp, &eof);
+      if (eof)
+       break;
+      c = read_hex (fp, &eof, &overflow);
+      if (eof)
+       break;
 
+      if (overflow)
+       continue;
       if (from < min_code || to > max_code || from > to || c > MAX_CHAR)
        continue;
 
@@ -844,7 +849,7 @@ DEFUN ("define-charset-internal", Fdefine_charset_internal,
        Sdefine_charset_internal, charset_arg_max, MANY, 0,
        doc: /* For internal use only.
 usage: (define-charset-internal ...)  */)
-  (size_t nargs, Lisp_Object *args)
+  (ptrdiff_t nargs, Lisp_Object *args)
 {
   /* Charset attr vector.  */
   Lisp_Object attrs;
@@ -1145,13 +1150,25 @@ usage: (define-charset-internal ...)  */)
                                     hash_code);
       if (charset_table_used == charset_table_size)
        {
-         struct charset *new_table
-           = (struct charset *) xmalloc (sizeof (struct charset)
-                                         * (charset_table_size + 16));
-         memcpy (new_table, charset_table,
-                 sizeof (struct charset) * charset_table_size);
-         charset_table_size += 16;
+         /* Ensure that charset IDs fit into 'int' as well as into the
+            restriction imposed by fixnums.  Although the 'int' restriction
+            could be removed, too much other code would need altering; for
+            example, the IDs are stuffed into struct
+            coding_system.charbuf[i] entries, which are 'int'.  */
+         int old_size = charset_table_size;
+         struct charset *new_table =
+           xpalloc (0, &charset_table_size, 1,
+                    min (INT_MAX, MOST_POSITIVE_FIXNUM),
+                    sizeof *charset_table);
+         memcpy (new_table, charset_table, old_size * sizeof *new_table);
          charset_table = new_table;
+         /* FIXME: This leaks memory, as the old charset_table becomes
+            unreachable.  If the old charset table is charset_table_init
+            then this leak is intentional; otherwise, it's unclear.
+            If the latter memory leak is intentional, a
+            comment should be added to explain this.  If not, the old
+            charset_table should be freed, by passing it as the 1st argument
+            to xpalloc and removing the memcpy.  */
        }
       id = charset_table_used++;
       new_definition_p = 1;
@@ -1624,6 +1641,12 @@ maybe_unify_char (int c, Lisp_Object val)
     return c;
 
   CHECK_CHARSET_GET_CHARSET (val, charset);
+#ifdef REL_ALLOC
+  /* The call to load_charset below can allocate memory, whcih screws
+     callers of this function through STRING_CHAR_* macros that hold C
+     pointers to buffer text, if REL_ALLOC is used.  */
+  r_alloc_inhibit_buffer_relocation (1);
+#endif
   load_charset (charset, 1);
   if (! inhibit_load_charset_map)
     {
@@ -1639,11 +1662,14 @@ maybe_unify_char (int c, Lisp_Object val)
       if (unified > 0)
        c = unified;
     }
+#ifdef REL_ALLOC
+  r_alloc_inhibit_buffer_relocation (0);
+#endif
   return c;
 }
 
 
-/* Return a character correponding to the code-point CODE of
+/* Return a character corresponding to the code-point CODE of
    CHARSET.  */
 
 int
@@ -2065,7 +2091,7 @@ that case, find the charset from what supported by that coding system.  */)
 DEFUN ("charset-after", Fcharset_after, Scharset_after, 0, 1, 0,
        doc: /*
 Return charset of a character in the current buffer at position POS.
-If POS is nil, it defauls to the current point.
+If POS is nil, it defaults to the current point.
 If POS is out of range, the value is nil.  */)
   (Lisp_Object pos)
 {
@@ -2145,11 +2171,11 @@ DEFUN ("set-charset-priority", Fset_charset_priority, Sset_charset_priority,
        1, MANY, 0,
        doc: /* Assign higher priority to the charsets given as arguments.
 usage: (set-charset-priority &rest charsets)  */)
-  (size_t nargs, Lisp_Object *args)
+  (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object new_head, old_list, arglist[2];
   Lisp_Object list_2022, list_emacs_mule;
-  size_t i;
+  ptrdiff_t i;
   int id;
 
   old_list = Fcopy_sequence (Vcharset_ordered_list);
@@ -2210,14 +2236,16 @@ struct charset_sort_data
 {
   Lisp_Object charset;
   int id;
-  int priority;
+  ptrdiff_t priority;
 };
 
 static int
 charset_compare (const void *d1, const void *d2)
 {
   const struct charset_sort_data *data1 = d1, *data2 = d2;
-  return (data1->priority - data2->priority);
+  if (data1->priority != data2->priority)
+    return data1->priority < data2->priority ? -1 : 1;
+  return 0;
 }
 
 DEFUN ("sort-charsets", Fsort_charsets, Ssort_charsets, 1, 1, 0,
@@ -2227,7 +2255,8 @@ See also `charset-priority-list' and `set-charset-priority'.  */)
      (Lisp_Object charsets)
 {
   Lisp_Object len = Flength (charsets);
-  int n = XFASTINT (len), i, j, done;
+  ptrdiff_t n = XFASTINT (len), i, j;
+  int done;
   Lisp_Object tail, elt, attrs;
   struct charset_sort_data *sort_data;
   int id, min_id = INT_MAX, max_id = INT_MIN;
@@ -2235,7 +2264,7 @@ See also `charset-priority-list' and `set-charset-priority'.  */)
 
   if (n == 0)
     return Qnil;
-  SAFE_ALLOCA (sort_data, struct charset_sort_data *, sizeof (*sort_data) * n);
+  SAFE_NALLOCA (sort_data, 1, n);
   for (tail = charsets, i = 0; CONSP (tail); tail = XCDR (tail), i++)
     {
       elt = XCAR (tail);
@@ -2307,6 +2336,18 @@ init_charset_once (void)
 
 #ifdef emacs
 
+/* Allocate an initial charset table that is large enough to handle
+   Emacs while it is bootstrapping.  As of September 2011, the size
+   needs to be at least 166; make it a bit bigger to allow for future
+   expansion.
+
+   Don't make the value so small that the table is reallocated during
+   bootstrapping, as glibc malloc calls larger than just under 64 KiB
+   during an initial bootstrap wreak havoc after dumping; see the
+   M_MMAP_THRESHOLD value in alloc.c, plus there is a extra overhead
+   internal to glibc malloc and perhaps to Emacs malloc debugging.  */
+static struct charset charset_table_init[180];
+
 void
 syms_of_charset (void)
 {
@@ -2342,9 +2383,8 @@ syms_of_charset (void)
     Vcharset_hash_table = Fmake_hash_table (2, args);
   }
 
-  charset_table_size = 128;
-  charset_table = ((struct charset *)
-                  xmalloc (sizeof (struct charset) * charset_table_size));
+  charset_table = charset_table_init;
+  charset_table_size = sizeof charset_table_init / sizeof *charset_table_init;
   charset_table_used = 0;
 
   defsubr (&Scharsetp);