Make sure a 64-bit char is never passed to CHAR_STRING.
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Jun 2011 00:36:03 +0000 (17:36 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Jun 2011 00:36:03 +0000 (17:36 -0700)
Otherwise, CHAR_STRING would do the wrong thing on a 64-bit platform,
by silently ignoring the top 32 bits, allowing some values
that were far too large to be valid characters.
* character.h: Include <verify.h>.
(CHAR_STRING, CHAR_STRING_ADVANCE): Verify that the character
arguments are no wider than unsigned, as a compile-time check
to prevent future regressions in this area.
* data.c (Faset):
* editfns.c (Fchar_to_string, general_insert_function, Finsert_char):
(Fsubst_char_in_region):
* fns.c (concat):
* xdisp.c (decode_mode_spec_coding):
Adjust to CHAR_STRING's new requirement.
* editfns.c (Finsert_char, Fsubst_char_in_region):
* fns.c (concat): Check that character args are actually
characters.  Without this test, these functions did the wrong
thing with wildly out-of-range values on 64-bit hosts.

src/ChangeLog
src/character.h
src/data.c
src/editfns.c
src/fns.c
src/xdisp.c

index 921f976..f8a4abd 100644 (file)
@@ -1,3 +1,25 @@
+2011-06-13  Paul Eggert  <eggert@cs.ucla.edu>
+
+
+       Make sure a 64-bit char is never passed to CHAR_STRING.
+       Otherwise, CHAR_STRING would do the wrong thing on a 64-bit platform,
+       by silently ignoring the top 32 bits, allowing some values
+       that were far too large to be valid characters.
+       * character.h: Include <verify.h>.
+       (CHAR_STRING, CHAR_STRING_ADVANCE): Verify that the character
+       arguments are no wider than unsigned, as a compile-time check
+       to prevent future regressions in this area.
+       * data.c (Faset):
+       * editfns.c (Fchar_to_string, general_insert_function, Finsert_char):
+       (Fsubst_char_in_region):
+       * fns.c (concat):
+       * xdisp.c (decode_mode_spec_coding):
+       Adjust to CHAR_STRING's new requirement.
+       * editfns.c (Finsert_char, Fsubst_char_in_region):
+       * fns.c (concat): Check that character args are actually
+       characters.  Without this test, these functions did the wrong
+       thing with wildly out-of-range values on 64-bit hosts.
+
 2011-06-12  Paul Eggert  <eggert@cs.ucla.edu>
 
        Remove incorrect casts to 'unsigned' that lose info on 64-bit hosts.
index 695a55b..de97754 100644 (file)
@@ -23,6 +23,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifndef EMACS_CHARACTER_H
 #define EMACS_CHARACTER_H
 
+#include <verify.h>
+
 /* character code      1st byte   byte sequence
    --------------      --------   -------------
         0-7F           00..7F     0xxxxxxx
@@ -173,7 +175,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
       (p)[1] = (0x80 | (((c) >> 6) & 0x3F)),   \
       (p)[2] = (0x80 | ((c) & 0x3F)),          \
       3)                                       \
-   : char_string ((unsigned) c, p))
+   : (char_string (c, p) + !verify_true (sizeof (c) <= sizeof (unsigned))))
 
 /* Store multibyte form of byte B in P.  The caller should allocate at
    least MAX_MULTIBYTE_LENGTH bytes area at P in advance.  Returns the
@@ -201,7 +203,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
        *(p)++ = (0x80 | (((c) >> 6) & 0x3F)),  \
        *(p)++ = (0x80 | ((c) & 0x3F));         \
     else                                       \
-      (p) += char_string ((c), (p));           \
+      {                                                \
+       verify (sizeof (c) <= sizeof (unsigned));       \
+       (p) += char_string (c, p);              \
+      }                                                \
   } while (0)
 
 
index 57d7753..3a08a7a 100644 (file)
@@ -2152,17 +2152,19 @@ bool-vector.  IDX starts at 0.  */)
     {
       EMACS_INT idxval_byte, prev_bytes, new_bytes, nbytes;
       unsigned char workbuf[MAX_MULTIBYTE_LENGTH], *p0 = workbuf, *p1;
+      int c;
 
       if (idxval < 0 || idxval >= SCHARS (array))
        args_out_of_range (array, idx);
       CHECK_CHARACTER (newelt);
+      c = XFASTINT (newelt);
 
       nbytes = SBYTES (array);
 
       idxval_byte = string_char_to_byte (array, idxval);
       p1 = SDATA (array) + idxval_byte;
       prev_bytes = BYTES_BY_CHAR_HEAD (*p1);
-      new_bytes = CHAR_STRING (XINT (newelt), p0);
+      new_bytes = CHAR_STRING (c, p0);
       if (prev_bytes != new_bytes)
        {
          /* We must relocate the string data.  */
index 232af35..81e5917 100644 (file)
@@ -185,12 +185,13 @@ DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
 usage: (char-to-string CHAR)  */)
   (Lisp_Object character)
 {
-  int len;
+  int c, len;
   unsigned char str[MAX_MULTIBYTE_LENGTH];
 
   CHECK_CHARACTER (character);
+  c = XFASTINT (character);
 
-  len = CHAR_STRING (XFASTINT (character), str);
+  len = CHAR_STRING (c, str);
   return make_string_from_bytes ((char *) str, 1, len);
 }
 
@@ -2203,16 +2204,17 @@ general_insert_function (void (*insert_func)
       val = args[argnum];
       if (CHARACTERP (val))
        {
+         int c = XFASTINT (val);
          unsigned char str[MAX_MULTIBYTE_LENGTH];
          int len;
 
          if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
-           len = CHAR_STRING (XFASTINT (val), str);
+           len = CHAR_STRING (c, str);
          else
            {
-             str[0] = (ASCII_CHAR_P (XINT (val))
-                       ? XINT (val)
-                       : multibyte_char_to_unibyte (XINT (val)));
+             str[0] = (ASCII_CHAR_P (c)
+                       ? c
+                       : multibyte_char_to_unibyte (c));
              len = 1;
            }
          (*insert_func) ((char *) str, len);
@@ -2332,16 +2334,17 @@ from adjoining text, if those properties are sticky.  */)
   register EMACS_INT stringlen;
   register int i;
   register EMACS_INT n;
-  int len;
+  int c, len;
   unsigned char str[MAX_MULTIBYTE_LENGTH];
 
-  CHECK_NUMBER (character);
+  CHECK_CHARACTER (character);
   CHECK_NUMBER (count);
+  c = XFASTINT (character);
 
   if (!NILP (BVAR (current_buffer, enable_multibyte_characters)))
-    len = CHAR_STRING (XFASTINT (character), str);
+    len = CHAR_STRING (c, str);
   else
-    str[0] = XFASTINT (character), len = 1;
+    str[0] = c, len = 1;
   if (BUF_BYTES_MAX / len < XINT (count))
     error ("Maximum buffer size would be exceeded");
   n = XINT (count) * len;
@@ -2784,17 +2787,20 @@ Both characters must have the same length of multi-byte form.  */)
   int maybe_byte_combining = COMBINING_NO;
   EMACS_INT last_changed = 0;
   int multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
+  int fromc, toc;
 
  restart:
 
   validate_region (&start, &end);
-  CHECK_NUMBER (fromchar);
-  CHECK_NUMBER (tochar);
+  CHECK_CHARACTER (fromchar);
+  CHECK_CHARACTER (tochar);
+  fromc = XFASTINT (fromchar);
+  toc = XFASTINT (tochar);
 
   if (multibyte_p)
     {
-      len = CHAR_STRING (XFASTINT (fromchar), fromstr);
-      if (CHAR_STRING (XFASTINT (tochar), tostr) != len)
+      len = CHAR_STRING (fromc, fromstr);
+      if (CHAR_STRING (toc, tostr) != len)
        error ("Characters in `subst-char-in-region' have different byte-lengths");
       if (!ASCII_BYTE_P (*tostr))
        {
@@ -2811,8 +2817,8 @@ Both characters must have the same length of multi-byte form.  */)
   else
     {
       len = 1;
-      fromstr[0] = XFASTINT (fromchar);
-      tostr[0] = XFASTINT (tochar);
+      fromstr[0] = fromc;
+      tostr[0] = toc;
     }
 
   pos = XINT (start);
index 7a28457..250df72 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -679,12 +679,13 @@ concat (size_t nargs, Lisp_Object *args,
              }
            else
              {
-               CHECK_NUMBER (elt);
+               int c;
+               CHECK_CHARACTER (elt);
+               c = XFASTINT (elt);
                if (some_multibyte)
-                 toindex_byte += CHAR_STRING (XINT (elt),
-                                              SDATA (val) + toindex_byte);
+                 toindex_byte += CHAR_STRING (c, SDATA (val) + toindex_byte);
                else
-                 SSET (val, toindex_byte++, XINT (elt));
+                 SSET (val, toindex_byte++, c);
                toindex++;
              }
          }
index 65f6ddd..c495659 100644 (file)
@@ -19379,7 +19379,8 @@ decode_mode_spec_coding (Lisp_Object coding_system, register char *buf, int eol_
       else if (CHARACTERP (eoltype))
        {
          unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
-         eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
+         int c = XFASTINT (eoltype);
+         eol_str_len = CHAR_STRING (c, tmp);
          eol_str = tmp;
        }
       else