aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2017-07-07 18:12:16 -0700
committerPaul Eggert2017-07-07 18:54:42 -0700
commitb8ead34f5df92b771520f4d090ff6cde49ca5705 (patch)
treedcd9a862148a1814ba6598f635b22d1e35ec82da
parent1628305811247bd652099dad92f6498fc244d8dc (diff)
downloademacs-b8ead34f5df92b771520f4d090ff6cde49ca5705.tar.gz
emacs-b8ead34f5df92b771520f4d090ff6cde49ca5705.zip
Fix more ungetc bugs with encoding errors
* src/lread.c (infile): New variable, replacing ... (instream): ... this. All uses changed. (readbyte_from_stdio): New function, which deals with lookahead. (readbyte_from_file, Fget_file_char): Use it. (Fget_file_char): When misused, signal an error instead of relying on undefined behavior. (close_infile_unwind): New function. (Fload): Use it. (readevalloop): 2nd arg is now struct infile *, not FILE *. All callers changed. (read1): Handle lookahead when copying doc strings with encoding errors.
-rw-r--r--src/lread.c100
1 files changed, 71 insertions, 29 deletions
diff --git a/src/lread.c b/src/lread.c
index 44eaf13996a..8e7cd3c5510 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -103,8 +103,20 @@ static Lisp_Object read_objects_map;
103 (to reduce allocations), or nil. */ 103 (to reduce allocations), or nil. */
104static Lisp_Object read_objects_completed; 104static Lisp_Object read_objects_completed;
105 105
106/* File for get_file_char to read from. Use by load. */ 106/* File and lookahead for get-file-char and get-emacs-mule-file-char
107static FILE *instream; 107 to read from. Used by Fload. */
108static struct infile
109{
110 /* The input stream. */
111 FILE *stream;
112
113 /* Lookahead byte count. */
114 signed char lookahead;
115
116 /* Lookahead bytes, in reverse order. Keep these here because it is
117 not portable to ungetc more than one byte at a time. */
118 unsigned char buf[MAX_MULTIBYTE_LENGTH - 1];
119} *infile;
108 120
109/* For use within read-from-string (this reader is non-reentrant!!) */ 121/* For use within read-from-string (this reader is non-reentrant!!) */
110static ptrdiff_t read_from_string_index; 122static ptrdiff_t read_from_string_index;
@@ -149,7 +161,7 @@ static Lisp_Object Vloads_in_progress;
149static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), 161static int read_emacs_mule_char (int, int (*) (int, Lisp_Object),
150 Lisp_Object); 162 Lisp_Object);
151 163
152static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool, 164static void readevalloop (Lisp_Object, struct infile *, Lisp_Object, bool,
153 Lisp_Object, Lisp_Object, 165 Lisp_Object, Lisp_Object,
154 Lisp_Object, Lisp_Object); 166 Lisp_Object, Lisp_Object);
155 167
@@ -361,8 +373,9 @@ skip_dyn_bytes (Lisp_Object readcharfun, ptrdiff_t n)
361 if (FROM_FILE_P (readcharfun)) 373 if (FROM_FILE_P (readcharfun))
362 { 374 {
363 block_input (); /* FIXME: Not sure if it's needed. */ 375 block_input (); /* FIXME: Not sure if it's needed. */
364 fseek (instream, n, SEEK_CUR); 376 fseek (infile->stream, n - infile->lookahead, SEEK_CUR);
365 unblock_input (); 377 unblock_input ();
378 infile->lookahead = 0;
366 } 379 }
367 else 380 else
368 { /* We're not reading directly from a file. In that case, it's difficult 381 { /* We're not reading directly from a file. In that case, it's difficult
@@ -384,8 +397,9 @@ skip_dyn_eof (Lisp_Object readcharfun)
384 if (FROM_FILE_P (readcharfun)) 397 if (FROM_FILE_P (readcharfun))
385 { 398 {
386 block_input (); /* FIXME: Not sure if it's needed. */ 399 block_input (); /* FIXME: Not sure if it's needed. */
387 fseek (instream, 0, SEEK_END); 400 fseek (infile->stream, 0, SEEK_END);
388 unblock_input (); 401 unblock_input ();
402 infile->lookahead = 0;
389 } 403 }
390 else 404 else
391 while (READCHAR >= 0); 405 while (READCHAR >= 0);
@@ -458,15 +472,13 @@ readbyte_for_lambda (int c, Lisp_Object readcharfun)
458 472
459 473
460static int 474static int
461readbyte_from_file (int c, Lisp_Object readcharfun) 475readbyte_from_stdio (void)
462{ 476{
463 if (c >= 0) 477 if (infile->lookahead)
464 { 478 return infile->buf[--infile->lookahead];
465 block_input (); 479
466 ungetc (c, instream); 480 int c;
467 unblock_input (); 481 FILE *instream = infile->stream;
468 return 0;
469 }
470 482
471 block_input (); 483 block_input ();
472 484
@@ -486,6 +498,19 @@ readbyte_from_file (int c, Lisp_Object readcharfun)
486} 498}
487 499
488static int 500static int
501readbyte_from_file (int c, Lisp_Object readcharfun)
502{
503 if (c >= 0)
504 {
505 eassert (infile->lookahead < sizeof infile->buf);
506 infile->buf[infile->lookahead++] = c;
507 return 0;
508 }
509
510 return readbyte_from_stdio ();
511}
512
513static int
489readbyte_from_string (int c, Lisp_Object readcharfun) 514readbyte_from_string (int c, Lisp_Object readcharfun)
490{ 515{
491 Lisp_Object string = XCAR (readcharfun); 516 Lisp_Object string = XCAR (readcharfun);
@@ -507,7 +532,7 @@ readbyte_from_string (int c, Lisp_Object readcharfun)
507} 532}
508 533
509 534
510/* Read one non-ASCII character from INSTREAM. The character is 535/* Read one non-ASCII character from INFILE. The character is
511 encoded in `emacs-mule' and the first byte is already read in 536 encoded in `emacs-mule' and the first byte is already read in
512 C. */ 537 C. */
513 538
@@ -777,11 +802,9 @@ DEFUN ("get-file-char", Fget_file_char, Sget_file_char, 0, 0, 0,
777 doc: /* Don't use this yourself. */) 802 doc: /* Don't use this yourself. */)
778 (void) 803 (void)
779{ 804{
780 register Lisp_Object val; 805 if (!infile)
781 block_input (); 806 error ("get-file-char misused");
782 XSETINT (val, getc_unlocked (instream)); 807 return make_number (readbyte_from_stdio ());
783 unblock_input ();
784 return val;
785} 808}
786 809
787 810
@@ -1026,6 +1049,15 @@ suffix_p (Lisp_Object string, const char *suffix)
1026 return string_len >= suffix_len && !strcmp (SSDATA (string) + string_len - suffix_len, suffix); 1049 return string_len >= suffix_len && !strcmp (SSDATA (string) + string_len - suffix_len, suffix);
1027} 1050}
1028 1051
1052static void
1053close_infile_unwind (void *arg)
1054{
1055 FILE *stream = arg;
1056 eassert (infile->stream == stream);
1057 infile = NULL;
1058 fclose (stream);
1059}
1060
1029DEFUN ("load", Fload, Sload, 1, 5, 0, 1061DEFUN ("load", Fload, Sload, 1, 5, 0,
1030 doc: /* Execute a file of Lisp code named FILE. 1062 doc: /* Execute a file of Lisp code named FILE.
1031First try FILE with `.elc' appended, then try with `.el', then try 1063First try FILE with `.elc' appended, then try with `.el', then try
@@ -1345,7 +1377,7 @@ Return t if the file exists and loads successfully. */)
1345 } 1377 }
1346 if (! stream) 1378 if (! stream)
1347 report_file_error ("Opening stdio stream", file); 1379 report_file_error ("Opening stdio stream", file);
1348 set_unwind_protect_ptr (fd_index, fclose_unwind, stream); 1380 set_unwind_protect_ptr (fd_index, close_infile_unwind, stream);
1349 1381
1350 if (! NILP (Vpurify_flag)) 1382 if (! NILP (Vpurify_flag))
1351 Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); 1383 Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list);
@@ -1368,19 +1400,23 @@ Return t if the file exists and loads successfully. */)
1368 specbind (Qinhibit_file_name_operation, Qnil); 1400 specbind (Qinhibit_file_name_operation, Qnil);
1369 specbind (Qload_in_progress, Qt); 1401 specbind (Qload_in_progress, Qt);
1370 1402
1371 instream = stream; 1403 struct infile input;
1404 input.stream = stream;
1405 input.lookahead = 0;
1406 infile = &input;
1407
1372 if (lisp_file_lexically_bound_p (Qget_file_char)) 1408 if (lisp_file_lexically_bound_p (Qget_file_char))
1373 Fset (Qlexical_binding, Qt); 1409 Fset (Qlexical_binding, Qt);
1374 1410
1375 if (! version || version >= 22) 1411 if (! version || version >= 22)
1376 readevalloop (Qget_file_char, stream, hist_file_name, 1412 readevalloop (Qget_file_char, &input, hist_file_name,
1377 0, Qnil, Qnil, Qnil, Qnil); 1413 0, Qnil, Qnil, Qnil, Qnil);
1378 else 1414 else
1379 { 1415 {
1380 /* We can't handle a file which was compiled with 1416 /* We can't handle a file which was compiled with
1381 byte-compile-dynamic by older version of Emacs. */ 1417 byte-compile-dynamic by older version of Emacs. */
1382 specbind (Qload_force_doc_strings, Qt); 1418 specbind (Qload_force_doc_strings, Qt);
1383 readevalloop (Qget_emacs_mule_file_char, stream, hist_file_name, 1419 readevalloop (Qget_emacs_mule_file_char, &input, hist_file_name,
1384 0, Qnil, Qnil, Qnil, Qnil); 1420 0, Qnil, Qnil, Qnil, Qnil);
1385 } 1421 }
1386 unbind_to (count, Qnil); 1422 unbind_to (count, Qnil);
@@ -1811,7 +1847,7 @@ readevalloop_eager_expand_eval (Lisp_Object val, Lisp_Object macroexpand)
1811 1847
1812static void 1848static void
1813readevalloop (Lisp_Object readcharfun, 1849readevalloop (Lisp_Object readcharfun,
1814 FILE *stream, 1850 struct infile *infile0,
1815 Lisp_Object sourcename, 1851 Lisp_Object sourcename,
1816 bool printflag, 1852 bool printflag,
1817 Lisp_Object unibyte, Lisp_Object readfun, 1853 Lisp_Object unibyte, Lisp_Object readfun,
@@ -1911,7 +1947,7 @@ readevalloop (Lisp_Object readcharfun,
1911 if (b && first_sexp) 1947 if (b && first_sexp)
1912 whole_buffer = (BUF_PT (b) == BUF_BEG (b) && BUF_ZV (b) == BUF_Z (b)); 1948 whole_buffer = (BUF_PT (b) == BUF_BEG (b) && BUF_ZV (b) == BUF_Z (b));
1913 1949
1914 instream = stream; 1950 infile = infile0;
1915 read_next: 1951 read_next:
1916 c = READCHAR; 1952 c = READCHAR;
1917 if (c == ';') 1953 if (c == ';')
@@ -2001,7 +2037,7 @@ readevalloop (Lisp_Object readcharfun,
2001 } 2037 }
2002 2038
2003 build_load_history (sourcename, 2039 build_load_history (sourcename,
2004 stream || whole_buffer); 2040 infile0 || whole_buffer);
2005 2041
2006 unbind_to (count, Qnil); 2042 unbind_to (count, Qnil);
2007} 2043}
@@ -2941,11 +2977,17 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
2941 saved_doc_string_size = nskip + extra; 2977 saved_doc_string_size = nskip + extra;
2942 } 2978 }
2943 2979
2944 saved_doc_string_position = file_tell (instream); 2980 FILE *instream = infile->stream;
2981 saved_doc_string_position = (file_tell (instream)
2982 - infile->lookahead);
2945 2983
2946 /* Copy that many characters into saved_doc_string. */ 2984 /* Copy that many bytes into saved_doc_string. */
2985 i = 0;
2986 for (int n = min (nskip, infile->lookahead); 0 < n; n--)
2987 saved_doc_string[i++]
2988 = c = infile->buf[--infile->lookahead];
2947 block_input (); 2989 block_input ();
2948 for (i = 0; i < nskip && c >= 0; i++) 2990 for (; i < nskip && 0 <= c; i++)
2949 saved_doc_string[i] = c = getc_unlocked (instream); 2991 saved_doc_string[i] = c = getc_unlocked (instream);
2950 unblock_input (); 2992 unblock_input ();
2951 2993