* lread.c (read_escape): Check for hex character overflow.
[bpt/emacs.git] / src / lread.c
index a6da09c..a2f78f8 100644 (file)
@@ -24,6 +24,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <errno.h>
+#include <limits.h>    /* for CHAR_BIT */
 #include <setjmp.h>
 #include "lisp.h"
 #include "intervals.h"
@@ -119,9 +120,9 @@ static EMACS_INT readchar_count;
 /* This contains the last string skipped with #@.  */
 static char *saved_doc_string;
 /* Length of buffer allocated in saved_doc_string.  */
-static int saved_doc_string_size;
+static ptrdiff_t saved_doc_string_size;
 /* Length of actual data in saved_doc_string.  */
-static int saved_doc_string_length;
+static ptrdiff_t saved_doc_string_length;
 /* This is the file position that string came from.  */
 static file_offset saved_doc_string_position;
 
@@ -130,9 +131,9 @@ static file_offset saved_doc_string_position;
    is put in saved_doc_string.  */
 static char *prev_saved_doc_string;
 /* Length of buffer allocated in prev_saved_doc_string.  */
-static int prev_saved_doc_string_size;
+static ptrdiff_t prev_saved_doc_string_size;
 /* Length of actual data in prev_saved_doc_string.  */
-static int prev_saved_doc_string_length;
+static ptrdiff_t prev_saved_doc_string_length;
 /* This is the file position that string came from.  */
 static file_offset prev_saved_doc_string_position;
 
@@ -157,7 +158,7 @@ static void readevalloop (Lisp_Object, FILE*, Lisp_Object, int,
 static Lisp_Object load_unwind (Lisp_Object);
 static Lisp_Object load_descriptor_unwind (Lisp_Object);
 
-static void invalid_syntax (const char *, int) NO_RETURN;
+static void invalid_syntax (const char *) NO_RETURN;
 static void end_of_file_error (void) NO_RETURN;
 
 \f
@@ -1202,12 +1203,15 @@ Return t if the file exists and loads successfully.  */)
 #ifdef DOS_NT
          fmode = "rb";
 #endif /* DOS_NT */
-         stat (SSDATA (efound), &s1);
-         SSET (efound, SBYTES (efound) - 1, 0);
-         result = stat (SSDATA (efound), &s2);
-         SSET (efound, SBYTES (efound) - 1, 'c');
+         result = stat (SSDATA (efound), &s1);
+         if (result == 0)
+           {
+             SSET (efound, SBYTES (efound) - 1, 0);
+             result = stat (SSDATA (efound), &s2);
+             SSET (efound, SBYTES (efound) - 1, 'c');
+           }
 
-         if (result >= 0 && (unsigned) s1.st_mtime < (unsigned) s2.st_mtime)
+         if (result == 0 && s1.st_mtime < s2.st_mtime)
            {
              /* Make the progress messages mention that source is newer.  */
              newer = 1;
@@ -2010,11 +2014,9 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
    S is error string of length N (if > 0)  */
 
 static void
-invalid_syntax (const char *s, int n)
+invalid_syntax (const char *s)
 {
-  if (!n)
-    n = strlen (s);
-  xsignal1 (Qinvalid_read_syntax, make_string (s, n));
+  xsignal1 (Qinvalid_read_syntax, build_string (s));
 }
 
 
@@ -2206,6 +2208,8 @@ read_escape (Lisp_Object readcharfun, int stringp)
                UNREAD (c);
                break;
              }
+           if (MAX_CHAR < i)
+             error ("Hex character out of range: \\x%x...", i);
            count++;
          }
 
@@ -2234,10 +2238,7 @@ read_escape (Lisp_Object readcharfun, int stringp)
            else if (c >= 'a' && c <= 'f')  i = (i << 4) + (c - 'a') + 10;
             else if (c >= 'A' && c <= 'F')  i = (i << 4) + (c - 'A') + 10;
            else
-             {
-               error ("Non-hex digit used for Unicode escape");
-               break;
-             }
+             error ("Non-hex digit used for Unicode escape");
          }
        if (i > 0x10FFFF)
          error ("Non-Unicode character: 0x%x", i);
@@ -2332,7 +2333,7 @@ read_integer (Lisp_Object readcharfun, int radix)
   if (! valid)
     {
       sprintf (buf, "integer, radix %d", radix);
-      invalid_syntax (buf, 0);
+      invalid_syntax (buf);
     }
 
   return string_to_number (buf, radix, 0);
@@ -2449,7 +2450,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
              return ht;
            }
          UNREAD (c);
-         invalid_syntax ("#", 1);
+         invalid_syntax ("#");
        }
       if (c == '^')
        {
@@ -2483,9 +2484,9 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                  XSETPVECTYPE (XVECTOR (tmp), PVEC_SUB_CHAR_TABLE);
                  return tmp;
                }
-             invalid_syntax ("#^^", 3);
+             invalid_syntax ("#^^");
            }
-         invalid_syntax ("#^", 2);
+         invalid_syntax ("#^");
        }
       if (c == '&')
        {
@@ -2509,7 +2510,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                         version.  */
                      && ! (XFASTINT (length)
                            == (SCHARS (tmp) - 1) * BOOL_VECTOR_BITS_PER_CHAR)))
-               invalid_syntax ("#&...", 5);
+               invalid_syntax ("#&...");
 
              val = Fmake_bool_vector (length, Qnil);
              memcpy (XBOOL_VECTOR (val)->data, SDATA (tmp), size_in_chars);
@@ -2519,7 +2520,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                  &= (1 << (XINT (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
              return val;
            }
-         invalid_syntax ("#&...", 5);
+         invalid_syntax ("#&...");
        }
       if (c == '[')
        {
@@ -2539,7 +2540,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
          /* Read the string itself.  */
          tmp = read1 (readcharfun, &ch, 0);
          if (ch != 0 || !STRINGP (tmp))
-           invalid_syntax ("#", 1);
+           invalid_syntax ("#");
          GCPRO1 (tmp);
          /* Read the intervals and their properties.  */
          while (1)
@@ -2555,7 +2556,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
              if (ch == 0)
                plist = read1 (readcharfun, &ch, 0);
              if (ch)
-               invalid_syntax ("Invalid string property list", 0);
+               invalid_syntax ("Invalid string property list");
              Fset_text_properties (beg, end, plist, tmp);
            }
          UNGCPRO;
@@ -2567,13 +2568,16 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
         and function definitions.  */
       if (c == '@')
        {
-         int i, nskip = 0;
+         enum { extra = 100 };
+         ptrdiff_t i, nskip = 0;
 
          load_each_byte = 1;
          /* Read a decimal integer.  */
          while ((c = READCHAR) >= 0
                 && c >= '0' && c <= '9')
            {
+             if ((STRING_BYTES_BOUND - extra) / 10 <= nskip)
+               string_overflow ();
              nskip *= 10;
              nskip += c - '0';
            }
@@ -2592,9 +2596,9 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
                 with prev_saved_doc_string, so we save two strings.  */
              {
                char *temp = saved_doc_string;
-               int temp_size = saved_doc_string_size;
+               ptrdiff_t temp_size = saved_doc_string_size;
                file_offset temp_pos = saved_doc_string_position;
-               int temp_len = saved_doc_string_length;
+               ptrdiff_t temp_len = saved_doc_string_length;
 
                saved_doc_string = prev_saved_doc_string;
                saved_doc_string_size = prev_saved_doc_string_size;
@@ -2609,12 +2613,12 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
 
              if (saved_doc_string_size == 0)
                {
-                 saved_doc_string_size = nskip + 100;
+                 saved_doc_string_size = nskip + extra;
                  saved_doc_string = (char *) xmalloc (saved_doc_string_size);
                }
              if (nskip > saved_doc_string_size)
                {
-                 saved_doc_string_size = nskip + 100;
+                 saved_doc_string_size = nskip + extra;
                  saved_doc_string = (char *) xrealloc (saved_doc_string,
                                                        saved_doc_string_size);
                }
@@ -2712,7 +2716,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
        return read_integer (readcharfun, 2);
 
       UNREAD (c);
-      invalid_syntax ("#", 1);
+      invalid_syntax ("#");
 
     case ';':
       while ((c = READCHAR) >= 0 && c != '\n');
@@ -2829,7 +2833,7 @@ read1 (register Lisp_Object readcharfun, int *pch, int first_in_list)
        if (ok)
          return make_number (c);
 
-       invalid_syntax ("?", 1);
+       invalid_syntax ("?");
       }
 
     case '"':
@@ -3331,7 +3335,7 @@ string_to_number (char const *string, int base, int ignore_trailing)
          /* Unfortunately there's no simple and accurate way to convert
             non-base-10 numbers that are out of C-language range.  */
          if (base != 10)
-           xsignal (Qoverflow_error, list1 (build_string (string)));
+           xsignal1 (Qoverflow_error, build_string (string));
        }
       else if (n <= (negative ? -MOST_NEGATIVE_FIXNUM : MOST_POSITIVE_FIXNUM))
        {
@@ -3497,7 +3501,7 @@ read_list (int flag, register Lisp_Object readcharfun)
            {
              if (ch == ']')
                return val;
-             invalid_syntax (") or . in a vector", 18);
+             invalid_syntax (") or . in a vector");
            }
          if (ch == ')')
            return val;
@@ -3526,7 +3530,7 @@ read_list (int flag, register Lisp_Object readcharfun)
                         doc string, caller must make it
                         multibyte.  */
 
-                     int pos = XINT (XCDR (val));
+                     EMACS_INT pos = XINT (XCDR (val));
                      /* Position is negative for user variables.  */
                      if (pos < 0) pos = -pos;
                      if (pos >= saved_doc_string_position
@@ -3599,9 +3603,9 @@ read_list (int flag, register Lisp_Object readcharfun)
 
                  return val;
                }
-             invalid_syntax (". in wrong context", 18);
+             invalid_syntax (". in wrong context");
            }
-         invalid_syntax ("] in a list", 11);
+         invalid_syntax ("] in a list");
        }
       tem = (read_pure && flag <= 0
             ? pure_cons (elt, Qnil)
@@ -3648,7 +3652,7 @@ Lisp_Object
 intern (const char *str)
 {
   Lisp_Object tem;
-  int len = strlen (str);
+  ptrdiff_t len = strlen (str);
   Lisp_Object obarray;
 
   obarray = Vobarray;
@@ -3664,7 +3668,7 @@ Lisp_Object
 intern_c_string (const char *str)
 {
   Lisp_Object tem;
-  int len = strlen (str);
+  ptrdiff_t len = strlen (str);
   Lisp_Object obarray;
 
   obarray = Vobarray;