]> git.eshelyaron.com Git - emacs.git/commitdiff
error: Print 32- and 64-bit integers portably (Bug#8435).
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 7 Apr 2011 03:34:05 +0000 (20:34 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 7 Apr 2011 03:34:05 +0000 (20:34 -0700)
Without this change, on typical 64-bit hosts error ("...%d...", N)
was used to print both 32- and 64-bit integers N, which relied on
undefined behavior.
* lisp.h, src/m/amdx86-64.h, src/m/ia64.h, src/m/ibms390x.h (pEd):
New macro.
* lisp.h (error, verror): Mark as printf-like functions.
* eval.c (verror): Use vsnprintf, not doprnt, to do the real work.
Report overflow in size calculations when allocating printf buffer.
Do not truncate output string at its first null byte.
* xdisp.c (vmessage): Use vsnprintf, not doprnt, to do the real work.
Truncate the output at a character boundary, since vsnprintf does not
do that.
* charset.c (check_iso_charset_parameter): Convert internal
character to string before calling 'error', since %c now has the
printf meaning.
* coding.c (Fdecode_sjis_char, Fdecode_big5_char): Avoid int
overflow when computing char to be passed to 'error'.  Do not
pass Lisp_Object to 'error'; pass the integer instead.
* nsfns.m (Fns_do_applescript): Use int, not long, since it's
formatted with plain %d.

17 files changed:
src/ChangeLog
src/category.c
src/charset.c
src/coding.c
src/doc.c
src/eval.c
src/fns.c
src/intervals.c
src/lisp.h
src/m/amdx86-64.h
src/m/ia64.h
src/m/ibms390x.h
src/nsfns.m
src/sysdep.c
src/window.c
src/xdisp.c
src/xfns.c

index 6f2509429d278efb0db055ddb7130c89239ab811..c1bea6b4cc785079f0cc9d2ed5f6e3abe40e42bf 100644 (file)
@@ -1,5 +1,27 @@
 2011-04-07  Paul Eggert  <eggert@cs.ucla.edu>
 
+       error: Print 32- and 64-bit integers portably (Bug#8435).
+       Without this change, on typical 64-bit hosts error ("...%d...", N)
+       was used to print both 32- and 64-bit integers N, which relied on
+       undefined behavior.
+       * lisp.h, src/m/amdx86-64.h, src/m/ia64.h, src/m/ibms390x.h (pEd):
+       New macro.
+       * lisp.h (error, verror): Mark as printf-like functions.
+       * eval.c (verror): Use vsnprintf, not doprnt, to do the real work.
+       Report overflow in size calculations when allocating printf buffer.
+       Do not truncate output string at its first null byte.
+       * xdisp.c (vmessage): Use vsnprintf, not doprnt, to do the real work.
+       Truncate the output at a character boundary, since vsnprintf does not
+       do that.
+       * charset.c (check_iso_charset_parameter): Convert internal
+       character to string before calling 'error', since %c now has the
+       printf meaning.
+       * coding.c (Fdecode_sjis_char, Fdecode_big5_char): Avoid int
+       overflow when computing char to be passed to 'error'.  Do not
+       pass Lisp_Object to 'error'; pass the integer instead.
+       * nsfns.m (Fns_do_applescript): Use int, not long, since it's
+       formatted with plain %d.
+
        * eval.c (internal_lisp_condition_case): Don't pass spurious arg.
 
        * keyboard.c (access_keymap_keyremap): Print func name, not garbage.
index cc7ff88474f9395bb9ff5136490f6ec714fc6157..bba030360c4102cac3e2e55fe0b743135e040644 100644 (file)
@@ -128,7 +128,7 @@ the current buffer's category table.  */)
   table = check_category_table (table);
 
   if (!NILP (CATEGORY_DOCSTRING (table, XFASTINT (category))))
-    error ("Category `%c' is already defined", XFASTINT (category));
+    error ("Category `%c' is already defined", (int) XFASTINT (category));
   if (!NILP (Vpurify_flag))
     docstring = Fpurecopy (docstring);
   CATEGORY_DOCSTRING (table, XFASTINT (category)) = docstring;
@@ -373,7 +373,7 @@ then delete CATEGORY from the category set instead of adding it.  */)
   table = check_category_table (table);
 
   if (NILP (CATEGORY_DOCSTRING (table, XFASTINT (category))))
-    error ("Undefined category: %c", XFASTINT (category));
+    error ("Undefined category: %c", (int) XFASTINT (category));
 
   set_value = NILP (reset) ? Qt : Qnil;
 
index 32836d459f34266e3fca95a6ea08ab9ff559429e..55cbfc4a399afff1544a92723a20b13cd94c0e5a 100644 (file)
@@ -493,7 +493,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, int co
   unbind_to (count, Qnil);
   if (fd < 0
       || ! (fp = fdopen (fd, "r")))
-    error ("Failure in loading charset map: %S", SDATA (mapfile));
+    error ("Failure in loading charset map: %s", SDATA (mapfile));
 
   /* Use SAFE_ALLOCA instead of alloca, as `charset_map_entries' is
      large (larger than MAX_ALLOCA).  */
@@ -1000,7 +1000,7 @@ usage: (define-charset-internal ...)  */)
     {
       CHECK_NUMBER (val);
       if (XINT (val) < '0' || XINT (val) > 127)
-       error ("Invalid iso-final-char: %d", XINT (val));
+       error ("Invalid iso-final-char: %"pEd, XINT (val));
       charset.iso_final = XINT (val);
     }
 
@@ -1022,7 +1022,7 @@ usage: (define-charset-internal ...)  */)
     {
       CHECK_NATNUM (val);
       if ((XINT (val) > 0 && XINT (val) <= 128) || XINT (val) >= 256)
-       error ("Invalid emacs-mule-id: %d", XINT (val));
+       error ("Invalid emacs-mule-id: %"pEd, XINT (val));
       charset.emacs_mule_id = XINT (val);
     }
 
@@ -1440,11 +1440,17 @@ check_iso_charset_parameter (Lisp_Object dimension, Lisp_Object chars, Lisp_Obje
   CHECK_NATNUM (final_char);
 
   if (XINT (dimension) > 3)
-    error ("Invalid DIMENSION %d, it should be 1, 2, or 3", XINT (dimension));
+    error ("Invalid DIMENSION %"pEd", it should be 1, 2, or 3",
+          XINT (dimension));
   if (XINT (chars) != 94 && XINT (chars) != 96)
-    error ("Invalid CHARS %d, it should be 94 or 96", XINT (chars));
+    error ("Invalid CHARS %"pEd", it should be 94 or 96", XINT (chars));
   if (XINT (final_char) < '0' || XINT (final_char) > '~')
-    error ("Invalid FINAL-CHAR %c, it should be `0'..`~'", XINT (chars));
+    {
+      unsigned char str[MAX_MULTIBYTE_LENGTH + 1];
+      int len = CHAR_STRING (XINT (chars), str);
+      str[len] = '\0';
+      error ("Invalid FINAL-CHAR %s, it should be `0'..`~'", str);
+    }
 }
 
 
index 798e5c533f67cfba75cdb71e63cd817924019610..f099605c774b263549d5956141531d58e6ab2779 100644 (file)
@@ -9023,14 +9023,15 @@ Return the corresponding character.  */)
 {
   Lisp_Object spec, attrs, val;
   struct charset *charset_roman, *charset_kanji, *charset_kana, *charset;
-  EMACS_INT c;
+  EMACS_INT ch;
+  int c;
 
   CHECK_NATNUM (code);
-  c = XFASTINT (code);
+  ch = XFASTINT (code);
   CHECK_CODING_SYSTEM_GET_SPEC (Vsjis_coding_system, spec);
   attrs = AREF (spec, 0);
 
-  if (ASCII_BYTE_P (c)
+  if (ASCII_BYTE_P (ch)
       && ! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
     return code;
 
@@ -9039,27 +9040,31 @@ Return the corresponding character.  */)
   charset_kana = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
   charset_kanji = CHARSET_FROM_ID (XINT (XCAR (val)));
 
-  if (c <= 0x7F)
-    charset = charset_roman;
-  else if (c >= 0xA0 && c < 0xDF)
+  if (ch <= 0x7F)
+    {
+      c = ch;
+      charset = charset_roman;
+    }
+  else if (ch >= 0xA0 && ch < 0xDF)
     {
+      c = ch - 0x80;
       charset = charset_kana;
-      c -= 0x80;
     }
   else
     {
-      EMACS_INT c1 = c >> 8;
-      int c2 = c & 0xFF;
+      EMACS_INT c1 = ch >> 8;
+      int c2 = ch & 0xFF;
 
       if (c1 < 0x81 || (c1 > 0x9F && c1 < 0xE0) || c1 > 0xEF
          || c2 < 0x40 || c2 == 0x7F || c2 > 0xFC)
-       error ("Invalid code: %d", code);
+       error ("Invalid code: %"pEd, ch);
+      c = ch;
       SJIS_TO_JIS (c);
       charset = charset_kanji;
     }
   c = DECODE_CHAR (charset, c);
   if (c < 0)
-    error ("Invalid code: %d", code);
+    error ("Invalid code: %"pEd, ch);
   return make_number (c);
 }
 
@@ -9099,14 +9104,15 @@ Return the corresponding character.  */)
 {
   Lisp_Object spec, attrs, val;
   struct charset *charset_roman, *charset_big5, *charset;
+  EMACS_INT ch;
   int c;
 
   CHECK_NATNUM (code);
-  c = XFASTINT (code);
+  ch = XFASTINT (code);
   CHECK_CODING_SYSTEM_GET_SPEC (Vbig5_coding_system, spec);
   attrs = AREF (spec, 0);
 
-  if (ASCII_BYTE_P (c)
+  if (ASCII_BYTE_P (ch)
       && ! NILP (CODING_ATTR_ASCII_COMPAT (attrs)))
     return code;
 
@@ -9114,19 +9120,24 @@ Return the corresponding character.  */)
   charset_roman = CHARSET_FROM_ID (XINT (XCAR (val))), val = XCDR (val);
   charset_big5 = CHARSET_FROM_ID (XINT (XCAR (val)));
 
-  if (c <= 0x7F)
-    charset = charset_roman;
+  if (ch <= 0x7F)
+    {
+      c = ch;
+      charset = charset_roman;
+    }
   else
     {
-      int b1 = c >> 8, b2 = c & 0x7F;
+      EMACS_INT b1 = ch >> 8;
+      int b2 = ch & 0x7F;
       if (b1 < 0xA1 || b1 > 0xFE
          || b2 < 0x40 || (b2 > 0x7E && b2 < 0xA1) || b2 > 0xFE)
-       error ("Invalid code: %d", code);
+       error ("Invalid code: %"pEd, ch);
+      c = ch;
       charset = charset_big5;
     }
-  c = DECODE_CHAR (charset, (unsigned )c);
+  c = DECODE_CHAR (charset, c);
   if (c < 0)
-    error ("Invalid code: %d", code);
+    error ("Invalid code: %"pEd, ch);
   return make_number (c);
 }
 
@@ -9298,7 +9309,7 @@ usage: (find-operation-coding-system OPERATION ARGUMENTS...)  */)
        || (EQ (operation, Qinsert_file_contents) && CONSP (target)
            && STRINGP (XCAR (target)) && BUFFERP (XCDR (target)))
        || (EQ (operation, Qopen_network_stream) && INTEGERP (target))))
-    error ("Invalid %dth argument", XFASTINT (target_idx) + 1);
+    error ("Invalid %"pEd"th argument", XFASTINT (target_idx) + 1);
   if (CONSP (target))
     target = XCAR (target);
 
@@ -9774,7 +9785,7 @@ usage: (define-coding-system-internal ...)  */)
          CHECK_CHARSET_GET_ID (tmp1, id);
          CHECK_NATNUM_CDR (val);
          if (XINT (XCDR (val)) >= 4)
-           error ("Invalid graphic register number: %d", XINT (XCDR (val)));
+           error ("Invalid graphic register number: %"pEd, XINT (XCDR (val)));
          XSETCAR (val, make_number (id));
        }
 
index 158b09790f7f114eb04d65e3ea063cdc5ae15c2d..ed0d2323ed5de49621597de7a4490d08959c9c0f 100644 (file)
--- a/src/doc.c
+++ b/src/doc.c
@@ -154,7 +154,7 @@ get_doc_string (Lisp_Object filepos, int unibyte, int definition)
   if (0 > lseek (fd, position - offset, 0))
     {
       emacs_close (fd);
-      error ("Position %ld out of range in doc string file \"%s\"",
+      error ("Position %"pEd" out of range in doc string file \"%s\"",
             position, name);
     }
 
@@ -669,7 +669,7 @@ the same file name is found in the `doc-directory'.  */)
                ; /* Just a source file name boundary marker.  Ignore it.  */
 
              else
-               error ("DOC file invalid at position %d", pos);
+               error ("DOC file invalid at position %"pEd, pos);
            }
        }
       pos += end - buf;
index 8b029967e7a016276bd7c55b387d9eb695d4fa27..77411a911ee82c682574ba8626079bcd41a70bb4 100644 (file)
@@ -1977,21 +1977,26 @@ void
 verror (const char *m, va_list ap)
 {
   char buf[200];
-  EMACS_INT size = 200;
-  int mlen;
+  size_t size = sizeof buf;
+  size_t size_max = (size_t) -1;
   char *buffer = buf;
   int allocated = 0;
+  int used;
   Lisp_Object string;
 
-  mlen = strlen (m);
-
   while (1)
     {
-      EMACS_INT used;
-      used = doprnt (buffer, size, m, m + mlen, ap);
+      used = vsnprintf (buffer, size, m, ap);
+      if (used < 0)
+       used = 0;
       if (used < size)
        break;
-      size *= 2;
+      if (size <= size_max / 2)
+       size *= 2;
+      else if (size < size_max)
+       size = size_max;
+      else
+       memory_full ();
       if (allocated)
        buffer = (char *) xrealloc (buffer, size);
       else
@@ -2001,7 +2006,7 @@ verror (const char *m, va_list ap)
        }
     }
 
-  string = build_string (buffer);
+  string = make_string (buffer, used);
   if (allocated)
     xfree (buffer);
 
index c45d9e31ef27ecd45df81c50396e2e70754003df..09ce8c1b597ec8077fdb9102b66bc673e9dc620a 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1076,7 +1076,7 @@ an error is signaled.  */)
       EMACS_INT converted = str_to_unibyte (SDATA (string), str, chars, 0);
 
       if (converted < chars)
-       error ("Can't convert the %dth character to unibyte", converted);
+       error ("Can't convert the %"pEd"th character to unibyte", converted);
       string = make_unibyte_string ((char *) str, chars);
       xfree (str);
     }
index 729e6810f74f0d4e5997238869ed2edf25959600..952f826778c2816f360176ac0eea25c2973cf73d 100644 (file)
@@ -777,7 +777,7 @@ update_interval (register INTERVAL i, EMACS_INT pos)
              i = i->right;             /* Move to the right child */
            }
          else if (NULL_PARENT (i))
-           error ("Point %d after end of properties", pos);
+           error ("Point %"pEd" after end of properties", pos);
          else
             i = INTERVAL_PARENT (i);
          continue;
index 41a64d2f47d0b2ced3807185f28a4b3d0b1e79f3..7999fb42d5fb10fec54da162c4896f88f27c20f1 100644 (file)
@@ -38,6 +38,7 @@ extern void check_cons_list (void);
 #ifndef EMACS_INT
 #define EMACS_INT long
 #define BITS_PER_EMACS_INT BITS_PER_LONG
+#define pEd "ld"
 #endif
 #ifndef EMACS_UINT
 #define EMACS_UINT unsigned long
@@ -46,6 +47,7 @@ extern void check_cons_list (void);
 #ifndef EMACS_INT
 #define EMACS_INT int
 #define BITS_PER_EMACS_INT BITS_PER_INT
+#define pEd "d"
 #endif
 #ifndef EMACS_UINT
 #define EMACS_UINT unsigned int
@@ -2872,8 +2874,9 @@ extern Lisp_Object internal_condition_case_n (Lisp_Object (*) (size_t, Lisp_Obje
 extern void specbind (Lisp_Object, Lisp_Object);
 extern void record_unwind_protect (Lisp_Object (*) (Lisp_Object), Lisp_Object);
 extern Lisp_Object unbind_to (int, Lisp_Object);
-extern void error (const char *, ...) NO_RETURN;
-extern void verror (const char *, va_list) NO_RETURN;
+extern void error (const char *, ...) NO_RETURN ATTRIBUTE_FORMAT_PRINTF (1, 2);
+extern void verror (const char *, va_list)
+  NO_RETURN ATTRIBUTE_FORMAT_PRINTF (1, 0);
 extern void do_autoload (Lisp_Object, Lisp_Object);
 extern Lisp_Object un_autoload (Lisp_Object);
 EXFUN (Ffetch_bytecode, 1);
index 441f41b4444bbabc9cebb67ea232364451ec0829..dbca9b5b8381f7a2907ce77c19038789e2635ad5 100644 (file)
@@ -28,6 +28,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Define the type to use.  */
 #define EMACS_INT               long
+#define pEd                    "ld"
 #define EMACS_UINT              unsigned long
 
 /* Define XPNTR to avoid or'ing with DATA_SEG_BITS */
index 101d56e648b65fdf71b23b1813c723ad3cfaf2a1..a1374d7c224646de8fd5ef5e573f06746192284f 100644 (file)
@@ -28,6 +28,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Define the type to use.  */
 #define EMACS_INT              long
+#define pEd                    "ld"
 #define EMACS_UINT             unsigned long
 
 #ifdef REL_ALLOC
index d4ef5c291efb84f1b62a31382e6c2ed0645d09ca..14228b61e56462af631b8a24e6d3eeaa888439f2 100644 (file)
@@ -24,6 +24,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Define the type to use.  */
 #define EMACS_INT long
+#define pEd "ld"
 #define EMACS_UINT unsigned long
 
 /* On the 64 bit architecture, we can use 60 bits for addresses */
@@ -31,4 +32,3 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Define XPNTR to avoid or'ing with DATA_SEG_BITS */
 #define XPNTR(a) XUINT (a)
-
index 6a5adbd7bf3857451ef01eff7d30dc7b218c5de0..d4445d1d62764bf73bfb98088fc2d80abd974b1a 100644 (file)
@@ -483,7 +483,7 @@ ns_set_name_internal (FRAME_PTR f, Lisp_Object name)
   if (!STRINGP (f->icon_name))
     encoded_icon_name = encoded_name;
   else
-    encoded_icon_name = ENCODE_UTF_8 (f->icon_name);    
+    encoded_icon_name = ENCODE_UTF_8 (f->icon_name);
 
   str = [NSString stringWithUTF8String: SDATA (encoded_icon_name)];
 
@@ -637,7 +637,7 @@ ns_set_name_as_filename (struct frame *f)
 
   if (FRAME_ICONIFIED_P (f))
     [[view window] setMiniwindowTitle: str];
-  else 
+  else
     {
       NSString *fstr;
 
@@ -1021,8 +1021,8 @@ frame_parm_handler ns_frame_parm_handlers[] =
   0,  /* x_set_fullscreen will ignore */
   x_set_font_backend, /* generic OK */
   x_set_alpha,
-  0, /* x_set_sticky */  
-  0, /* x_set_tool_bar_position */  
+  0, /* x_set_sticky */
+  0, /* x_set_tool_bar_position */
 };
 
 
@@ -2044,7 +2044,7 @@ In case the execution fails, an error is signaled. */)
      (Lisp_Object script)
 {
   Lisp_Object result;
-  long status;
+  int status;
 
   CHECK_STRING (script);
   check_ns ();
@@ -2330,7 +2330,7 @@ If omitted or nil, that stands for the selected frame's display.  */)
 {
   struct ns_display_info *dpyinfo;
   check_ns ();
-  
+
   dpyinfo = check_ns_display_info (display);
   /* We force 24+ bit depths to 24-bit to prevent an overflow.  */
   return make_number (1 << min (dpyinfo->n_planes, 24));
@@ -2373,7 +2373,7 @@ compute_tip_xy (struct frame *f,
       pt.y = x_display_pixel_height (FRAME_NS_DISPLAY_INFO (f)) - XINT (top)
         - height;
     }
-  
+
   /* Ensure in bounds.  (Note, screen origin = lower left.) */
   if (INTEGERP (left))
     *root_x = pt.x;
@@ -2655,4 +2655,3 @@ be used as the image of the icon representing the frame.  */);
   check_window_system_func = check_ns;
 
 }
-
index a165a9ca52f9d330996dd4ae574350f7bc850530..f4f767dac3f28c3e7b2100cd10c8728b5e208327 100644 (file)
@@ -2361,7 +2361,8 @@ serial_configure (struct Lisp_Process *p,
   CHECK_NUMBER (tem);
   err = cfsetspeed (&attr, XINT (tem));
   if (err != 0)
-    error ("cfsetspeed(%d) failed: %s", XINT (tem), emacs_strerror (errno));
+    error ("cfsetspeed(%"pEd") failed: %s", XINT (tem),
+          emacs_strerror (errno));
   childp2 = Fplist_put (childp2, QCspeed, tem);
 
   /* Configure bytesize.  */
index 5ca46dd3316f3b28befb88c84450317e67d0d2c9..ebfd1b0f778907f0a23094f74257e3eb69e7d5fd 100644 (file)
@@ -3804,7 +3804,7 @@ See Info node `(elisp)Splitting Windows' for more details and examples.  */)
        error ("Window height %d too small (after splitting)", size_int);
       if (size_int + window_safe_height > XFASTINT (o->total_lines))
        error ("Window height %d too small (after splitting)",
-              XFASTINT (o->total_lines) - size_int);
+              (int) (XFASTINT (o->total_lines) - size_int));
       if (NILP (o->parent)
          || NILP (XWINDOW (o->parent)->vchild))
        {
@@ -3821,7 +3821,7 @@ See Info node `(elisp)Splitting Windows' for more details and examples.  */)
        error ("Window width %d too small (after splitting)", size_int);
       if (size_int + window_safe_width > XFASTINT (o->total_cols))
        error ("Window width %d too small (after splitting)",
-              XFASTINT (o->total_cols) - size_int);
+              (int) (XFASTINT (o->total_cols) - size_int));
       if (NILP (o->parent)
          || NILP (XWINDOW (o->parent)->hchild))
        {
index 16954d0f809b742c55ec03a9e068fd42e1419cc6..a296fb33a9f5c7d51d6064c2d90758ec6b1d2e46 100644 (file)
@@ -8407,10 +8407,18 @@ vmessage (const char *m, va_list ap)
        {
          if (m)
            {
-             EMACS_INT len;
-
-             len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
+             char *buf = FRAME_MESSAGE_BUF (f);
+             size_t bufsize = FRAME_MESSAGE_BUF_SIZE (f);
+             int len = vsnprintf (buf, bufsize, m, ap);
+             if (len < 0)
+               len = 0;
+
+             /* Do any truncation at a character boundary.  */
+             if (0 < bufsize && bufsize <= len)
+               for (len = bufsize - 1;
+                    len && ! CHAR_HEAD_P (buf[len - 1]);
+                    len--)
+                 continue;
 
              message2 (FRAME_MESSAGE_BUF (f), len, 0);
            }
index 8e5639681dfb74df1ce4a465fdfae640e3a5131c..04b8e44b5610f5a1acc312569f95bd534a7bce1f 100644 (file)
@@ -215,7 +215,7 @@ check_x_display_info (Lisp_Object object)
       struct terminal *t = get_terminal (object, 1);
 
       if (t->type != output_x_window)
-        error ("Terminal %d is not an X display", XINT (object));
+        error ("Terminal %"pEd" is not an X display", XINT (object));
 
       dpyinfo = t->display_info.x;
     }