aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2025-05-02 16:59:17 -0400
committerStefan Monnier2025-05-02 17:06:09 -0400
commit9048fcf22c3ec3b5cc77dbb98993a53f5f9b7cd5 (patch)
treed633384235b0038f3aa3568f096367374493a1e6
parent99ca41b6ef300653a0d15b73a0c0d446a9a9e059 (diff)
downloademacs-9048fcf22c3ec3b5cc77dbb98993a53f5f9b7cd5.tar.gz
emacs-9048fcf22c3ec3b5cc77dbb98993a53f5f9b7cd5.zip
(decode_coding): Avoid nested *-change-functions (bug#78042)
* src/coding.c (decode_coding): Avoid nested *-change-functions (bug#78042). * test/src/editfns-tests.el (sanity-check-change-functions-before) (sanity-check-change-functions-after): Record notifications in `sanity-check-change-functions-op`. (sanity-check-change-functions-with-op): Don't rely on `sanity-check-change-functions-op` always holding only the `op`. (sanity-check-change-functions-errors): Include the sequence of notifications in the error info. (editfns-tests--before/after-change-functions): Add tests for (bug#78042).
-rw-r--r--src/coding.c6
-rw-r--r--test/src/editfns-tests.el28
2 files changed, 29 insertions, 5 deletions
diff --git a/src/coding.c b/src/coding.c
index 63b0dbeb18b..a923b6bd82d 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -7363,6 +7363,7 @@ decode_coding (struct coding_system *coding)
7363 struct ccl_spec cclspec; 7363 struct ccl_spec cclspec;
7364 int carryover; 7364 int carryover;
7365 int i; 7365 int i;
7366 specpdl_ref count = SPECPDL_INDEX ();
7366 7367
7367 USE_SAFE_ALLOCA; 7368 USE_SAFE_ALLOCA;
7368 7369
@@ -7389,6 +7390,9 @@ decode_coding (struct coding_system *coding)
7389 7390
7390 undo_list = BVAR (current_buffer, undo_list); 7391 undo_list = BVAR (current_buffer, undo_list);
7391 bset_undo_list (current_buffer, Qt); 7392 bset_undo_list (current_buffer, Qt);
7393 /* Avoid running nested *-change-functions via 'produce_annotation'.
7394 Our callers run *-change-functions over the whole region anyway. */
7395 specbind (Qinhibit_modification_hooks, Qt);
7392 } 7396 }
7393 7397
7394 coding->consumed = coding->consumed_char = 0; 7398 coding->consumed = coding->consumed_char = 0;
@@ -7501,7 +7505,7 @@ decode_coding (struct coding_system *coding)
7501 record_insert (coding->dst_pos, coding->produced_char); 7505 record_insert (coding->dst_pos, coding->produced_char);
7502 } 7506 }
7503 7507
7504 SAFE_FREE (); 7508 SAFE_FREE_UNBIND_TO (count, Qnil);
7505} 7509}
7506 7510
7507 7511
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index 2553ad3ec2c..9a27c420f1e 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -498,10 +498,10 @@
498(defvar sanity-check-change-functions-op nil) 498(defvar sanity-check-change-functions-op nil)
499(defmacro sanity-check-change-functions-with-op (op &rest body) 499(defmacro sanity-check-change-functions-with-op (op &rest body)
500 (declare (debug t) (indent 1)) 500 (declare (debug t) (indent 1))
501 `(let ((sanity-check-change-functions-op ,op)) 501 `(let ((sanity-check-change-functions-op (list ,op)))
502 (sanity-check--message "%S..." sanity-check-change-functions-op) 502 (sanity-check--message "%S..." ,op)
503 ,@body 503 ,@body
504 (sanity-check--message "%S...done" sanity-check-change-functions-op))) 504 (sanity-check--message "%S...done" ,op)))
505 505
506(defun sanity-check--message (&rest args) 506(defun sanity-check--message (&rest args)
507 (if sanity-check-change-functions-verbose (apply #'message args))) 507 (if sanity-check-change-functions-verbose (apply #'message args)))
@@ -530,6 +530,7 @@
530 (setq sanity-check-change-functions-buffer-size (buffer-size))))) 530 (setq sanity-check-change-functions-buffer-size (buffer-size)))))
531 531
532(defun sanity-check-change-functions-before (beg end) 532(defun sanity-check-change-functions-before (beg end)
533 (push `(BEFORE ,beg ,end) sanity-check-change-functions-op)
533 (sanity-check--message "Before: %S %S" beg end) 534 (sanity-check--message "Before: %S %S" beg end)
534 (unless (<= (point-min) beg end (point-max)) 535 (unless (<= (point-min) beg end (point-max))
535 (sanity-check-change-functions-error 536 (sanity-check-change-functions-error
@@ -540,6 +541,7 @@
540 (setq sanity-check-change-functions-end end)) 541 (setq sanity-check-change-functions-end end))
541 542
542(defun sanity-check-change-functions-after (beg end len) 543(defun sanity-check-change-functions-after (beg end len)
544 (push `(AFTER ,beg ,end ,len) sanity-check-change-functions-op)
543 (sanity-check--message "After : %S %S (%S)" beg end len) 545 (sanity-check--message "After : %S %S (%S)" beg end len)
544 (unless (<= (point-min) beg end (point-max)) 546 (unless (<= (point-min) beg end (point-max))
545 (sanity-check-change-functions-error 547 (sanity-check-change-functions-error
@@ -565,7 +567,7 @@
565(defun sanity-check-change-functions-errors () 567(defun sanity-check-change-functions-errors ()
566 (sanity-check-change-functions-check-size) 568 (sanity-check-change-functions-check-size)
567 (if sanity-check-change-functions-errors 569 (if sanity-check-change-functions-errors
568 (cons sanity-check-change-functions-op 570 (cons (reverse sanity-check-change-functions-op)
569 sanity-check-change-functions-errors))) 571 sanity-check-change-functions-errors)))
570 572
571(ert-deftest editfns-tests--before/after-change-functions () 573(ert-deftest editfns-tests--before/after-change-functions ()
@@ -591,6 +593,24 @@
591 (decode-coding-region beg (point) 'utf-8) 593 (decode-coding-region beg (point) 'utf-8)
592 (should (null (sanity-check-change-functions-errors))))) 594 (should (null (sanity-check-change-functions-errors)))))
593 595
596 (let ((beg (point))) ;bug#78042
597 (apply #'insert (make-list 5000 "hell\351 "))
598 (sanity-check-change-functions-with-op 'DECODE-CODING-LARGE-REGION
599 (decode-coding-region beg (point) 'windows-1252)
600 (should-not (sanity-check-change-functions-errors))))
601
602 (let ((beg (point))) ;bug#78042
603 (sanity-check-change-functions-with-op 'DECODE-CODING-INSERT
604 ;; The `insert' calls make sure we track the buffer-size
605 ;; so as to detect if `decode-coding-string' fails to run the
606 ;; `*-change-functions'.
607 (insert "<")
608 (decode-coding-string "hell\351 " 'windows-1252 nil (current-buffer))
609 (forward-char 6)
610 (insert ">")
611 (should (equal "<hellé >" (buffer-substring beg (point))))
612 (should-not (sanity-check-change-functions-errors))))
613
594 (sanity-check-change-functions-with-op 'ENCODE-CODING-STRING 614 (sanity-check-change-functions-with-op 'ENCODE-CODING-STRING
595 (encode-coding-string "ééé" 'utf-8 nil (current-buffer)) 615 (encode-coding-string "ééé" 'utf-8 nil (current-buffer))
596 (should (null (sanity-check-change-functions-errors)))) 616 (should (null (sanity-check-change-functions-errors))))