summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2019-07-02 18:02:51 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2019-07-02 18:02:51 -0400
commitfe3676fe18577643d9d247db2e6c32691f3acf80 (patch)
tree638a1ef4ce2f7a82aea4929d81463affc111351d
parentc136f93dfad1a55c653e844d3cf25f804744275e (diff)
downloademacs-fe3676fe18577643d9d247db2e6c32691f3acf80.tar.gz
(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.c65
-rw-r--r--test/src/fileio-tests.el19
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. */)
enum { READ_BUF_SIZE = MAX_ALLOCA };
-/* This function is called after Lisp functions to decide a coding
- system are called, or when they cause an error. Before they are
- called, the current buffer is set unibyte and it contains only a
- newly inserted text (thus the buffer was empty before the
- insertion).
-
- The functions may set markers, overlays, text properties, or even
- alter the buffer contents, change the current buffer.
-
- Here, we reset all those changes by:
- o set back the current buffer.
- o move all markers and overlays to BEG.
- o remove all text properties.
- o set back the buffer multibyteness. */
-
-static void
-decide_coding_unwind (Lisp_Object unwind_data)
-{
- Lisp_Object multibyte, undo_list, buffer;
-
- multibyte = XCAR (unwind_data);
- unwind_data = XCDR (unwind_data);
- undo_list = XCAR (unwind_data);
- buffer = XCDR (unwind_data);
-
- set_buffer_internal (XBUFFER (buffer));
- adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE);
- adjust_overlays_for_delete (BEG, Z - BEG);
- set_buffer_intervals (current_buffer, NULL);
- TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
-
- /* Now we are safe to change the buffer's multibyteness directly. */
- bset_enable_multibyte_characters (current_buffer, multibyte);
- bset_undo_list (current_buffer, undo_list);
-}
-
/* Read from a non-regular file. Return the number of bytes read. */
union read_non_regular
@@ -4457,15 +4421,14 @@ by calling `format-decode', which see. */)
enable-multibyte-characters directly here without taking
care of marker adjustment. By this way, we can run Lisp
program safely before decoding the inserted text. */
- Lisp_Object unwind_data;
+ Lisp_Object multibyte
+ = BVAR (current_buffer, enable_multibyte_characters);
+ Lisp_Object undo_list = BVAR (current_buffer, undo_list);
ptrdiff_t count1 = SPECPDL_INDEX ();
- unwind_data = Fcons (BVAR (current_buffer, enable_multibyte_characters),
- Fcons (BVAR (current_buffer, undo_list),
- Fcurrent_buffer ()));
bset_enable_multibyte_characters (current_buffer, Qnil);
bset_undo_list (current_buffer, Qt);
- record_unwind_protect (decide_coding_unwind, unwind_data);
+ record_unwind_protect (restore_buffer, Fcurrent_buffer ());
if (inserted > 0 && ! NILP (Vset_auto_coding_function))
{
@@ -4484,8 +4447,24 @@ by calling `format-decode', which see. */)
coding_system = XCAR (coding_system);
}
unbind_to (count1, Qnil);
- inserted = Z_BYTE - BEG_BYTE;
- }
+ /* We're about to "delete" the text by moving it back into the gap
+ (right before calling decode_coding_gap).
+ So move markers that set-auto-coding might have created to BEG,
+ just in case. */
+ adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE);
+ adjust_overlays_for_delete (BEG, Z - BEG);
+ set_buffer_intervals (current_buffer, NULL);
+ TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+
+ /* Change the buffer's multibyteness directly. We used to do this
+ from within unbind_to, but it was unsafe since the bytes
+ may contain invalid sequences for a multibyte buffer (which is OK
+ here since we'll decode them before anyone else gets to see
+ them, but is dangerous when we're doing a non-local exit). */
+ bset_enable_multibyte_characters (current_buffer, multibyte);
+ bset_undo_list (current_buffer, undo_list);
+ inserted = Z_BYTE - BEG_BYTE;
+ }
if (NILP (coding_system))
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."
(setenv "HOME" "x:foo")
(should (equal (expand-file-name "~/bar") "x:/foo/bar")))
(setenv "HOME" old-home)))
+
+(ert-deftest fileio-tests--insert-file-interrupt ()
+ (let ((text "-*- coding: binary -*-\n\xc3\xc3help")
+ f)
+ (unwind-protect
+ (progn
+ (setq f (make-temp-file "ftifi"))
+ (write-region text nil f nil 'silent)
+ (with-temp-buffer
+ (catch 'toto
+ (let ((set-auto-coding-function (lambda (&rest _) (throw 'toto nil))))
+ (insert-file-contents f)))
+ (goto-char (point-min))
+ (forward-line 1)
+ (let ((c1 (char-after)))
+ (forward-char 1)
+ (should (equal c1 (char-before)))
+ (should (equal c1 (char-after))))))
+ (if f (delete-file f)))))