diff options
| author | Stefan Monnier | 2019-07-02 18:02:51 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2019-07-02 18:02:51 -0400 |
| commit | fe3676fe18577643d9d247db2e6c32691f3acf80 (patch) | |
| tree | 638a1ef4ce2f7a82aea4929d81463affc111351d | |
| parent | c136f93dfad1a55c653e844d3cf25f804744275e (diff) | |
| download | emacs-fe3676fe18577643d9d247db2e6c32691f3acf80.tar.gz emacs-fe3676fe18577643d9d247db2e6c32691f3acf80.zip | |
(Finsert_file_contents): Keep buffer consistent in non-local exit
* src/fileio.c (decide_coding_unwind): Delete function.
(Finsert_file_contents): Don't let invalid multibyte byte sequences
escape when we exit non-locally.
* test/src/fileio-tests.el (fileio-tests--insert-file-interrupt): New test.
| -rw-r--r-- | src/fileio.c | 65 | ||||
| -rw-r--r-- | test/src/fileio-tests.el | 19 |
2 files changed, 41 insertions, 43 deletions
diff --git a/src/fileio.c b/src/fileio.c index fc938ebe1fa..2825c1b54c6 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -3459,42 +3459,6 @@ otherwise, if FILE2 does not exist, the answer is t. */) | |||
| 3459 | 3459 | ||
| 3460 | enum { READ_BUF_SIZE = MAX_ALLOCA }; | 3460 | enum { READ_BUF_SIZE = MAX_ALLOCA }; |
| 3461 | 3461 | ||
| 3462 | /* This function is called after Lisp functions to decide a coding | ||
| 3463 | system are called, or when they cause an error. Before they are | ||
| 3464 | called, the current buffer is set unibyte and it contains only a | ||
| 3465 | newly inserted text (thus the buffer was empty before the | ||
| 3466 | insertion). | ||
| 3467 | |||
| 3468 | The functions may set markers, overlays, text properties, or even | ||
| 3469 | alter the buffer contents, change the current buffer. | ||
| 3470 | |||
| 3471 | Here, we reset all those changes by: | ||
| 3472 | o set back the current buffer. | ||
| 3473 | o move all markers and overlays to BEG. | ||
| 3474 | o remove all text properties. | ||
| 3475 | o set back the buffer multibyteness. */ | ||
| 3476 | |||
| 3477 | static void | ||
| 3478 | decide_coding_unwind (Lisp_Object unwind_data) | ||
| 3479 | { | ||
| 3480 | Lisp_Object multibyte, undo_list, buffer; | ||
| 3481 | |||
| 3482 | multibyte = XCAR (unwind_data); | ||
| 3483 | unwind_data = XCDR (unwind_data); | ||
| 3484 | undo_list = XCAR (unwind_data); | ||
| 3485 | buffer = XCDR (unwind_data); | ||
| 3486 | |||
| 3487 | set_buffer_internal (XBUFFER (buffer)); | ||
| 3488 | adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE); | ||
| 3489 | adjust_overlays_for_delete (BEG, Z - BEG); | ||
| 3490 | set_buffer_intervals (current_buffer, NULL); | ||
| 3491 | TEMP_SET_PT_BOTH (BEG, BEG_BYTE); | ||
| 3492 | |||
| 3493 | /* Now we are safe to change the buffer's multibyteness directly. */ | ||
| 3494 | bset_enable_multibyte_characters (current_buffer, multibyte); | ||
| 3495 | bset_undo_list (current_buffer, undo_list); | ||
| 3496 | } | ||
| 3497 | |||
| 3498 | /* Read from a non-regular file. Return the number of bytes read. */ | 3462 | /* Read from a non-regular file. Return the number of bytes read. */ |
| 3499 | 3463 | ||
| 3500 | union read_non_regular | 3464 | union read_non_regular |
| @@ -4457,15 +4421,14 @@ by calling `format-decode', which see. */) | |||
| 4457 | enable-multibyte-characters directly here without taking | 4421 | enable-multibyte-characters directly here without taking |
| 4458 | care of marker adjustment. By this way, we can run Lisp | 4422 | care of marker adjustment. By this way, we can run Lisp |
| 4459 | program safely before decoding the inserted text. */ | 4423 | program safely before decoding the inserted text. */ |
| 4460 | Lisp_Object unwind_data; | 4424 | Lisp_Object multibyte |
| 4425 | = BVAR (current_buffer, enable_multibyte_characters); | ||
| 4426 | Lisp_Object undo_list = BVAR (current_buffer, undo_list); | ||
| 4461 | ptrdiff_t count1 = SPECPDL_INDEX (); | 4427 | ptrdiff_t count1 = SPECPDL_INDEX (); |
| 4462 | 4428 | ||
| 4463 | unwind_data = Fcons (BVAR (current_buffer, enable_multibyte_characters), | ||
| 4464 | Fcons (BVAR (current_buffer, undo_list), | ||
| 4465 | Fcurrent_buffer ())); | ||
| 4466 | bset_enable_multibyte_characters (current_buffer, Qnil); | 4429 | bset_enable_multibyte_characters (current_buffer, Qnil); |
| 4467 | bset_undo_list (current_buffer, Qt); | 4430 | bset_undo_list (current_buffer, Qt); |
| 4468 | record_unwind_protect (decide_coding_unwind, unwind_data); | 4431 | record_unwind_protect (restore_buffer, Fcurrent_buffer ()); |
| 4469 | 4432 | ||
| 4470 | if (inserted > 0 && ! NILP (Vset_auto_coding_function)) | 4433 | if (inserted > 0 && ! NILP (Vset_auto_coding_function)) |
| 4471 | { | 4434 | { |
| @@ -4484,8 +4447,24 @@ by calling `format-decode', which see. */) | |||
| 4484 | coding_system = XCAR (coding_system); | 4447 | coding_system = XCAR (coding_system); |
| 4485 | } | 4448 | } |
| 4486 | unbind_to (count1, Qnil); | 4449 | unbind_to (count1, Qnil); |
| 4487 | inserted = Z_BYTE - BEG_BYTE; | 4450 | /* We're about to "delete" the text by moving it back into the gap |
| 4488 | } | 4451 | (right before calling decode_coding_gap). |
| 4452 | So move markers that set-auto-coding might have created to BEG, | ||
| 4453 | just in case. */ | ||
| 4454 | adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE); | ||
| 4455 | adjust_overlays_for_delete (BEG, Z - BEG); | ||
| 4456 | set_buffer_intervals (current_buffer, NULL); | ||
| 4457 | TEMP_SET_PT_BOTH (BEG, BEG_BYTE); | ||
| 4458 | |||
| 4459 | /* Change the buffer's multibyteness directly. We used to do this | ||
| 4460 | from within unbind_to, but it was unsafe since the bytes | ||
| 4461 | may contain invalid sequences for a multibyte buffer (which is OK | ||
| 4462 | here since we'll decode them before anyone else gets to see | ||
| 4463 | them, but is dangerous when we're doing a non-local exit). */ | ||
| 4464 | bset_enable_multibyte_characters (current_buffer, multibyte); | ||
| 4465 | bset_undo_list (current_buffer, undo_list); | ||
| 4466 | inserted = Z_BYTE - BEG_BYTE; | ||
| 4467 | } | ||
| 4489 | 4468 | ||
| 4490 | if (NILP (coding_system)) | 4469 | if (NILP (coding_system)) |
| 4491 | coding_system = Qundecided; | 4470 | coding_system = Qundecided; |
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el index 6262d946df1..bd827e5498f 100644 --- a/test/src/fileio-tests.el +++ b/test/src/fileio-tests.el | |||
| @@ -107,3 +107,22 @@ Also check that an encoding error can appear in a symlink." | |||
| 107 | (setenv "HOME" "x:foo") | 107 | (setenv "HOME" "x:foo") |
| 108 | (should (equal (expand-file-name "~/bar") "x:/foo/bar"))) | 108 | (should (equal (expand-file-name "~/bar") "x:/foo/bar"))) |
| 109 | (setenv "HOME" old-home))) | 109 | (setenv "HOME" old-home))) |
| 110 | |||
| 111 | (ert-deftest fileio-tests--insert-file-interrupt () | ||
| 112 | (let ((text "-*- coding: binary -*-\n\xc3\xc3help") | ||
| 113 | f) | ||
| 114 | (unwind-protect | ||
| 115 | (progn | ||
| 116 | (setq f (make-temp-file "ftifi")) | ||
| 117 | (write-region text nil f nil 'silent) | ||
| 118 | (with-temp-buffer | ||
| 119 | (catch 'toto | ||
| 120 | (let ((set-auto-coding-function (lambda (&rest _) (throw 'toto nil)))) | ||
| 121 | (insert-file-contents f))) | ||
| 122 | (goto-char (point-min)) | ||
| 123 | (forward-line 1) | ||
| 124 | (let ((c1 (char-after))) | ||
| 125 | (forward-char 1) | ||
| 126 | (should (equal c1 (char-before))) | ||
| 127 | (should (equal c1 (char-after)))))) | ||
| 128 | (if f (delete-file f))))) | ||