Commit fe3676fe authored by Stefan Monnier's avatar Stefan Monnier

(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.
parent c136f93d
Pipeline #2230 failed with stage
in 54 minutes and 38 seconds
......@@ -3459,42 +3459,6 @@ otherwise, if FILE2 does not exist, the answer is t. */)
/* 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
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);
/* 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);
/* 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;
......@@ -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")
(setq f (make-temp-file "ftifi"))
(write-region text nil f nil 'silent)
(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)))))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment