diff options
| author | Paul Eggert | 2017-07-07 18:12:16 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-07-07 18:54:42 -0700 |
| commit | b8ead34f5df92b771520f4d090ff6cde49ca5705 (patch) | |
| tree | dcd9a862148a1814ba6598f635b22d1e35ec82da | |
| parent | 1628305811247bd652099dad92f6498fc244d8dc (diff) | |
| download | emacs-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.c | 100 |
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. */ |
| 104 | static Lisp_Object read_objects_completed; | 104 | static 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 |
| 107 | static FILE *instream; | 107 | to read from. Used by Fload. */ |
| 108 | static 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!!) */ |
| 110 | static ptrdiff_t read_from_string_index; | 122 | static ptrdiff_t read_from_string_index; |
| @@ -149,7 +161,7 @@ static Lisp_Object Vloads_in_progress; | |||
| 149 | static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), | 161 | static int read_emacs_mule_char (int, int (*) (int, Lisp_Object), |
| 150 | Lisp_Object); | 162 | Lisp_Object); |
| 151 | 163 | ||
| 152 | static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool, | 164 | static 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 | ||
| 460 | static int | 474 | static int |
| 461 | readbyte_from_file (int c, Lisp_Object readcharfun) | 475 | readbyte_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 | ||
| 488 | static int | 500 | static int |
| 501 | readbyte_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 | |||
| 513 | static int | ||
| 489 | readbyte_from_string (int c, Lisp_Object readcharfun) | 514 | readbyte_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 | ||
| 1052 | static void | ||
| 1053 | close_infile_unwind (void *arg) | ||
| 1054 | { | ||
| 1055 | FILE *stream = arg; | ||
| 1056 | eassert (infile->stream == stream); | ||
| 1057 | infile = NULL; | ||
| 1058 | fclose (stream); | ||
| 1059 | } | ||
| 1060 | |||
| 1029 | DEFUN ("load", Fload, Sload, 1, 5, 0, | 1061 | DEFUN ("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. |
| 1031 | First try FILE with `.elc' appended, then try with `.el', then try | 1063 | First 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 | ||
| 1812 | static void | 1848 | static void |
| 1813 | readevalloop (Lisp_Object readcharfun, | 1849 | readevalloop (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 | ||