emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] /srv/bzr/emacs/trunk r104390: Merge: Integer overflow fixe


From: Paul Eggert
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r104390: Merge: Integer overflow fixes.
Date: Fri, 27 May 2011 13:32:41 -0700
User-agent: Bazaar (2.3.1)

------------------------------------------------------------
revno: 104390 [merge]
fixes bug(s): http://debbugs.gnu.org/8722 http://debbugs.gnu.org/8719 
http://debbugs.gnu.org/8668
committer: Paul Eggert <address@hidden>
branch nick: trunk
timestamp: Fri 2011-05-27 13:32:41 -0700
message:
  Merge: Integer overflow fixes.
modified:
  src/ChangeLog
  src/alloc.c
  src/ccl.c
  src/character.c
  src/character.h
  src/data.c
  src/dbusbind.c
  src/editfns.c
  src/fns.c
  src/insdel.c
  src/lisp.h
  src/mem-limits.h
  src/print.c
=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2011-05-27 19:39:18 +0000
+++ b/src/ChangeLog     2011-05-27 19:58:54 +0000
@@ -1,3 +1,85 @@
+2011-05-27  Paul Eggert  <address@hidden>
+
+       Integer overflow fixes.
+
+       * dbusbind.c: Serial number integer overflow fixes.
+       (CHECK_DBUS_SERIAL_GET_SERIAL): New macro.
+       (Fdbus_call_method_asynchronously, xd_read_message_1): Use a float
+       to hold a serial number that is too large for a fixnum.
+       (Fdbus_method_return_internal, Fdbus_method_error_internal):
+       Check for serial numbers out of range.  Decode any serial number
+       that was so large that it became a float.  (Bug#8722)
+
+       * dbusbind.c: Use XFASTINT rather than XUINT, and check for nonneg.
+       (Fdbus_call_method, Fdbus_call_method_asynchronously):
+       Use XFASTINT rather than XUINT when numbers are nonnegative.
+       (xd_append_arg, Fdbus_method_return_internal):
+       (Fdbus_method_error_internal): Likewise.  Also, for unsigned
+       arguments, check that Lisp number is nonnegative, rather than
+       silently wrapping negative numbers around.  (Bug#8722)
+       (xd_read_message_1): Don't assume dbus_uint32_t can fit in int.
+       (Bug#8722)
+
+       * data.c (arith_driver, Flsh): Avoid unnecessary casts to EMACS_UINT.
+
+       * ccl.c (ccl_driver): Redo slightly to avoid the need for 'unsigned'.
+
+       ccl: add integer overflow checks
+       * ccl.c (CCL_CODE_MAX, GET_CCL_RANGE, GET_CCL_CODE, GET_CCL_INT):
+       (IN_INT_RANGE): New macros.
+       (ccl_driver): Use them to check for integer overflow when
+       decoding a CCL program.  Many of the new checks are whether XINT (x)
+       fits in int; it doesn't always, on 64-bit hosts.  The new version
+       doesn't catch all possible integer overflows, but it's an
+       improvement.  (Bug#8719)
+
+       * alloc.c (make_event_array): Use XINT, not XUINT.
+       There's no need for unsigned here.
+
+       * mem-limits.h (EXCEEDS_LISP_PTR) [!USE_LSB_TAG]: EMACS_UINT -> 
uintptr_t
+       This follows up to the 2011-05-06 change that substituted uintptr_t
+       for EMACS_INT.  This case wasn't caught back then.
+
+       Rework Fformat to avoid integer overflow issues.
+       * editfns.c: Include <float.h> unconditionally, as it's everywhere
+       now (part of C89).  Include <verify.h>.
+       (MAX_10_EXP, CONVERTED_BYTE_SIZE): Remove; no longer needed.
+       (pWIDE, pWIDElen, signed_wide, unsigned_wide): New defns.
+       (Fformat): Avoid the prepass trying to compute sizes; it was only
+       approximate and thus did not catch overflow reliably.  Instead, walk
+       through the format just once, formatting and computing sizes as we go,
+       checking for integer overflow at every step, and allocating a larger
+       buffer as needed.  Keep track separately whether the format is
+       multibyte.  Keep only the most-recently calculated precision, rather
+       than them all.  Record whether each argument has been converted to
+       string.  Use EMACS_INT, not int, for byte and char and arg counts.
+       Support field widths and precisions larger than INT_MAX.  Avoid
+       sprintf's undefined behavior with conversion specifications such as %#d
+       and %.0c.  Fix bug with strchr succeeding on '\0' when looking for
+       flags.  Fix bug with (format "%c" 256.0).  Avoid integer overflow when
+       formatting out-of-range floating point numbers with int
+       formats. (Bug#8668)
+
+       * lisp.h (FIXNUM_OVERFLOW_P): Work even if arg is a NaN.
+
+       * data.c: Avoid integer truncation in expressions involving floats.
+       * data.c: Include <intprops.h>.
+       (arith_driver): When there's an integer overflow in an expression
+       involving floating point, convert the integers to floating point
+       so that the resulting value does not suffer from catastrophic
+       integer truncation.  For example, on a 64-bit host (* 4
+       most-negative-fixnum 0.5) should yield about -4.6e+18, not zero.
+       Do not rely on undefined behavior after integer overflow.
+
+       merge count_size_as_multibyte, parse_str_to_multibyte
+       * character.c, character.h (count_size_as_multibyte):
+       Renamed from parse_str_to_multibyte; all uses changed.
+       Check for integer overflow.
+       * insdel.c, lisp.h (count_size_as_multibyte): Remove,
+       since it's now a duplicate of the other.  This is more of
+       a character than a buffer op, so better that it's in character.c.
+       * fns.c, print.c: Adjust to above changes.
+
 2011-05-27  Stefan Monnier  <address@hidden>
 
        * xselect.c (x_convert_selection): Yet another int/Lisp_Object mixup.

=== modified file 'src/alloc.c'
--- a/src/alloc.c       2011-05-16 01:11:54 +0000
+++ b/src/alloc.c       2011-05-23 00:31:35 +0000
@@ -3244,7 +3244,7 @@
        are characters that are in 0...127,
        after discarding the meta bit and all the bits above it.  */
     if (!INTEGERP (args[i])
-       || (XUINT (args[i]) & ~(-CHAR_META)) >= 0200)
+       || (XINT (args[i]) & ~(-CHAR_META)) >= 0200)
       return Fvector (nargs, args);
 
   /* Since the loop exited, we know that all the things in it are

=== modified file 'src/ccl.c'
--- a/src/ccl.c 2011-05-12 07:07:06 +0000
+++ b/src/ccl.c 2011-05-23 06:58:38 +0000
@@ -98,6 +98,8 @@
    and `rrr' are CCL register number, `XXXXX' is one of the following
    CCL commands.  */
 
+#define CCL_CODE_MAX ((1 << (28 - 1)) - 1)
+
 /* CCL commands
 
    Each comment fields shows one or more lines for command syntax and
@@ -742,6 +744,24 @@
 
 #endif
 
+#define GET_CCL_RANGE(var, ccl_prog, ic, lo, hi)               \
+  do                                                           \
+    {                                                          \
+      EMACS_INT prog_word = XINT ((ccl_prog)[ic]);             \
+      if (! ((lo) <= prog_word && prog_word <= (hi)))          \
+       CCL_INVALID_CMD;                                        \
+      (var) = prog_word;                                       \
+    }                                                          \
+  while (0)
+
+#define GET_CCL_CODE(code, ccl_prog, ic)                       \
+  GET_CCL_RANGE (code, ccl_prog, ic, 0, CCL_CODE_MAX)
+
+#define GET_CCL_INT(var, ccl_prog, ic)                         \
+  GET_CCL_RANGE (var, ccl_prog, ic, INT_MIN, INT_MAX)
+
+#define IN_INT_RANGE(val) (INT_MIN <= (val) && (val) <= INT_MAX)
+
 /* Encode one character CH to multibyte form and write to the current
    output buffer.  If CH is less than 256, CH is written as is.  */
 #define CCL_WRITE_CHAR(ch)                     \
@@ -899,7 +919,7 @@
        }
 
       this_ic = ic;
-      code = XINT (ccl_prog[ic]); ic++;
+      GET_CCL_CODE (code, ccl_prog, ic++);
       field1 = code >> 8;
       field2 = (code & 0xFF) >> 5;
 
@@ -920,15 +940,14 @@
          break;
 
        case CCL_SetConst:      /* 00000000000000000000rrrXXXXX */
-         reg[rrr] = XINT (ccl_prog[ic]);
-         ic++;
+         GET_CCL_INT (reg[rrr], ccl_prog, ic++);
          break;
 
        case CCL_SetArray:      /* CCCCCCCCCCCCCCCCCCCCRRRrrrXXXXX */
          i = reg[RRR];
          j = field1 >> 3;
-         if ((unsigned int) i < j)
-           reg[rrr] = XINT (ccl_prog[ic + i]);
+         if (0 <= i && i < j)
+           GET_CCL_INT (reg[rrr], ccl_prog, ic + i);
          ic += j;
          break;
 
@@ -956,13 +975,13 @@
          break;
 
        case CCL_WriteConstJump: /* A--D--D--R--E--S--S-000XXXXX */
-         i = XINT (ccl_prog[ic]);
+         GET_CCL_INT (i, ccl_prog, ic);
          CCL_WRITE_CHAR (i);
          ic += ADDR;
          break;
 
        case CCL_WriteConstReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
-         i = XINT (ccl_prog[ic]);
+         GET_CCL_INT (i, ccl_prog, ic);
          CCL_WRITE_CHAR (i);
          ic++;
          CCL_READ_CHAR (reg[rrr]);
@@ -970,18 +989,17 @@
          break;
 
        case CCL_WriteStringJump: /* A--D--D--R--E--S--S-000XXXXX */
-         j = XINT (ccl_prog[ic]);
-         ic++;
+         GET_CCL_INT (j, ccl_prog, ic++);
          CCL_WRITE_STRING (j);
          ic += ADDR - 1;
          break;
 
        case CCL_WriteArrayReadJump: /* A--D--D--R--E--S--S-rrrXXXXX */
          i = reg[rrr];
-         j = XINT (ccl_prog[ic]);
-         if ((unsigned int) i < j)
+         GET_CCL_INT (j, ccl_prog, ic);
+         if (0 <= i && i < j)
            {
-             i = XINT (ccl_prog[ic + 1 + i]);
+             GET_CCL_INT (i, ccl_prog, ic + 1 + i);
              CCL_WRITE_CHAR (i);
            }
          ic += j + 2;
@@ -998,10 +1016,14 @@
          CCL_READ_CHAR (reg[rrr]);
          /* fall through ... */
        case CCL_Branch:        /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
-         if ((unsigned int) reg[rrr] < field1)
-           ic += XINT (ccl_prog[ic + reg[rrr]]);
-         else
-           ic += XINT (ccl_prog[ic + field1]);
+       {
+         int incr;
+         GET_CCL_INT (incr, ccl_prog,
+                      ic + (0 <= reg[rrr] && reg[rrr] < field1
+                            ? reg[rrr]
+                            : field1));
+         ic += incr;
+       }
          break;
 
        case CCL_ReadRegister:  /* CCCCCCCCCCCCCCCCCCCCrrXXXXX */
@@ -1009,7 +1031,7 @@
            {
              CCL_READ_CHAR (reg[rrr]);
              if (!field1) break;
-             code = XINT (ccl_prog[ic]); ic++;
+             GET_CCL_CODE (code, ccl_prog, ic++);
              field1 = code >> 8;
              field2 = (code & 0xFF) >> 5;
            }
@@ -1018,7 +1040,7 @@
        case CCL_WriteExprConst:  /* 1:00000OPERATION000RRR000XXXXX */
          rrr = 7;
          i = reg[RRR];
-         j = XINT (ccl_prog[ic]);
+         GET_CCL_INT (j, ccl_prog, ic);
          op = field1 >> 6;
          jump_address = ic + 1;
          goto ccl_set_expr;
@@ -1029,7 +1051,7 @@
              i = reg[rrr];
              CCL_WRITE_CHAR (i);
              if (!field1) break;
-             code = XINT (ccl_prog[ic]); ic++;
+             GET_CCL_CODE (code, ccl_prog, ic++);
              field1 = code >> 8;
              field2 = (code & 0xFF) >> 5;
            }
@@ -1051,10 +1073,7 @@
            /* If FFF is nonzero, the CCL program ID is in the
                following code.  */
            if (rrr)
-             {
-               prog_id = XINT (ccl_prog[ic]);
-               ic++;
-             }
+             GET_CCL_INT (prog_id, ccl_prog, ic++);
            else
              prog_id = field1;
 
@@ -1095,9 +1114,9 @@
 
        case CCL_WriteArray:    /* CCCCCCCCCCCCCCCCCCCCrrrXXXXX */
          i = reg[rrr];
-         if ((unsigned int) i < field1)
+         if (0 <= i && i < field1)
            {
-             j = XINT (ccl_prog[ic + i]);
+             GET_CCL_INT (j, ccl_prog, ic + i);
              CCL_WRITE_CHAR (j);
            }
          ic += field1;
@@ -1122,8 +1141,7 @@
          CCL_SUCCESS;
 
        case CCL_ExprSelfConst: /* 00000OPERATION000000rrrXXXXX */
-         i = XINT (ccl_prog[ic]);
-         ic++;
+         GET_CCL_INT (i, ccl_prog, ic++);
          op = field1 >> 6;
          goto ccl_expr_self;
 
@@ -1159,9 +1177,9 @@
 
        case CCL_SetExprConst:  /* 00000OPERATION000RRRrrrXXXXX */
          i = reg[RRR];
-         j = XINT (ccl_prog[ic]);
+         GET_CCL_INT (j, ccl_prog, ic++);
          op = field1 >> 6;
-         jump_address = ++ic;
+         jump_address = ic;
          goto ccl_set_expr;
 
        case CCL_SetExprReg:    /* 00000OPERATIONRrrRRRrrrXXXXX */
@@ -1175,10 +1193,9 @@
          CCL_READ_CHAR (reg[rrr]);
        case CCL_JumpCondExprConst: /* A--D--D--R--E--S--S-rrrXXXXX */
          i = reg[rrr];
-         op = XINT (ccl_prog[ic]);
-         jump_address = ic++ + ADDR;
-         j = XINT (ccl_prog[ic]);
-         ic++;
+         jump_address = ic + ADDR;
+         GET_CCL_INT (op, ccl_prog, ic++);
+         GET_CCL_INT (j, ccl_prog, ic++);
          rrr = 7;
          goto ccl_set_expr;
 
@@ -1186,10 +1203,10 @@
          CCL_READ_CHAR (reg[rrr]);
        case CCL_JumpCondExprReg:
          i = reg[rrr];
-         op = XINT (ccl_prog[ic]);
-         jump_address = ic++ + ADDR;
-         j = reg[XINT (ccl_prog[ic])];
-         ic++;
+         jump_address = ic + ADDR;
+         GET_CCL_INT (op, ccl_prog, ic++);
+         GET_CCL_RANGE (j, ccl_prog, ic++, 0, 7);
+         j = reg[j];
          rrr = 7;
 
        ccl_set_expr:
@@ -1267,18 +1284,27 @@
              break;
 
            case CCL_TranslateCharacterConstTbl:
-             op = XINT (ccl_prog[ic]); /* table */
-             ic++;
-             i = CCL_DECODE_CHAR (reg[RRR], reg[rrr]);
-             op = translate_char (GET_TRANSLATION_TABLE (op), i);
-             CCL_ENCODE_CHAR (op, charset_list, reg[RRR], reg[rrr]);
+             {
+               EMACS_INT eop;
+               GET_CCL_RANGE (eop, ccl_prog, ic++, 0,
+                              (VECTORP (Vtranslation_table_vector)
+                               ? ASIZE (Vtranslation_table_vector)
+                               : -1));
+               i = CCL_DECODE_CHAR (reg[RRR], reg[rrr]);
+               op = translate_char (GET_TRANSLATION_TABLE (eop), i);
+               CCL_ENCODE_CHAR (op, charset_list, reg[RRR], reg[rrr]);
+             }
              break;
 
            case CCL_LookupIntConstTbl:
-             op = XINT (ccl_prog[ic]); /* table */
-             ic++;
              {
-               struct Lisp_Hash_Table *h = GET_HASH_TABLE (op);
+               EMACS_INT eop;
+               struct Lisp_Hash_Table *h;
+               GET_CCL_RANGE (eop, ccl_prog, ic++, 0,
+                              (VECTORP (Vtranslation_hash_table_vector)
+                               ? ASIZE (Vtranslation_hash_table_vector)
+                               : -1));
+               h = GET_HASH_TABLE (eop);
 
                op = hash_lookup (h, make_number (reg[RRR]), NULL);
                if (op >= 0)
@@ -1297,18 +1323,22 @@
              break;
 
            case CCL_LookupCharConstTbl:
-             op = XINT (ccl_prog[ic]); /* table */
-             ic++;
-             i = CCL_DECODE_CHAR (reg[RRR], reg[rrr]);
              {
-               struct Lisp_Hash_Table *h = GET_HASH_TABLE (op);
+               EMACS_INT eop;
+               struct Lisp_Hash_Table *h;
+               GET_CCL_RANGE (eop, ccl_prog, ic++, 0,
+                              (VECTORP (Vtranslation_hash_table_vector)
+                               ? ASIZE (Vtranslation_hash_table_vector)
+                               : -1));
+               i = CCL_DECODE_CHAR (reg[RRR], reg[rrr]);
+               h = GET_HASH_TABLE (eop);
 
                op = hash_lookup (h, make_number (i), NULL);
                if (op >= 0)
                  {
                    Lisp_Object opl;
                    opl = HASH_VALUE (h, op);
-                   if (!INTEGERP (opl))
+                   if (! (INTEGERP (opl) && IN_INT_RANGE (XINT (opl))))
                      CCL_INVALID_CMD;
                    reg[RRR] = XINT (opl);
                    reg[7] = 1; /* r7 true for success */
@@ -1321,9 +1351,10 @@
            case CCL_IterateMultipleMap:
              {
                Lisp_Object map, content, attrib, value;
-               int point, size, fin_ic;
+               EMACS_INT point, size;
+               int fin_ic;
 
-               j = XINT (ccl_prog[ic++]); /* number of maps. */
+               GET_CCL_INT (j, ccl_prog, ic++); /* number of maps. */
                fin_ic = ic + j;
                op = reg[rrr];
                if ((j > reg[RRR]) && (j >= 0))
@@ -1343,7 +1374,7 @@
 
                    size = ASIZE (Vcode_conversion_map_vector);
                    point = XINT (ccl_prog[ic++]);
-                   if (point >= size) continue;
+                   if (! (0 <= point && point < size)) continue;
                    map = AREF (Vcode_conversion_map_vector, point);
 
                    /* Check map validity.  */
@@ -1358,18 +1389,19 @@
                    /* check map type,
                       [STARTPOINT VAL1 VAL2 ...] or
                       [t ELEMENT STARTPOINT ENDPOINT]  */
-                   if (NUMBERP (content))
+                   if (INTEGERP (content))
                      {
-                       point = XUINT (content);
-                       point = op - point + 1;
-                       if (!((point >= 1) && (point < size))) continue;
-                       content = AREF (map, point);
+                       point = XINT (content);
+                       if (!(point <= op && op - point + 1 < size)) continue;
+                       content = AREF (map, op - point + 1);
                      }
                    else if (EQ (content, Qt))
                      {
                        if (size != 4) continue;
-                       if ((op >= XUINT (AREF (map, 2)))
-                           && (op < XUINT (AREF (map, 3))))
+                       if (INTEGERP (AREF (map, 2))
+                           && XINT (AREF (map, 2)) <= op
+                           && INTEGERP (AREF (map, 3))
+                           && op < XINT (AREF (map, 3)))
                          content = AREF (map, 1);
                        else
                          continue;
@@ -1379,7 +1411,7 @@
 
                    if (NILP (content))
                      continue;
-                   else if (NUMBERP (content))
+                   else if (INTEGERP (content) && IN_INT_RANGE (XINT 
(content)))
                      {
                        reg[RRR] = i;
                        reg[rrr] = XINT(content);
@@ -1394,10 +1426,11 @@
                      {
                        attrib = XCAR (content);
                        value = XCDR (content);
-                       if (!NUMBERP (attrib) || !NUMBERP (value))
+                       if (! (INTEGERP (attrib) && INTEGERP (value)
+                              && IN_INT_RANGE (XINT (value))))
                          continue;
                        reg[RRR] = i;
-                       reg[rrr] = XUINT (value);
+                       reg[rrr] = XINT (value);
                        break;
                      }
                    else if (SYMBOLP (content))
@@ -1432,8 +1465,9 @@
                  mapping_stack_pointer = mapping_stack;
                stack_idx_of_map_multiple = 0;
 
-               map_set_rest_length =
-                 XINT (ccl_prog[ic++]); /* number of maps and separators. */
+               /* Get number of maps and separators.  */
+               GET_CCL_INT (map_set_rest_length, ccl_prog, ic++);
+
                fin_ic = ic + map_set_rest_length;
                op = reg[rrr];
 
@@ -1501,7 +1535,7 @@
                do {
                  for (;map_set_rest_length > 0;i++, ic++, 
map_set_rest_length--)
                    {
-                     point = XINT(ccl_prog[ic]);
+                     GET_CCL_INT (point, ccl_prog, ic);
                      if (point < 0)
                        {
                          /* +1 is for including separator. */
@@ -1531,18 +1565,19 @@
                      /* check map type,
                         [STARTPOINT VAL1 VAL2 ...] or
                         [t ELEMENT STARTPOINT ENDPOINT]  */
-                     if (NUMBERP (content))
+                     if (INTEGERP (content))
                        {
-                         point = XUINT (content);
-                         point = op - point + 1;
-                         if (!((point >= 1) && (point < size))) continue;
-                         content = AREF (map, point);
+                         point = XINT (content);
+                         if (!(point <= op && op - point + 1 < size)) continue;
+                         content = AREF (map, op - point + 1);
                        }
                      else if (EQ (content, Qt))
                        {
                          if (size != 4) continue;
-                         if ((op >= XUINT (AREF (map, 2))) &&
-                             (op < XUINT (AREF (map, 3))))
+                         if (INTEGERP (AREF (map, 2))
+                             && XINT (AREF (map, 2)) <= op
+                             && INTEGERP (AREF (map, 3))
+                             && op < XINT (AREF (map, 3)))
                            content = AREF (map, 1);
                          else
                            continue;
@@ -1554,7 +1589,7 @@
                        continue;
 
                      reg[RRR] = i;
-                     if (NUMBERP (content))
+                     if (INTEGERP (content) && IN_INT_RANGE (XINT (content)))
                        {
                          op = XINT (content);
                          i += map_set_rest_length - 1;
@@ -1566,9 +1601,10 @@
                        {
                          attrib = XCAR (content);
                          value = XCDR (content);
-                         if (!NUMBERP (attrib) || !NUMBERP (value))
+                         if (! (INTEGERP (attrib) && INTEGERP (value)
+                                && IN_INT_RANGE (XINT (value))))
                            continue;
-                         op = XUINT (value);
+                         op = XINT (value);
                          i += map_set_rest_length - 1;
                          ic += map_set_rest_length - 1;
                          POP_MAPPING_STACK (map_set_rest_length, reg[rrr]);
@@ -1613,7 +1649,7 @@
            case CCL_MapSingle:
              {
                Lisp_Object map, attrib, value, content;
-               int size, point;
+               int point;
                j = XINT (ccl_prog[ic++]); /* map_id */
                op = reg[rrr];
                if (j >= ASIZE (Vcode_conversion_map_vector))
@@ -1628,41 +1664,36 @@
                    break;
                  }
                map = XCDR (map);
-               if (!VECTORP (map))
+               if (! (VECTORP (map)
+                      && INTEGERP (AREF (map, 0))
+                      && XINT (AREF (map, 0)) <= op
+                      && op - XINT (AREF (map, 0)) + 1 < ASIZE (map)))
                  {
                    reg[RRR] = -1;
                    break;
                  }
-               size = ASIZE (map);
-               point = XUINT (AREF (map, 0));
+               point = XINT (AREF (map, 0));
                point = op - point + 1;
                reg[RRR] = 0;
-               if ((size <= 1) ||
-                   (!((point >= 1) && (point < size))))
+               content = AREF (map, point);
+               if (NILP (content))
                  reg[RRR] = -1;
-               else
+               else if (INTEGERP (content))
+                 reg[rrr] = XINT (content);
+               else if (EQ (content, Qt));
+               else if (CONSP (content))
                  {
-                   reg[RRR] = 0;
-                   content = AREF (map, point);
-                   if (NILP (content))
-                     reg[RRR] = -1;
-                   else if (NUMBERP (content))
-                     reg[rrr] = XINT (content);
-                   else if (EQ (content, Qt));
-                   else if (CONSP (content))
-                     {
-                       attrib = XCAR (content);
-                       value = XCDR (content);
-                       if (!NUMBERP (attrib) || !NUMBERP (value))
-                         continue;
-                       reg[rrr] = XUINT(value);
-                       break;
-                     }
-                   else if (SYMBOLP (content))
-                     CCL_CALL_FOR_MAP_INSTRUCTION (content, ic);
-                   else
-                     reg[RRR] = -1;
+                   attrib = XCAR (content);
+                   value = XCDR (content);
+                   if (!INTEGERP (attrib) || !INTEGERP (value))
+                     continue;
+                   reg[rrr] = XINT(value);
+                   break;
                  }
+               else if (SYMBOLP (content))
+                 CCL_CALL_FOR_MAP_INSTRUCTION (content, ic);
+               else
+                 reg[RRR] = -1;
              }
              break;
 

=== modified file 'src/character.c'
--- a/src/character.c   2011-05-16 05:18:38 +0000
+++ b/src/character.c   2011-05-21 04:33:23 +0000
@@ -672,13 +672,18 @@
    `str_to_multibyte'.  */
 
 EMACS_INT
-parse_str_to_multibyte (const unsigned char *str, EMACS_INT len)
+count_size_as_multibyte (const unsigned char *str, EMACS_INT len)
 {
   const unsigned char *endp = str + len;
   EMACS_INT bytes;
 
   for (bytes = 0; str < endp; str++)
-    bytes += (*str < 0x80) ? 1 : 2;
+    {
+      int n = *str < 0x80 ? 1 : 2;
+      if (INT_ADD_OVERFLOW (bytes, n))
+        string_overflow ();
+      bytes += n;
+    }
   return bytes;
 }
 

=== modified file 'src/character.h'
--- a/src/character.h   2011-05-16 05:08:59 +0000
+++ b/src/character.h   2011-05-21 04:33:23 +0000
@@ -602,7 +602,7 @@
 extern int char_printable_p (int c);
 extern void parse_str_as_multibyte (const unsigned char *,
                                    EMACS_INT, EMACS_INT *, EMACS_INT *);
-extern EMACS_INT parse_str_to_multibyte (const unsigned char *, EMACS_INT);
+extern EMACS_INT count_size_as_multibyte (const unsigned char *, EMACS_INT);
 extern EMACS_INT str_as_multibyte (unsigned char *, EMACS_INT, EMACS_INT,
                             EMACS_INT *);
 extern EMACS_INT str_to_multibyte (unsigned char *, EMACS_INT, EMACS_INT);

=== modified file 'src/data.c'
--- a/src/data.c        2011-05-12 07:07:06 +0000
+++ b/src/data.c        2011-05-27 19:48:22 +0000
@@ -22,6 +22,9 @@
 #include <signal.h>
 #include <stdio.h>
 #include <setjmp.h>
+
+#include <intprops.h>
+
 #include "lisp.h"
 #include "puresize.h"
 #include "character.h"
@@ -2431,6 +2434,10 @@
   register EMACS_INT accum = 0;
   register EMACS_INT next;
 
+  int overflow = 0;
+  size_t ok_args;
+  EMACS_INT ok_accum;
+
   switch (SWITCH_ENUM_CAST (code))
     {
     case Alogior:
@@ -2451,25 +2458,48 @@
 
   for (argnum = 0; argnum < nargs; argnum++)
     {
+      if (! overflow)
+       {
+         ok_args = argnum;
+         ok_accum = accum;
+       }
+
       /* Using args[argnum] as argument to CHECK_NUMBER_... */
       val = args[argnum];
       CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (val);
 
       if (FLOATP (val))
-       return float_arith_driver ((double) accum, argnum, code,
+       return float_arith_driver (ok_accum, ok_args, code,
                                   nargs, args);
       args[argnum] = val;
       next = XINT (args[argnum]);
       switch (SWITCH_ENUM_CAST (code))
        {
        case Aadd:
+         if (INT_ADD_OVERFLOW (accum, next))
+           {
+             overflow = 1;
+             accum &= INTMASK;
+           }
          accum += next;
          break;
        case Asub:
+         if (INT_SUBTRACT_OVERFLOW (accum, next))
+           {
+             overflow = 1;
+             accum &= INTMASK;
+           }
          accum = argnum ? accum - next : nargs == 1 ? - next : next;
          break;
        case Amult:
-         accum *= next;
+         if (INT_MULTIPLY_OVERFLOW (accum, next))
+           {
+             EMACS_UINT a = accum, b = next, ab = a * b;
+             overflow = 1;
+             accum = ab & INTMASK;
+           }
+         else
+           accum *= next;
          break;
        case Adiv:
          if (!argnum)
@@ -2760,11 +2790,11 @@
   if (XINT (count) >= BITS_PER_EMACS_INT)
     XSETINT (val, 0);
   else if (XINT (count) > 0)
-    XSETINT (val, (EMACS_UINT) XUINT (value) << XFASTINT (count));
+    XSETINT (val, XUINT (value) << XFASTINT (count));
   else if (XINT (count) <= -BITS_PER_EMACS_INT)
     XSETINT (val, 0);
   else
-    XSETINT (val, (EMACS_UINT) XUINT (value) >> -XINT (count));
+    XSETINT (val, XUINT (value) >> -XINT (count));
   return val;
 }
 

=== modified file 'src/dbusbind.c'
--- a/src/dbusbind.c    2011-05-06 22:12:31 +0000
+++ b/src/dbusbind.c    2011-05-24 07:41:16 +0000
@@ -242,6 +242,24 @@
 #define XD_NEXT_VALUE(object)                                          \
   ((XD_DBUS_TYPE_P (CAR_SAFE (object))) ? CDR_SAFE (object) : object)
 
+/* Check whether X is a valid dbus serial number.  If valid, set
+   SERIAL to its value.  Otherwise, signal an error. */
+#define CHECK_DBUS_SERIAL_GET_SERIAL(x, serial)                                
\
+  do                                                                   \
+    {                                                                  \
+      dbus_uint32_t DBUS_SERIAL_MAX = -1;                              \
+      if (NATNUMP (x) && XINT (x) <= DBUS_SERIAL_MAX)                  \
+       serial = XINT (x);                                              \
+      else if (MOST_POSITIVE_FIXNUM < DBUS_SERIAL_MAX                  \
+              && FLOATP (x)                                            \
+              && 0 <= XFLOAT_DATA (x)                                  \
+              && XFLOAT_DATA (x) <= DBUS_SERIAL_MAX)                   \
+       serial = XFLOAT_DATA (x);                                       \
+      else                                                             \
+       XD_SIGNAL2 (build_string ("Invalid dbus serial"), x);           \
+    }                                                                  \
+  while (0)
+
 /* Compute SIGNATURE of OBJECT.  It must have a form that it can be
    used in dbus_message_iter_open_container.  DTYPE is the DBusType
    the object is related to.  It is passed as argument, because it
@@ -431,9 +449,9 @@
     switch (dtype)
       {
       case DBUS_TYPE_BYTE:
-       CHECK_NUMBER (object);
+       CHECK_NATNUM (object);
        {
-         unsigned char val = XUINT (object) & 0xFF;
+         unsigned char val = XFASTINT (object) & 0xFF;
          XD_DEBUG_MESSAGE ("%c %d", dtype, val);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
@@ -460,9 +478,9 @@
        }
 
       case DBUS_TYPE_UINT16:
-       CHECK_NUMBER (object);
+       CHECK_NATNUM (object);
        {
-         dbus_uint16_t val = XUINT (object);
+         dbus_uint16_t val = XFASTINT (object);
          XD_DEBUG_MESSAGE ("%c %u", dtype, (unsigned int) val);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
@@ -483,9 +501,9 @@
 #ifdef DBUS_TYPE_UNIX_FD
       case DBUS_TYPE_UNIX_FD:
 #endif
-       CHECK_NUMBER (object);
+       CHECK_NATNUM (object);
        {
-         dbus_uint32_t val = XUINT (object);
+         dbus_uint32_t val = XFASTINT (object);
          XD_DEBUG_MESSAGE ("%c %u", dtype, val);
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
@@ -503,10 +521,10 @@
        }
 
       case DBUS_TYPE_UINT64:
-       CHECK_NUMBER (object);
+       CHECK_NATNUM (object);
        {
-         dbus_uint64_t val = XUINT (object);
-         XD_DEBUG_MESSAGE ("%c %"pI"u", dtype, XUINT (object));
+         dbus_uint64_t val = XFASTINT (object);
+         XD_DEBUG_MESSAGE ("%c %"pI"d", dtype, XFASTINT (object));
          if (!dbus_message_iter_append_basic (iter, dtype, &val))
            XD_SIGNAL2 (build_string ("Unable to append argument"), object);
          return;
@@ -1110,7 +1128,7 @@
   if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout)))
     {
       CHECK_NATNUM (args[i+1]);
-      timeout = XUINT (args[i+1]);
+      timeout = XFASTINT (args[i+1]);
       i = i+2;
     }
 
@@ -1186,7 +1204,7 @@
 
   /* Return the result.  If there is only one single Lisp object,
      return it as-it-is, otherwise return the reversed list.  */
-  if (XUINT (Flength (result)) == 1)
+  if (XFASTINT (Flength (result)) == 1)
     RETURN_UNGCPRO (CAR_SAFE (result));
   else
     RETURN_UNGCPRO (Fnreverse (result));
@@ -1251,6 +1269,7 @@
   DBusMessage *dmessage;
   DBusMessageIter iter;
   unsigned int dtype;
+  dbus_uint32_t serial;
   int timeout = -1;
   size_t i = 6;
   char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
@@ -1292,7 +1311,7 @@
   if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout)))
     {
       CHECK_NATNUM (args[i+1]);
-      timeout = XUINT (args[i+1]);
+      timeout = XFASTINT (args[i+1]);
       i = i+2;
     }
 
@@ -1335,7 +1354,8 @@
        XD_SIGNAL1 (build_string ("Cannot send message"));
 
       /* The result is the key in Vdbus_registered_objects_table.  */
-      result = (list2 (bus, make_number (dbus_message_get_serial (dmessage))));
+      serial = dbus_message_get_serial (dmessage);
+      result = list2 (bus, make_fixnum_or_float (serial));
 
       /* Create a hash table entry.  */
       Fputhash (result, handler, Vdbus_registered_objects_table);
@@ -1368,25 +1388,26 @@
 usage: (dbus-method-return-internal BUS SERIAL SERVICE &rest ARGS)  */)
   (size_t nargs, register Lisp_Object *args)
 {
-  Lisp_Object bus, serial, service;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  Lisp_Object bus, service;
+  struct gcpro gcpro1, gcpro2;
   DBusConnection *connection;
   DBusMessage *dmessage;
   DBusMessageIter iter;
-  unsigned int dtype;
+  dbus_uint32_t serial;
+  unsigned int ui_serial, dtype;
   size_t i;
   char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
 
   /* Check parameters.  */
   bus = args[0];
-  serial = args[1];
   service = args[2];
 
-  CHECK_NUMBER (serial);
+  CHECK_DBUS_SERIAL_GET_SERIAL (args[1], serial);
   CHECK_STRING (service);
-  GCPRO3 (bus, serial, service);
+  GCPRO2 (bus, service);
 
-  XD_DEBUG_MESSAGE ("%"pI"u %s ", XUINT (serial), SDATA (service));
+  ui_serial = serial;
+  XD_DEBUG_MESSAGE ("%u %s ", ui_serial, SSDATA (service));
 
   /* Open a connection to the bus.  */
   connection = xd_initialize (bus, TRUE);
@@ -1394,7 +1415,7 @@
   /* Create the message.  */
   dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN);
   if ((dmessage == NULL)
-      || (!dbus_message_set_reply_serial (dmessage, XUINT (serial)))
+      || (!dbus_message_set_reply_serial (dmessage, serial))
       || (!dbus_message_set_destination (dmessage, SSDATA (service))))
     {
       UNGCPRO;
@@ -1456,25 +1477,26 @@
 usage: (dbus-method-error-internal BUS SERIAL SERVICE &rest ARGS)  */)
   (size_t nargs, register Lisp_Object *args)
 {
-  Lisp_Object bus, serial, service;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  Lisp_Object bus, service;
+  struct gcpro gcpro1, gcpro2;
   DBusConnection *connection;
   DBusMessage *dmessage;
   DBusMessageIter iter;
-  unsigned int dtype;
+  dbus_uint32_t serial;
+  unsigned int ui_serial, dtype;
   size_t i;
   char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
 
   /* Check parameters.  */
   bus = args[0];
-  serial = args[1];
   service = args[2];
 
-  CHECK_NUMBER (serial);
+  CHECK_DBUS_SERIAL_GET_SERIAL (args[1], serial);
   CHECK_STRING (service);
-  GCPRO3 (bus, serial, service);
+  GCPRO2 (bus, service);
 
-  XD_DEBUG_MESSAGE ("%"pI"u %s ", XUINT (serial), SDATA (service));
+  ui_serial = serial;
+  XD_DEBUG_MESSAGE ("%u %s ", ui_serial, SSDATA (service));
 
   /* Open a connection to the bus.  */
   connection = xd_initialize (bus, TRUE);
@@ -1483,7 +1505,7 @@
   dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
   if ((dmessage == NULL)
       || (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED))
-      || (!dbus_message_set_reply_serial (dmessage, XUINT (serial)))
+      || (!dbus_message_set_reply_serial (dmessage, serial))
       || (!dbus_message_set_destination (dmessage, SSDATA (service))))
     {
       UNGCPRO;
@@ -1663,7 +1685,9 @@
   DBusMessage *dmessage;
   DBusMessageIter iter;
   unsigned int dtype;
-  int mtype, serial;
+  int mtype;
+  dbus_uint32_t serial;
+  unsigned int ui_serial;
   const char *uname, *path, *interface, *member;
 
   dmessage = dbus_connection_pop_message (connection);
@@ -1692,7 +1716,7 @@
   /* Read message type, message serial, unique name, object path,
      interface and member from the message.  */
   mtype = dbus_message_get_type (dmessage);
-  serial =
+  ui_serial = serial =
     ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
      || (mtype == DBUS_MESSAGE_TYPE_ERROR))
     ? dbus_message_get_reply_serial (dmessage)
@@ -1702,7 +1726,7 @@
   interface = dbus_message_get_interface (dmessage);
   member = dbus_message_get_member (dmessage);
 
-  XD_DEBUG_MESSAGE ("Event received: %s %d %s %s %s %s %s",
+  XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s",
                    (mtype == DBUS_MESSAGE_TYPE_INVALID)
                    ? "DBUS_MESSAGE_TYPE_INVALID"
                    : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
@@ -1712,14 +1736,14 @@
                    : (mtype == DBUS_MESSAGE_TYPE_ERROR)
                    ? "DBUS_MESSAGE_TYPE_ERROR"
                    : "DBUS_MESSAGE_TYPE_SIGNAL",
-                   serial, uname, path, interface, member,
+                   ui_serial, uname, path, interface, member,
                    SDATA (format2 ("%s", args, Qnil)));
 
   if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
       || (mtype == DBUS_MESSAGE_TYPE_ERROR))
     {
       /* Search for a registered function of the message.  */
-      key = list2 (bus, make_number (serial));
+      key = list2 (bus, make_fixnum_or_float (serial));
       value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
 
       /* There shall be exactly one entry.  Construct an event.  */
@@ -1785,7 +1809,7 @@
                     event.arg);
   event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
                     event.arg);
-  event.arg = Fcons (make_number (serial), event.arg);
+  event.arg = Fcons (make_fixnum_or_float (serial), event.arg);
   event.arg = Fcons (make_number (mtype), event.arg);
 
   /* Add the bus symbol to the event.  */

=== modified file 'src/editfns.c'
--- a/src/editfns.c     2011-05-26 05:36:55 +0000
+++ b/src/editfns.c     2011-05-27 19:37:32 +0000
@@ -45,9 +45,11 @@
 #endif
 
 #include <ctype.h>
+#include <float.h>
 #include <limits.h>
 #include <intprops.h>
 #include <strftime.h>
+#include <verify.h>
 
 #include "intervals.h"
 #include "buffer.h"
@@ -57,13 +59,6 @@
 #include "window.h"
 #include "blockinput.h"
 
-#ifdef STDC_HEADERS
-#include <float.h>
-#define MAX_10_EXP     DBL_MAX_10_EXP
-#else
-#define MAX_10_EXP     310
-#endif
-
 #ifndef NULL
 #define NULL 0
 #endif
@@ -3525,14 +3520,21 @@
   RETURN_UNGCPRO (string);
 }
 
-
-/* Number of bytes that STRING will occupy when put into the result.
-   MULTIBYTE is nonzero if the result should be multibyte.  */
-
-#define CONVERTED_BYTE_SIZE(MULTIBYTE, STRING)                         \
-  (((MULTIBYTE) && ! STRING_MULTIBYTE (STRING))                                
\
-   ? count_size_as_multibyte (SDATA (STRING), SBYTES (STRING))         \
-   : SBYTES (STRING))
+/* pWIDE is a conversion for printing large decimal integers (possibly with a
+   trailing "d" that is ignored).  pWIDElen is its length.  signed_wide and
+   unsigned_wide are signed and unsigned types for printing them.  Use widest
+   integers if available so that more floating point values can be converted.  
*/
+#ifdef PRIdMAX
+# define pWIDE PRIdMAX
+enum { pWIDElen = sizeof PRIdMAX - 2 }; /* Don't count trailing "d".  */
+typedef intmax_t signed_wide;
+typedef uintmax_t unsigned_wide;
+#else
+# define pWIDE pI
+enum { pWIDElen = sizeof pI - 1 };
+typedef EMACS_INT signed_wide;
+typedef EMACS_UINT unsigned_wide;
+#endif
 
 DEFUN ("format", Fformat, Sformat, 1, MANY, 0,
        doc: /* Format a string out of a format-string and arguments.
@@ -3583,11 +3585,17 @@
 usage: (format STRING &rest OBJECTS)  */)
   (size_t nargs, register Lisp_Object *args)
 {
-  register size_t n;           /* The number of the next arg to substitute */
-  register size_t total;       /* An estimate of the final length */
-  char *buf, *p;
+  EMACS_INT n;         /* The number of the next arg to substitute */
+  char initial_buffer[4000];
+  char *buf = initial_buffer;
+  EMACS_INT bufsize = sizeof initial_buffer;
+  EMACS_INT max_bufsize = min (MOST_POSITIVE_FIXNUM + 1, SIZE_MAX);
+  char *p;
+  Lisp_Object buf_save_value IF_LINT (= {0});
   register char *format, *end, *format_start;
-  int nchars;
+  EMACS_INT formatlen, nchars;
+  /* Nonzero if the format is multibyte.  */
+  int multibyte_format = 0;
   /* Nonzero if the output should be a multibyte string,
      which is true if any of the inputs is one.  */
   int multibyte = 0;
@@ -3596,14 +3604,6 @@
      multibyte character of the previous string.  This flag tells if we
      must consider such a situation or not.  */
   int maybe_combine_byte;
-  char *this_format;
-  /* Precision for each spec, or -1, a flag value meaning no precision
-     was given in that spec.  Element 0, corresponding to the format
-     string itself, will not be used.  Element NARGS, corresponding to
-     no argument, *will* be assigned to in the case that a `%' and `.'
-     occur after the final format specifier.  */
-  int *precision = (int *) (alloca ((nargs + 1) * sizeof (int)));
-  int longest_format;
   Lisp_Object val;
   int arg_intervals = 0;
   USE_SAFE_ALLOCA;
@@ -3611,458 +3611,603 @@
   /* discarded[I] is 1 if byte I of the format
      string was not copied into the output.
      It is 2 if byte I was not the first byte of its character.  */
-  char *discarded = 0;
+  char *discarded;
 
   /* Each element records, for one argument,
      the start and end bytepos in the output string,
+     whether the argument has been converted to string (e.g., due to "%S"),
      and whether the argument is a string with intervals.
      info[0] is unused.  Unused elements have -1 for start.  */
   struct info
   {
-    int start, end, intervals;
+    EMACS_INT start, end;
+    int converted_to_string;
+    int intervals;
   } *info = 0;
 
   /* It should not be necessary to GCPRO ARGS, because
      the caller in the interpreter should take care of that.  */
 
+  CHECK_STRING (args[0]);
+  format_start = SSDATA (args[0]);
+  formatlen = SBYTES (args[0]);
+
+  /* Allocate the info and discarded tables.  */
+  {
+    EMACS_INT i;
+    if ((SIZE_MAX - formatlen) / sizeof (struct info) <= nargs)
+      memory_full ();
+    SAFE_ALLOCA (info, struct info *, (nargs + 1) * sizeof *info + formatlen);
+    discarded = (char *) &info[nargs + 1];
+    for (i = 0; i < nargs + 1; i++)
+      {
+       info[i].start = -1;
+       info[i].intervals = info[i].converted_to_string = 0;
+      }
+    memset (discarded, 0, formatlen);
+  }
+
   /* Try to determine whether the result should be multibyte.
      This is not always right; sometimes the result needs to be multibyte
      because of an object that we will pass through prin1,
      and in that case, we won't know it here.  */
-  for (n = 0; n < nargs; n++)
-    {
-      if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
-       multibyte = 1;
-      /* Piggyback on this loop to initialize precision[N]. */
-      precision[n] = -1;
-    }
-  precision[nargs] = -1;
-
-  CHECK_STRING (args[0]);
-  /* We may have to change "%S" to "%s". */
-  args[0] = Fcopy_sequence (args[0]);
-
-  /* GC should never happen here, so abort if it does.  */
-  abort_on_gc++;
+  multibyte_format = STRING_MULTIBYTE (args[0]);
+  multibyte = multibyte_format;
+  for (n = 1; !multibyte && n < nargs; n++)
+    if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n]))
+      multibyte = 1;
 
   /* If we start out planning a unibyte result,
-     then discover it has to be multibyte, we jump back to retry.
-     That can only happen from the first large while loop below.  */
+     then discover it has to be multibyte, we jump back to retry.  */
  retry:
 
-  format = SSDATA (args[0]);
-  format_start = format;
-  end = format + SBYTES (args[0]);
-  longest_format = 0;
-
-  /* Make room in result for all the non-%-codes in the control string.  */
-  total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]) + 1;
-
-  /* Allocate the info and discarded tables.  */
-  {
-    size_t nbytes = (nargs+1) * sizeof *info;
-    size_t i;
-    if (!info)
-      info = (struct info *) alloca (nbytes);
-    memset (info, 0, nbytes);
-    for (i = 0; i < nargs + 1; i++)
-      info[i].start = -1;
-    if (!discarded)
-      SAFE_ALLOCA (discarded, char *, SBYTES (args[0]));
-    memset (discarded, 0, SBYTES (args[0]));
-  }
-
-  /* Add to TOTAL enough space to hold the converted arguments.  */
-
-  n = 0;
-  while (format != end)
-    if (*format++ == '%')
-      {
-       EMACS_INT thissize = 0;
-       EMACS_INT actual_width = 0;
-       char *this_format_start = format - 1;
-       int field_width = 0;
-
-       /* General format specifications look like
-
-          '%' [flags] [field-width] [precision] format
-
-          where
-
-          flags        ::= [-+ #0]+
-          field-width  ::= [0-9]+
-          precision    ::= '.' [0-9]*
-
-          If a field-width is specified, it specifies to which width
-          the output should be padded with blanks, if the output
-          string is shorter than field-width.
-
-          If precision is specified, it specifies the number of
-          digits to print after the '.' for floats, or the max.
-          number of chars to print from a string.  */
-
-       while (format != end
-              && (*format == '-' || *format == '0' || *format == '#'
-                  || * format == ' ' || *format == '+'))
-         ++format;
-
-       if (*format >= '0' && *format <= '9')
-         {
-           for (field_width = 0; *format >= '0' && *format <= '9'; ++format)
-             field_width = 10 * field_width + *format - '0';
-         }
-
-       /* N is not incremented for another few lines below, so refer to
-          element N+1 (which might be precision[NARGS]). */
-       if (*format == '.')
-         {
-           ++format;
-           for (precision[n+1] = 0; *format >= '0' && *format <= '9'; ++format)
-             precision[n+1] = 10 * precision[n+1] + *format - '0';
-         }
-
-       /* Extra +1 for 'l' that we may need to insert into the
-          format.  */
-       if (format - this_format_start + 2 > longest_format)
-         longest_format = format - this_format_start + 2;
-
-       if (format == end)
-         error ("Format string ends in middle of format specifier");
-       if (*format == '%')
-         format++;
-       else if (++n >= nargs)
-         error ("Not enough arguments for format string");
-       else if (*format == 'S')
-         {
-           /* For `S', prin1 the argument and then treat like a string.  */
-           register Lisp_Object tem;
-           tem = Fprin1_to_string (args[n], Qnil);
-           if (STRING_MULTIBYTE (tem) && ! multibyte)
-             {
-               multibyte = 1;
-               goto retry;
-             }
-           args[n] = tem;
-           /* If we restart the loop, we should not come here again
-              because args[n] is now a string and calling
-              Fprin1_to_string on it produces superflous double
-              quotes.  So, change "%S" to "%s" now.  */
-           *format = 's';
-           goto string;
-         }
-       else if (SYMBOLP (args[n]))
-         {
-           args[n] = SYMBOL_NAME (args[n]);
-           if (STRING_MULTIBYTE (args[n]) && ! multibyte)
-             {
-               multibyte = 1;
-               goto retry;
-             }
-           goto string;
-         }
-       else if (STRINGP (args[n]))
-         {
-         string:
-           if (*format != 's' && *format != 'S')
-             error ("Format specifier doesn't match argument type");
-           /* In the case (PRECISION[N] > 0), THISSIZE may not need
-              to be as large as is calculated here.  Easy check for
-              the case PRECISION = 0. */
-           thissize = precision[n] ? CONVERTED_BYTE_SIZE (multibyte, args[n]) 
: 0;
-           /* The precision also constrains how much of the argument
-              string will finally appear (Bug#5710). */
-           actual_width = lisp_string_width (args[n], -1, NULL, NULL);
-           if (precision[n] != -1)
-             actual_width = min (actual_width, precision[n]);
-         }
-       /* Would get MPV otherwise, since Lisp_Int's `point' to low memory.  */
-       else if (INTEGERP (args[n]) && *format != 's')
-         {
-           /* The following loop assumes the Lisp type indicates
-              the proper way to pass the argument.
-              So make sure we have a flonum if the argument should
-              be a double.  */
-           if (*format == 'e' || *format == 'f' || *format == 'g')
-             args[n] = Ffloat (args[n]);
-           else
-             if (*format != 'd' && *format != 'o' && *format != 'x'
-                 && *format != 'i' && *format != 'X' && *format != 'c')
-               error ("Invalid format operation %%%c", *format);
-
-           thissize = 30 + (precision[n] > 0 ? precision[n] : 0);
-           if (*format == 'c')
-             {
-               if (! ASCII_CHAR_P (XINT (args[n]))
-                   /* Note: No one can remember why we have to treat
-                      the character 0 as a multibyte character here.
-                      But, until it causes a real problem, let's
-                      don't change it.  */
-                   || XINT (args[n]) == 0)
-                 {
-                   if (! multibyte)
-                     {
-                       multibyte = 1;
-                       goto retry;
-                     }
-                   args[n] = Fchar_to_string (args[n]);
-                   thissize = SBYTES (args[n]);
-                 }
-             }
-         }
-       else if (FLOATP (args[n]) && *format != 's')
-         {
-           if (! (*format == 'e' || *format == 'f' || *format == 'g'))
-             {
-               if (*format != 'd' && *format != 'o' && *format != 'x'
-                   && *format != 'i' && *format != 'X' && *format != 'c')
-                 error ("Invalid format operation %%%c", *format);
-               /* This fails unnecessarily if args[n] is bigger than
-                  most-positive-fixnum but smaller than MAXINT.
-                  These cases are important because we sometimes use floats
-                  to represent such integer values (typically such values
-                  come from UIDs or PIDs).  */
-               /* args[n] = Ftruncate (args[n], Qnil); */
-             }
-
-           /* Note that we're using sprintf to print floats,
-              so we have to take into account what that function
-              prints.  */
-           /* Filter out flag value of -1.  */
-           thissize = (MAX_10_EXP + 100
-                       + (precision[n] > 0 ? precision[n] : 0));
-         }
-       else
-         {
-           /* Anything but a string, convert to a string using princ.  */
-           register Lisp_Object tem;
-           tem = Fprin1_to_string (args[n], Qt);
-           if (STRING_MULTIBYTE (tem) && ! multibyte)
-             {
-               multibyte = 1;
-               goto retry;
-             }
-           args[n] = tem;
-           goto string;
-         }
-
-       thissize += max (0, field_width - actual_width);
-       total += thissize + 4;
-      }
-
-  abort_on_gc--;
-
-  /* Now we can no longer jump to retry.
-     TOTAL and LONGEST_FORMAT are known for certain.  */
-
-  this_format = (char *) alloca (longest_format + 1);
-
-  /* Allocate the space for the result.
-     Note that TOTAL is an overestimate.  */
-  SAFE_ALLOCA (buf, char *, total);
-
   p = buf;
   nchars = 0;
   n = 0;
 
   /* Scan the format and store result in BUF.  */
-  format = SSDATA (args[0]);
-  format_start = format;
-  end = format + SBYTES (args[0]);
+  format = format_start;
+  end = format + formatlen;
   maybe_combine_byte = 0;
+
   while (format != end)
     {
+      /* The values of N and FORMAT when the loop body is entered.  */
+      EMACS_INT n0 = n;
+      char *format0 = format;
+
+      /* Bytes needed to represent the output of this conversion.  */
+      EMACS_INT convbytes;
+
       if (*format == '%')
        {
-         int minlen;
-         int negative = 0;
-         char *this_format_start = format;
-
+         /* General format specifications look like
+
+            '%' [flags] [field-width] [precision] format
+
+            where
+
+            flags ::= [-+0# ]+
+            field-width ::= [0-9]+
+            precision ::= '.' [0-9]*
+
+            If a field-width is specified, it specifies to which width
+            the output should be padded with blanks, if the output
+            string is shorter than field-width.
+
+            If precision is specified, it specifies the number of
+            digits to print after the '.' for floats, or the max.
+            number of chars to print from a string.  */
+
+         int minus_flag = 0;
+         int  plus_flag = 0;
+         int space_flag = 0;
+         int sharp_flag = 0;
+         int  zero_flag = 0;
+         EMACS_INT field_width;
+         int precision_given;
+         uintmax_t precision = UINTMAX_MAX;
+         char *num_end;
+         char conversion;
+
+         while (1)
+           {
+             switch (*++format)
+               {
+               case '-': minus_flag = 1; continue;
+               case '+':  plus_flag = 1; continue;
+               case ' ': space_flag = 1; continue;
+               case '#': sharp_flag = 1; continue;
+               case '0':  zero_flag = 1; continue;
+               }
+             break;
+           }
+
+         /* Ignore flags when sprintf ignores them.  */
+         space_flag &= ~ plus_flag;
+         zero_flag &= ~ minus_flag;
+
+         {
+           uintmax_t w = strtoumax (format, &num_end, 10);
+           if (max_bufsize <= w)
+             string_overflow ();
+           field_width = w;
+         }
+         precision_given = *num_end == '.';
+         if (precision_given)
+           precision = strtoumax (num_end + 1, &num_end, 10);
+         format = num_end;
+
+         if (format == end)
+           error ("Format string ends in middle of format specifier");
+
+         memset (&discarded[format0 - format_start], 1, format - format0);
+         conversion = *format;
+         if (conversion == '%')
+           goto copy_char;
          discarded[format - format_start] = 1;
          format++;
 
-         while (strchr ("-+0# ", *format))
-           {
-             if (*format == '-')
-               {
-                 negative = 1;
-               }
-             discarded[format - format_start] = 1;
-             ++format;
-           }
-
-         minlen = atoi (format);
-
-         while ((*format >= '0' && *format <= '9') || *format == '.')
-           {
-             discarded[format - format_start] = 1;
-             format++;
-           }
-
-         if (*format++ == '%')
-           {
-             *p++ = '%';
-             nchars++;
-             continue;
-           }
-
          ++n;
-
-         discarded[format - format_start - 1] = 1;
-         info[n].start = nchars;
-
-         if (STRINGP (args[n]))
+         if (! (n < nargs))
+           error ("Not enough arguments for format string");
+
+         /* For 'S', prin1 the argument, and then treat like 's'.
+            For 's', princ any argument that is not a string or
+            symbol.  But don't do this conversion twice, which might
+            happen after retrying.  */
+         if ((conversion == 'S'
+              || (conversion == 's'
+                  && ! STRINGP (args[n]) && ! SYMBOLP (args[n]))))
+           {
+             if (! info[n].converted_to_string)
+               {
+                 Lisp_Object noescape = conversion == 'S' ? Qnil : Qt;
+                 args[n] = Fprin1_to_string (args[n], noescape);
+                 info[n].converted_to_string = 1;
+                 if (STRING_MULTIBYTE (args[n]) && ! multibyte)
+                   {
+                     multibyte = 1;
+                     goto retry;
+                   }
+               }
+             conversion = 's';
+           }
+         else if (conversion == 'c')
+           {
+             if (FLOATP (args[n]))
+               {
+                 double d = XFLOAT_DATA (args[n]);
+                 args[n] = make_number (FIXNUM_OVERFLOW_P (d) ? -1 : d);
+               }
+
+             if (INTEGERP (args[n]) && ! ASCII_CHAR_P (XINT (args[n])))
+               {
+                 if (!multibyte)
+                   {
+                     multibyte = 1;
+                     goto retry;
+                   }
+                 args[n] = Fchar_to_string (args[n]);
+                 info[n].converted_to_string = 1;
+               }
+
+             if (info[n].converted_to_string)
+               conversion = 's';
+             zero_flag = 0;
+           }
+
+         if (SYMBOLP (args[n]))
+           {
+             args[n] = SYMBOL_NAME (args[n]);
+             if (STRING_MULTIBYTE (args[n]) && ! multibyte)
+               {
+                 multibyte = 1;
+                 goto retry;
+               }
+           }
+
+         if (conversion == 's')
            {
              /* handle case (precision[n] >= 0) */
 
-             int width, padding;
-             EMACS_INT nbytes, start;
+             EMACS_INT width, padding, nbytes;
              EMACS_INT nchars_string;
 
+             EMACS_INT prec = -1;
+             if (precision_given && precision <= TYPE_MAXIMUM (EMACS_INT))
+               prec = precision;
+
              /* lisp_string_width ignores a precision of 0, but GNU
                 libc functions print 0 characters when the precision
                 is 0.  Imitate libc behavior here.  Changing
                 lisp_string_width is the right thing, and will be
                 done, but meanwhile we work with it. */
 
-             if (precision[n] == 0)
+             if (prec == 0)
                width = nchars_string = nbytes = 0;
-             else if (precision[n] > 0)
-               width = lisp_string_width (args[n], precision[n],
-                                          &nchars_string, &nbytes);
-             else
-               {               /* no precision spec given for this argument */
-                 width = lisp_string_width (args[n], -1, NULL, NULL);
-                 nbytes = SBYTES (args[n]);
-                 nchars_string = SCHARS (args[n]);
-               }
-
-             /* If spec requires it, pad on right with spaces.  */
-             padding = minlen - width;
-             if (! negative)
-               while (padding-- > 0)
-                 {
-                   *p++ = ' ';
-                   ++nchars;
-                 }
-
-             info[n].start = start = nchars;
-             nchars += nchars_string;
-
-             if (p > buf
-                 && multibyte
-                 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
-                 && STRING_MULTIBYTE (args[n])
-                 && !CHAR_HEAD_P (SREF (args[n], 0)))
-               maybe_combine_byte = 1;
-
-             p += copy_text (SDATA (args[n]), (unsigned char *) p,
-                             nbytes,
-                             STRING_MULTIBYTE (args[n]), multibyte);
-
-             info[n].end = nchars;
-
-             if (negative)
-               while (padding-- > 0)
-                 {
-                   *p++ = ' ';
-                   nchars++;
-                 }
-
-             /* If this argument has text properties, record where
-                in the result string it appears.  */
-             if (STRING_INTERVALS (args[n]))
-               info[n].intervals = arg_intervals = 1;
-           }
-         else if (INTEGERP (args[n]) || FLOATP (args[n]))
-           {
-             int this_nchars;
-
-             memcpy (this_format, this_format_start,
-                     format - this_format_start);
-             this_format[format - this_format_start] = 0;
-
-             if (format[-1] == 'e' || format[-1] == 'f' || format[-1] == 'g')
-               sprintf (p, this_format, XFLOAT_DATA (args[n]));
-             else
-               {
-                 if (sizeof (EMACS_INT) > sizeof (int)
-                     && format[-1] != 'c')
-                   {
-                     /* Insert 'l' before format spec.  */
-                     this_format[format - this_format_start]
-                       = this_format[format - this_format_start - 1];
-                     this_format[format - this_format_start - 1] = 'l';
-                     this_format[format - this_format_start + 1] = 0;
-                   }
-
-                 if (INTEGERP (args[n]))
-                   {
-                     if (format[-1] == 'c')
-                       sprintf (p, this_format, (int) XINT (args[n]));
-                     else if (format[-1] == 'd')
-                       sprintf (p, this_format, XINT (args[n]));
-                     /* Don't sign-extend for octal or hex printing.  */
-                     else
-                       sprintf (p, this_format, XUINT (args[n]));
-                   }
-                 else if (format[-1] == 'c')
-                   sprintf (p, this_format, (int) XFLOAT_DATA (args[n]));
-                 else if (format[-1] == 'd')
-                   /* Maybe we should use "%1.0f" instead so it also works
-                      for values larger than MAXINT.  */
-                   sprintf (p, this_format, (EMACS_INT) XFLOAT_DATA (args[n]));
-                 else
-                   /* Don't sign-extend for octal or hex printing.  */
-                   sprintf (p, this_format, (EMACS_UINT) XFLOAT_DATA 
(args[n]));
-               }
-
-             if (p > buf
-                 && multibyte
-                 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
-                 && !CHAR_HEAD_P (*((unsigned char *) p)))
-               maybe_combine_byte = 1;
-             this_nchars = strlen (p);
-             if (multibyte)
-               p += str_to_multibyte ((unsigned char *) p,
-                                      buf + total - 1 - p, this_nchars);
-             else
-               p += this_nchars;
-             nchars += this_nchars;
-             info[n].end = nchars;
-           }
-
-       }
-      else if (STRING_MULTIBYTE (args[0]))
-       {
-         /* Copy a whole multibyte character.  */
-         if (p > buf
-             && multibyte
-             && !ASCII_BYTE_P (*((unsigned char *) p - 1))
-             && !CHAR_HEAD_P (*format))
-           maybe_combine_byte = 1;
-         *p++ = *format++;
-         while (! CHAR_HEAD_P (*format))
-           {
-             discarded[format - format_start] = 2;
-             *p++ = *format++;
-           }
-         nchars++;
-       }
-      else if (multibyte)
-       {
-         /* Convert a single-byte character to multibyte.  */
-         int len = copy_text ((unsigned char *) format, (unsigned char *) p,
-                              1, 0, 1);
-
-         p += len;
-         format++;
-         nchars++;
+             else
+               {
+                 EMACS_INT nch, nby;
+                 width = lisp_string_width (args[n], prec, &nch, &nby);
+                 if (prec < 0)
+                   {
+                     nchars_string = SCHARS (args[n]);
+                     nbytes = SBYTES (args[n]);
+                   }
+                 else
+                   {
+                     nchars_string = nch;
+                     nbytes = nby;
+                   }
+               }
+
+             convbytes = nbytes;
+             if (convbytes && multibyte && ! STRING_MULTIBYTE (args[n]))
+               convbytes = count_size_as_multibyte (SDATA (args[n]), nbytes);
+
+             padding = width < field_width ? field_width - width : 0;
+
+             if (max_bufsize - padding <= convbytes)
+               string_overflow ();
+             convbytes += padding;
+             if (convbytes <= buf + bufsize - p)
+               {
+                 if (! minus_flag)
+                   {
+                     memset (p, ' ', padding);
+                     p += padding;
+                     nchars += padding;
+                   }
+
+                 if (p > buf
+                     && multibyte
+                     && !ASCII_BYTE_P (*((unsigned char *) p - 1))
+                     && STRING_MULTIBYTE (args[n])
+                     && !CHAR_HEAD_P (SREF (args[n], 0)))
+                   maybe_combine_byte = 1;
+
+                 p += copy_text (SDATA (args[n]), (unsigned char *) p,
+                                 nbytes,
+                                 STRING_MULTIBYTE (args[n]), multibyte);
+
+                  info[n].start = nchars;
+                 nchars += nchars_string;
+                 info[n].end = nchars;
+
+                 if (minus_flag)
+                   {
+                     memset (p, ' ', padding);
+                     p += padding;
+                     nchars += padding;
+                   }
+
+                 /* If this argument has text properties, record where
+                    in the result string it appears.  */
+                 if (STRING_INTERVALS (args[n]))
+                   info[n].intervals = arg_intervals = 1;
+
+                 continue;
+               }
+           }
+         else if (! (conversion == 'c' || conversion == 'd'
+                     || conversion == 'e' || conversion == 'f'
+                     || conversion == 'g' || conversion == 'i'
+                     || conversion == 'o' || conversion == 'x'
+                     || conversion == 'X'))
+           error ("Invalid format operation %%%c",
+                  STRING_CHAR ((unsigned char *) format - 1));
+         else if (! (INTEGERP (args[n]) || FLOATP (args[n])))
+           error ("Format specifier doesn't match argument type");
+         else
+           {
+             enum
+             {
+               /* Maximum precision for a %f conversion such that the
+                  trailing output digit might be nonzero.  Any precisions
+                  larger than this will not yield useful information.  */
+               USEFUL_PRECISION_MAX =
+                 ((1 - DBL_MIN_EXP)
+                  * (FLT_RADIX == 2 || FLT_RADIX == 10 ? 1
+                     : FLT_RADIX == 16 ? 4
+                     : -1)),
+
+               /* Maximum number of bytes generated by any format, if
+                  precision is no more than DBL_USEFUL_PRECISION_MAX.
+                  On all practical hosts, %f is the worst case.  */
+               SPRINTF_BUFSIZE =
+                 sizeof "-." + (DBL_MAX_10_EXP + 1) + USEFUL_PRECISION_MAX
+             };
+             verify (0 < USEFUL_PRECISION_MAX);
+
+             int prec;
+             EMACS_INT padding, sprintf_bytes;
+             uintmax_t excess_precision, numwidth;
+             uintmax_t leading_zeros = 0, trailing_zeros = 0;
+
+             char sprintf_buf[SPRINTF_BUFSIZE];
+
+             /* Copy of conversion specification, modified somewhat.
+                At most three flags F can be specified at once.  */
+             char convspec[sizeof "%FFF.*d" + pWIDElen];
+
+             /* Avoid undefined behavior in underlying sprintf.  */
+             if (conversion == 'd' || conversion == 'i')
+               sharp_flag = 0;
+
+             /* Create the copy of the conversion specification, with
+                any width and precision removed, with ".*" inserted,
+                and with pWIDE inserted for integer formats.  */
+             {
+               char *f = convspec;
+               *f++ = '%';
+               *f = '-'; f += minus_flag;
+               *f = '+'; f +=  plus_flag;
+               *f = ' '; f += space_flag;
+               *f = '#'; f += sharp_flag;
+               *f = '0'; f +=  zero_flag;
+                *f++ = '.';
+                *f++ = '*';
+               if (conversion == 'd' || conversion == 'i'
+                   || conversion == 'o' || conversion == 'x'
+                   || conversion == 'X')
+                 {
+                   memcpy (f, pWIDE, pWIDElen);
+                   f += pWIDElen;
+                   zero_flag &= ~ precision_given;
+                 }
+               *f++ = conversion;
+               *f = '\0';
+             }
+
+             prec = -1;
+             if (precision_given)
+               prec = min (precision, USEFUL_PRECISION_MAX);
+
+             /* Use sprintf to format this number into sprintf_buf.  Omit
+                padding and excess precision, though, because sprintf limits
+                output length to INT_MAX.
+
+                There are four types of conversion: double, unsigned
+                char (passed as int), wide signed int, and wide
+                unsigned int.  Treat them separately because the
+                sprintf ABI is sensitive to which type is passed.  Be
+                careful about integer overflow, NaNs, infinities, and
+                conversions; for example, the min and max macros are
+                not suitable here.  */
+             if (conversion == 'e' || conversion == 'f' || conversion == 'g')
+               {
+                 double x = (INTEGERP (args[n])
+                             ? XINT (args[n])
+                             : XFLOAT_DATA (args[n]));
+                 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
+               }
+             else if (conversion == 'c')
+               {
+                 /* Don't use sprintf here, as it might mishandle prec.  */
+                 sprintf_buf[0] = XINT (args[n]);
+                 sprintf_bytes = prec != 0;
+               }
+             else if (conversion == 'd')
+               {
+                 /* For float, maybe we should use "%1.0f"
+                    instead so it also works for values outside
+                    the integer range.  */
+                 signed_wide x;
+                 if (INTEGERP (args[n]))
+                   x = XINT (args[n]);
+                 else
+                   {
+                     double d = XFLOAT_DATA (args[n]);
+                     if (d < 0)
+                       {
+                         x = TYPE_MINIMUM (signed_wide);
+                         if (x < d)
+                           x = d;
+                       }
+                     else
+                       {
+                         x = TYPE_MAXIMUM (signed_wide);
+                         if (d < x)
+                           x = d;
+                       }
+                   }
+                 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
+               }
+             else
+               {
+                 /* Don't sign-extend for octal or hex printing.  */
+                 unsigned_wide x;
+                 if (INTEGERP (args[n]))
+                   x = XUINT (args[n]);
+                 else
+                   {
+                     double d = XFLOAT_DATA (args[n]);
+                     if (d < 0)
+                       x = 0;
+                     else
+                       {
+                         x = TYPE_MAXIMUM (unsigned_wide);
+                         if (d < x)
+                           x = d;
+                       }
+                   }
+                 sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x);
+               }
+
+             /* Now the length of the formatted item is known, except it omits
+                padding and excess precision.  Deal with excess precision
+                first.  This happens only when the format specifies
+                ridiculously large precision.  */
+             excess_precision = precision - prec;
+             if (excess_precision)
+               {
+                 if (conversion == 'e' || conversion == 'f'
+                     || conversion == 'g')
+                   {
+                     if ((conversion == 'g' && ! sharp_flag)
+                         || ! ('0' <= sprintf_buf[sprintf_bytes - 1]
+                               && sprintf_buf[sprintf_bytes - 1] <= '9'))
+                       excess_precision = 0;
+                     else
+                       {
+                         if (conversion == 'g')
+                           {
+                             char *dot = strchr (sprintf_buf, '.');
+                             if (!dot)
+                               excess_precision = 0;
+                           }
+                       }
+                     trailing_zeros = excess_precision;
+                   }
+                 else
+                   leading_zeros = excess_precision;
+               }
+
+             /* Compute the total bytes needed for this item, including
+                excess precision and padding.  */
+             numwidth = sprintf_bytes + excess_precision;
+             padding = numwidth < field_width ? field_width - numwidth : 0;
+             if (max_bufsize - sprintf_bytes <= excess_precision
+                 || max_bufsize - padding <= numwidth)
+               string_overflow ();
+             convbytes = numwidth + padding;
+
+             if (convbytes <= buf + bufsize - p)
+               {
+                 /* Copy the formatted item from sprintf_buf into buf,
+                    inserting padding and excess-precision zeros.  */
+
+                  char *src = sprintf_buf;
+                 char src0 = src[0];
+                 int exponent_bytes = 0;
+                 int signedp = src0 == '-' || src0 == '+' || src0 == ' ';
+                 int significand_bytes;
+                 if (zero_flag && '0' <= src[signedp] && src[signedp] <= '9')
+                   {
+                     leading_zeros += padding;
+                     padding = 0;
+                   }
+
+                 if (excess_precision
+                     && (conversion == 'e' || conversion == 'g'))
+                   {
+                     char *e = strchr (src, 'e');
+                     if (e)
+                       exponent_bytes = src + sprintf_bytes - e;
+                   }
+
+                 if (! minus_flag)
+                   {
+                     memset (p, ' ', padding);
+                     p += padding;
+                     nchars += padding;
+                   }
+
+                 *p = src0;
+                 src += signedp;
+                 p += signedp;
+                 memset (p, '0', leading_zeros);
+                 p += leading_zeros;
+                 significand_bytes = sprintf_bytes - signedp - exponent_bytes;
+                 memcpy (p, src, significand_bytes);
+                  p += significand_bytes;
+                 src += significand_bytes;
+                 memset (p, '0', trailing_zeros);
+                 p += trailing_zeros;
+                 memcpy (p, src, exponent_bytes);
+                 p += exponent_bytes;
+
+                  info[n].start = nchars;
+                 nchars += leading_zeros + sprintf_bytes + trailing_zeros;
+                 info[n].end = nchars;
+
+                 if (minus_flag)
+                   {
+                     memset (p, ' ', padding);
+                     p += padding;
+                     nchars += padding;
+                   }
+
+                 continue;
+               }
+           }
        }
       else
-       *p++ = *format++, nchars++;
+      copy_char:
+       {
+         /* Copy a single character from format to buf.  */
+
+         char *src = format;
+         unsigned char str[MAX_MULTIBYTE_LENGTH];
+
+         if (multibyte_format)
+           {
+             /* Copy a whole multibyte character.  */
+             if (p > buf
+                 && !ASCII_BYTE_P (*((unsigned char *) p - 1))
+                 && !CHAR_HEAD_P (*format))
+               maybe_combine_byte = 1;
+
+             do
+               format++;
+             while (! CHAR_HEAD_P (*format));
+
+             convbytes = format - format0;
+             memset (&discarded[format0 + 1 - format_start], 2, convbytes - 1);
+           }
+         else
+           {
+             unsigned char uc = *format++;
+             if (! multibyte || ASCII_BYTE_P (uc))
+               convbytes = 1;
+             else
+               {
+                 int c = BYTE8_TO_CHAR (uc);
+                 convbytes = CHAR_STRING (c, str);
+                 src = (char *) str;
+               }
+           }
+
+         if (convbytes <= buf + bufsize - p)
+           {
+             memcpy (p, src, convbytes);
+             p += convbytes;
+             nchars++;
+             continue;
+           }
+       }
+
+      /* There wasn't enough room to store this conversion or single
+        character.  CONVBYTES says how much room is needed.  Allocate
+        enough room (and then some) and do it again.  */
+      {
+       EMACS_INT used = p - buf;
+
+       if (max_bufsize - used < convbytes)
+         string_overflow ();
+       bufsize = used + convbytes;
+       bufsize = bufsize < max_bufsize / 2 ? bufsize * 2 : max_bufsize;
+
+       if (buf == initial_buffer)
+         {
+           buf = xmalloc (bufsize);
+           sa_must_free = 1;
+           buf_save_value = make_save_value (buf, 0);
+           record_unwind_protect (safe_alloca_unwind, buf_save_value);
+           memcpy (buf, initial_buffer, used);
+         }
+       else
+         XSAVE_VALUE (buf_save_value)->pointer = buf = xrealloc (buf, bufsize);
+
+       p = buf + used;
+      }
+
+      format = format0;
+      n = n0;
     }
 
-  if (p > buf + total)
+  if (bufsize < p - buf)
     abort ();
 
   if (maybe_combine_byte)
@@ -4089,7 +4234,7 @@
       if (CONSP (props))
        {
          EMACS_INT bytepos = 0, position = 0, translated = 0;
-         int argn = 1;
+         EMACS_INT argn = 1;
          Lisp_Object list;
 
          /* Adjust the bounds of each text property

=== modified file 'src/fns.c'
--- a/src/fns.c 2011-05-27 19:30:12 +0000
+++ b/src/fns.c 2011-05-27 19:37:32 +0000
@@ -898,7 +898,7 @@
   if (STRING_MULTIBYTE (string))
     return string;
 
-  nbytes = parse_str_to_multibyte (SDATA (string), SBYTES (string));
+  nbytes = count_size_as_multibyte (SDATA (string), SBYTES (string));
   /* If all the chars are ASCII, they won't need any more bytes once
      converted.  */
   if (nbytes == SBYTES (string))

=== modified file 'src/insdel.c'
--- a/src/insdel.c      2011-05-16 05:15:51 +0000
+++ b/src/insdel.c      2011-05-21 04:33:23 +0000
@@ -570,37 +570,6 @@
       return to_addr - initial_to_addr;
     }
 }
-
-/* Return the number of bytes it would take
-   to convert some single-byte text to multibyte.
-   The single-byte text consists of NBYTES bytes at PTR.  */
-
-EMACS_INT
-count_size_as_multibyte (const unsigned char *ptr, EMACS_INT nbytes)
-{
-  EMACS_INT i;
-  EMACS_INT outgoing_nbytes = 0;
-
-  for (i = 0; i < nbytes; i++)
-    {
-      unsigned int c = *ptr++;
-      int n;
-
-      if (ASCII_CHAR_P (c))
-       n = 1;
-      else
-       {
-         c = BYTE8_TO_CHAR (c);
-         n = CHAR_BYTES (c);
-       }
-
-      if (INT_ADD_OVERFLOW (outgoing_nbytes, n))
-       string_overflow ();
-      outgoing_nbytes += n;
-    }
-
-  return outgoing_nbytes;
-}
 
 /* Insert a string of specified length before point.
    This function judges multibyteness based on

=== modified file 'src/lisp.h'
--- a/src/lisp.h        2011-05-16 01:11:54 +0000
+++ b/src/lisp.h        2011-05-22 07:12:24 +0000
@@ -544,11 +544,10 @@
 
 /* Value is non-zero if I doesn't fit into a Lisp fixnum.  It is
    written this way so that it also works if I is of unsigned
-   type.  */
+   type or if I is a NaN.  */
 
 #define FIXNUM_OVERFLOW_P(i) \
-  ((i) > MOST_POSITIVE_FIXNUM \
-   || ((i) < 0 && (i) < MOST_NEGATIVE_FIXNUM))
+  (! ((0 <= (i) || MOST_NEGATIVE_FIXNUM <= (i)) && (i) <= 
MOST_POSITIVE_FIXNUM))
 
 /* Extract a value or address from a Lisp_Object.  */
 
@@ -2574,7 +2573,6 @@
 extern void make_gap (EMACS_INT);
 extern EMACS_INT copy_text (const unsigned char *, unsigned char *,
                            EMACS_INT, int, int);
-extern EMACS_INT count_size_as_multibyte (const unsigned char *, EMACS_INT);
 extern int count_combining_before (const unsigned char *,
                                   EMACS_INT, EMACS_INT, EMACS_INT);
 extern int count_combining_after (const unsigned char *,

=== modified file 'src/mem-limits.h'
--- a/src/mem-limits.h  2011-01-25 04:08:28 +0000
+++ b/src/mem-limits.h  2011-05-23 00:22:43 +0000
@@ -40,8 +40,7 @@
 #define EXCEEDS_LISP_PTR(ptr) 0
 #elif defined DATA_SEG_BITS
 #define EXCEEDS_LISP_PTR(ptr) \
-  (((EMACS_UINT) (ptr) & ~DATA_SEG_BITS) >> VALBITS)
+  (((uintptr_t) (ptr) & ~DATA_SEG_BITS) >> VALBITS)
 #else
-#define EXCEEDS_LISP_PTR(ptr) ((EMACS_UINT) (ptr) >> VALBITS)
+#define EXCEEDS_LISP_PTR(ptr) ((uintptr_t) (ptr) >> VALBITS)
 #endif
-

=== modified file 'src/print.c'
--- a/src/print.c       2011-05-12 07:07:06 +0000
+++ b/src/print.c       2011-05-21 04:33:23 +0000
@@ -381,7 +381,7 @@
          EMACS_INT bytes;
 
          chars = SBYTES (string);
-         bytes = parse_str_to_multibyte (SDATA (string), chars);
+         bytes = count_size_as_multibyte (SDATA (string), chars);
          if (chars < bytes)
            {
              newstr = make_uninit_multibyte_string (chars, bytes);


reply via email to

[Prev in Thread] Current Thread [Next in Thread]