aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Monnier2019-07-09 17:04:07 -0400
committerStefan Monnier2019-07-09 17:04:24 -0400
commitfec111c9ee7a248ac49ba1d6d62d3ef9473b7af9 (patch)
treec88f33a33fbd4bba52c7b0e8310dcdfc99591065 /src
parent4c619758b2806ee6607af7b1d56943e547001e7a (diff)
downloademacs-fec111c9ee7a248ac49ba1d6d62d3ef9473b7af9.tar.gz
emacs-fec111c9ee7a248ac49ba1d6d62d3ef9473b7af9.zip
* src/fileio.c: Fix bug#36431
(decide_coding_unwind): Re-introduce. Move text back to the gap. Return the new `inserted` via the unwind_data. (Finsert_file_contents): Use it. Make sure `inserted` is always 0 when we jump straight to `notfound`. Don't insert the text in the buffer until we know it's properly decoded for the byteness of the buffer. * test/src/fileio-tests.el (fileio-tests--insert-file-interrupt): Allow insert-file-contents to return an empty buffer in case of non-local exit in set-auto-coding-function.
Diffstat (limited to 'src')
-rw-r--r--src/fileio.c119
1 files changed, 89 insertions, 30 deletions
diff --git a/src/fileio.c b/src/fileio.c
index cce49c43b2e..614c0f989da 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3474,6 +3474,67 @@ otherwise, if FILE2 does not exist, the answer is t. */)
3474 3474
3475enum { READ_BUF_SIZE = MAX_ALLOCA }; 3475enum { READ_BUF_SIZE = MAX_ALLOCA };
3476 3476
3477/* This function is called after Lisp functions to decide a coding
3478 system are called, or when they cause an error. Before they are
3479 called, the current buffer is set unibyte and it contains only a
3480 newly inserted text (thus the buffer was empty before the
3481 insertion).
3482
3483 The functions may set markers, overlays, text properties, or even
3484 alter the buffer contents, change the current buffer.
3485
3486 Here, we reset all those changes by:
3487 o set back the current buffer.
3488 o move all markers and overlays to BEG.
3489 o remove all text properties.
3490 o set back the buffer multibyteness. */
3491
3492static void
3493decide_coding_unwind (Lisp_Object unwind_data)
3494{
3495 Lisp_Object multibyte = XCAR (unwind_data);
3496 Lisp_Object tmp = XCDR (unwind_data);
3497 Lisp_Object undo_list = XCAR (tmp);
3498 Lisp_Object buffer = XCDR (tmp);
3499
3500 set_buffer_internal (XBUFFER (buffer));
3501
3502 /* We're about to "delete" the text by moving it back into the gap.
3503 So move markers that set-auto-coding might have created to BEG,
3504 just in case. */
3505 adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE);
3506 adjust_overlays_for_delete (BEG, Z - BEG);
3507 set_buffer_intervals (current_buffer, NULL);
3508 TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
3509
3510 /* In case of a non-local exit from set_auto_coding_function, in order not
3511 to end up with potentially invalid byte sequences in a multibyte buffer,
3512 we have the following options:
3513 1- decode the bytes in some arbitrary coding-system.
3514 2- erase the buffer.
3515 3- leave the buffer unibyte (which is actually the same as option (1)
3516 where the coding-system is `raw-text-unix`).
3517 Here we choose 2. */
3518
3519 /* Move the bytes back to (the beginning of) the gap.
3520 In general this may have to move all the bytes, but here
3521 this can't move more bytes than were moved during the execution
3522 of Vset_auto_coding_function, which is normally 0 (because it
3523 normally doesn't modify the buffer). */
3524 move_gap_both (Z, Z_BYTE);
3525 ptrdiff_t inserted = Z_BYTE - BEG_BYTE;
3526 GAP_SIZE += inserted;
3527 ZV = Z = GPT = BEG;
3528 ZV_BYTE = Z_BYTE = GPT_BYTE = BEG_BYTE;
3529
3530 /* Pass the new `inserted` back. */
3531 XSETCAR (unwind_data, make_fixnum (inserted));
3532
3533 /* Now we are safe to change the buffer's multibyteness directly. */
3534 bset_enable_multibyte_characters (current_buffer, multibyte);
3535 bset_undo_list (current_buffer, undo_list);
3536}
3537
3477/* Read from a non-regular file. Return the number of bytes read. */ 3538/* Read from a non-regular file. Return the number of bytes read. */
3478 3539
3479union read_non_regular 3540union read_non_regular
@@ -3720,6 +3781,7 @@ by calling `format-decode', which see. */)
3720 CHECK_CODING_SYSTEM (Vcoding_system_for_read); 3781 CHECK_CODING_SYSTEM (Vcoding_system_for_read);
3721 Fset (Qbuffer_file_coding_system, Vcoding_system_for_read); 3782 Fset (Qbuffer_file_coding_system, Vcoding_system_for_read);
3722 } 3783 }
3784 eassert (inserted == 0);
3723 goto notfound; 3785 goto notfound;
3724 } 3786 }
3725 3787
@@ -3746,7 +3808,10 @@ by calling `format-decode', which see. */)
3746 not_regular = 1; 3808 not_regular = 1;
3747 3809
3748 if (! NILP (visit)) 3810 if (! NILP (visit))
3749 goto notfound; 3811 {
3812 eassert (inserted == 0);
3813 goto notfound;
3814 }
3750 3815
3751 if (! NILP (replace) || ! NILP (beg) || ! NILP (end)) 3816 if (! NILP (replace) || ! NILP (beg) || ! NILP (end))
3752 xsignal2 (Qfile_error, 3817 xsignal2 (Qfile_error,
@@ -4414,9 +4479,6 @@ by calling `format-decode', which see. */)
4414 if (how_much < 0) 4479 if (how_much < 0)
4415 report_file_error ("Read error", orig_filename); 4480 report_file_error ("Read error", orig_filename);
4416 4481
4417 /* Make the text read part of the buffer. */
4418 insert_from_gap_1 (inserted, inserted, false);
4419
4420 notfound: 4482 notfound:
4421 4483
4422 if (NILP (coding_system)) 4484 if (NILP (coding_system))
@@ -4426,6 +4488,7 @@ by calling `format-decode', which see. */)
4426 4488
4427 Note that we can get here only if the buffer was empty 4489 Note that we can get here only if the buffer was empty
4428 before the insertion. */ 4490 before the insertion. */
4491 eassert (Z == BEG);
4429 4492
4430 if (!NILP (Vcoding_system_for_read)) 4493 if (!NILP (Vcoding_system_for_read))
4431 coding_system = Vcoding_system_for_read; 4494 coding_system = Vcoding_system_for_read;
@@ -4438,12 +4501,18 @@ by calling `format-decode', which see. */)
4438 program safely before decoding the inserted text. */ 4501 program safely before decoding the inserted text. */
4439 Lisp_Object multibyte 4502 Lisp_Object multibyte
4440 = BVAR (current_buffer, enable_multibyte_characters); 4503 = BVAR (current_buffer, enable_multibyte_characters);
4441 Lisp_Object undo_list = BVAR (current_buffer, undo_list); 4504 Lisp_Object unwind_data
4505 = Fcons (multibyte,
4506 Fcons (BVAR (current_buffer, undo_list),
4507 Fcurrent_buffer ()));
4442 ptrdiff_t count1 = SPECPDL_INDEX (); 4508 ptrdiff_t count1 = SPECPDL_INDEX ();
4443 4509
4444 bset_enable_multibyte_characters (current_buffer, Qnil); 4510 bset_enable_multibyte_characters (current_buffer, Qnil);
4445 bset_undo_list (current_buffer, Qt); 4511 bset_undo_list (current_buffer, Qt);
4446 record_unwind_protect (restore_buffer, Fcurrent_buffer ()); 4512 record_unwind_protect (decide_coding_unwind, unwind_data);
4513
4514 /* Make the text read part of the buffer. */
4515 insert_from_gap_1 (inserted, inserted, false);
4447 4516
4448 if (inserted > 0 && ! NILP (Vset_auto_coding_function)) 4517 if (inserted > 0 && ! NILP (Vset_auto_coding_function))
4449 { 4518 {
@@ -4461,24 +4530,9 @@ by calling `format-decode', which see. */)
4461 if (CONSP (coding_system)) 4530 if (CONSP (coding_system))
4462 coding_system = XCAR (coding_system); 4531 coding_system = XCAR (coding_system);
4463 } 4532 }
4533 /* Move the text back to the gap. */
4464 unbind_to (count1, Qnil); 4534 unbind_to (count1, Qnil);
4465 /* We're about to "delete" the text by moving it back into the gap 4535 inserted = XFIXNUM (XCAR (unwind_data));
4466 (right before calling decode_coding_gap).
4467 So move markers that set-auto-coding might have created to BEG,
4468 just in case. */
4469 adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE);
4470 adjust_overlays_for_delete (BEG, Z - BEG);
4471 set_buffer_intervals (current_buffer, NULL);
4472 TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
4473
4474 /* Change the buffer's multibyteness directly. We used to do this
4475 from within unbind_to, but it was unsafe since the bytes
4476 may contain invalid sequences for a multibyte buffer (which is OK
4477 here since we'll decode them before anyone else gets to see
4478 them, but is dangerous when we're doing a non-local exit). */
4479 bset_enable_multibyte_characters (current_buffer, multibyte);
4480 bset_undo_list (current_buffer, undo_list);
4481 inserted = Z_BYTE - BEG_BYTE;
4482 } 4536 }
4483 4537
4484 if (NILP (coding_system)) 4538 if (NILP (coding_system))
@@ -4512,22 +4566,27 @@ by calling `format-decode', which see. */)
4512 } 4566 }
4513 } 4567 }
4514 4568
4515 coding.dst_multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters)); 4569 eassert (PT == GPT);
4570
4571 coding.dst_multibyte
4572 = !NILP (BVAR (current_buffer, enable_multibyte_characters));
4516 if (CODING_MAY_REQUIRE_DECODING (&coding) 4573 if (CODING_MAY_REQUIRE_DECODING (&coding)
4517 && (inserted > 0 || CODING_REQUIRE_FLUSHING (&coding))) 4574 && (inserted > 0 || CODING_REQUIRE_FLUSHING (&coding)))
4518 { 4575 {
4519 move_gap_both (PT, PT_BYTE); 4576 /* Now we have all the new bytes at the beginning of the gap,
4520 GAP_SIZE += inserted; 4577 but `decode_coding_gap` can't have them at the beginning of the gap,
4521 ZV_BYTE -= inserted; 4578 so we need to move them. */
4522 Z_BYTE -= inserted; 4579 memmove (GAP_END_ADDR - inserted, GPT_ADDR, inserted);
4523 ZV -= inserted;
4524 Z -= inserted;
4525 decode_coding_gap (&coding, inserted); 4580 decode_coding_gap (&coding, inserted);
4526 inserted = coding.produced_char; 4581 inserted = coding.produced_char;
4527 coding_system = CODING_ID_NAME (coding.id); 4582 coding_system = CODING_ID_NAME (coding.id);
4528 } 4583 }
4529 else if (inserted > 0) 4584 else if (inserted > 0)
4530 { 4585 {
4586 /* Make the text read part of the buffer. */
4587 eassert (NILP (BVAR (current_buffer, enable_multibyte_characters)));
4588 insert_from_gap_1 (inserted, inserted, false);
4589
4531 invalidate_buffer_caches (current_buffer, PT, PT + inserted); 4590 invalidate_buffer_caches (current_buffer, PT, PT + inserted);
4532 adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted, 4591 adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
4533 inserted); 4592 inserted);