diff options
| author | Noam Postavsky | 2018-03-30 16:44:24 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2018-06-03 12:48:13 -0400 |
| commit | daa602338fd91aced720b5555c8b6ed389383831 (patch) | |
| tree | b859b9a568d8b18d0f67cdfeee62c93a3bbcc299 | |
| parent | 7460840a6c9ab713e8ccc470011495fdb86a61d7 (diff) | |
| download | emacs-daa602338fd91aced720b5555c8b6ed389383831.tar.gz emacs-daa602338fd91aced720b5555c8b6ed389383831.zip | |
Fix another case of freed markers in the undo-list (Bug#30931)
* src/alloc.c (free_marker): Remove.
* src/editfns.c (save_restriction_restore):
* src/insdel.c (signal_before_change): Detach the markers from the
buffer when we're done with them instead of calling free_marker on
them.
* test/src/editfns-tests.el (delete-region-undo-markers-1)
(delete-region-undo-markers-2): New tests.
(cherry picked from commit 96b8747d5c5d747af13fd84d8fe0308ef2a0ea7a)
| -rw-r--r-- | src/alloc.c | 9 | ||||
| -rw-r--r-- | src/editfns.c | 10 | ||||
| -rw-r--r-- | src/insdel.c | 7 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | test/src/editfns-tests.el | 51 |
5 files changed, 62 insertions, 16 deletions
diff --git a/src/alloc.c b/src/alloc.c index c3f7920ed87..09d61b7e5f3 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3884,15 +3884,6 @@ build_marker (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos) | |||
| 3884 | return obj; | 3884 | return obj; |
| 3885 | } | 3885 | } |
| 3886 | 3886 | ||
| 3887 | /* Put MARKER back on the free list after using it temporarily. */ | ||
| 3888 | |||
| 3889 | void | ||
| 3890 | free_marker (Lisp_Object marker) | ||
| 3891 | { | ||
| 3892 | unchain_marker (XMARKER (marker)); | ||
| 3893 | free_misc (marker); | ||
| 3894 | } | ||
| 3895 | |||
| 3896 | 3887 | ||
| 3897 | /* Return a newly created vector or string with specified arguments as | 3888 | /* Return a newly created vector or string with specified arguments as |
| 3898 | elements. If all the arguments are characters that can fit | 3889 | elements. If all the arguments are characters that can fit |
diff --git a/src/editfns.c b/src/editfns.c index 3fc08f9d202..1fcfc7aef63 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3876,10 +3876,12 @@ save_restriction_restore (Lisp_Object data) | |||
| 3876 | 3876 | ||
| 3877 | buf->clip_changed = 1; /* Remember that the narrowing changed. */ | 3877 | buf->clip_changed = 1; /* Remember that the narrowing changed. */ |
| 3878 | } | 3878 | } |
| 3879 | /* This isn’t needed anymore, so don’t wait for GC. | 3879 | /* This isn’t needed anymore, so don’t wait for GC. Do not call |
| 3880 | Do not call free_marker on XCAR (data) or XCDR (data), | 3880 | free_marker on XCAR (data) or XCDR (data), though, since |
| 3881 | though, since record_marker_adjustments may have put | 3881 | record_marker_adjustments may have put them on the buffer’s |
| 3882 | them on the buffer’s undo list (Bug#30931). */ | 3882 | undo list (Bug#30931). Just detach them instead. */ |
| 3883 | Fset_marker (XCAR (data), Qnil, Qnil); | ||
| 3884 | Fset_marker (XCDR (data), Qnil, Qnil); | ||
| 3883 | free_cons (XCONS (data)); | 3885 | free_cons (XCONS (data)); |
| 3884 | } | 3886 | } |
| 3885 | else | 3887 | else |
diff --git a/src/insdel.c b/src/insdel.c index 02e3f41bc9f..697395c507b 100644 --- a/src/insdel.c +++ b/src/insdel.c | |||
| @@ -2148,10 +2148,13 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, | |||
| 2148 | FETCH_START, FETCH_END, Qnil); | 2148 | FETCH_START, FETCH_END, Qnil); |
| 2149 | } | 2149 | } |
| 2150 | 2150 | ||
| 2151 | /* Detach the markers now that we're done with them. Don't directly | ||
| 2152 | free them, since the change functions could have caused them to | ||
| 2153 | be inserted into the undo list (Bug#30931). */ | ||
| 2151 | if (! NILP (start_marker)) | 2154 | if (! NILP (start_marker)) |
| 2152 | free_marker (start_marker); | 2155 | Fset_marker (start_marker, Qnil, Qnil); |
| 2153 | if (! NILP (end_marker)) | 2156 | if (! NILP (end_marker)) |
| 2154 | free_marker (end_marker); | 2157 | Fset_marker (end_marker, Qnil, Qnil); |
| 2155 | RESTORE_VALUE; | 2158 | RESTORE_VALUE; |
| 2156 | 2159 | ||
| 2157 | unbind_to (count, Qnil); | 2160 | unbind_to (count, Qnil); |
diff --git a/src/lisp.h b/src/lisp.h index a8963b7f3c4..9320345bff0 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3728,7 +3728,6 @@ extern Lisp_Object make_save_funcptr_ptr_obj (void (*) (void), void *, | |||
| 3728 | extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t); | 3728 | extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t); |
| 3729 | extern void free_save_value (Lisp_Object); | 3729 | extern void free_save_value (Lisp_Object); |
| 3730 | extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); | 3730 | extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); |
| 3731 | extern void free_marker (Lisp_Object); | ||
| 3732 | extern void free_cons (struct Lisp_Cons *); | 3731 | extern void free_cons (struct Lisp_Cons *); |
| 3733 | extern void init_alloc_once (void); | 3732 | extern void init_alloc_once (void); |
| 3734 | extern void init_alloc (void); | 3733 | extern void init_alloc (void); |
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el index b72f37d1f01..714e92e5053 100644 --- a/test/src/editfns-tests.el +++ b/test/src/editfns-tests.el | |||
| @@ -247,4 +247,55 @@ | |||
| 247 | (buffer-string) | 247 | (buffer-string) |
| 248 | "foo bar baz qux")))))) | 248 | "foo bar baz qux")))))) |
| 249 | 249 | ||
| 250 | (ert-deftest delete-region-undo-markers-1 () | ||
| 251 | "Make sure we don't end up with freed markers reachable from Lisp." | ||
| 252 | ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=30931#40 | ||
| 253 | (with-temp-buffer | ||
| 254 | (insert "1234567890") | ||
| 255 | (setq buffer-undo-list nil) | ||
| 256 | (narrow-to-region 2 5) | ||
| 257 | ;; `save-restriction' in a narrowed buffer creates two markers | ||
| 258 | ;; representing the current restriction. | ||
| 259 | (save-restriction | ||
| 260 | (widen) | ||
| 261 | ;; Any markers *within* the deleted region are put onto the undo | ||
| 262 | ;; list. | ||
| 263 | (delete-region 1 6)) | ||
| 264 | ;; (princ (format "%S" buffer-undo-list) #'external-debugging-output) | ||
| 265 | ;; `buffer-undo-list' is now | ||
| 266 | ;; (("12345" . 1) (#<temp-marker1> . -1) (#<temp-marker2> . 1)) | ||
| 267 | ;; | ||
| 268 | ;; If temp-marker1 or temp-marker2 are freed prematurely, calling | ||
| 269 | ;; `type-of' on them will cause Emacs to abort. Calling | ||
| 270 | ;; `garbage-collect' will also abort if it finds any reachable | ||
| 271 | ;; freed objects. | ||
| 272 | (should (eq (type-of (car (nth 1 buffer-undo-list))) 'marker)) | ||
| 273 | (should (eq (type-of (car (nth 2 buffer-undo-list))) 'marker)) | ||
| 274 | (garbage-collect))) | ||
| 275 | |||
| 276 | (ert-deftest delete-region-undo-markers-2 () | ||
| 277 | "Make sure we don't end up with freed markers reachable from Lisp." | ||
| 278 | ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=30931#55 | ||
| 279 | (with-temp-buffer | ||
| 280 | (insert "1234567890") | ||
| 281 | (setq buffer-undo-list nil) | ||
| 282 | ;; signal_before_change creates markers delimiting a change | ||
| 283 | ;; region. | ||
| 284 | (let ((before-change-functions | ||
| 285 | (list (lambda (beg end) | ||
| 286 | (delete-region (1- beg) (1+ end)))))) | ||
| 287 | (delete-region 2 5)) | ||
| 288 | ;; (princ (format "%S" buffer-undo-list) #'external-debugging-output) | ||
| 289 | ;; `buffer-undo-list' is now | ||
| 290 | ;; (("678" . 1) ("12345" . 1) (#<marker in no buffer> . -1) | ||
| 291 | ;; (#<temp-marker1> . -1) (#<temp-marker2> . -4)) | ||
| 292 | ;; | ||
| 293 | ;; If temp-marker1 or temp-marker2 are freed prematurely, calling | ||
| 294 | ;; `type-of' on them will cause Emacs to abort. Calling | ||
| 295 | ;; `garbage-collect' will also abort if it finds any reachable | ||
| 296 | ;; freed objects. | ||
| 297 | (should (eq (type-of (car (nth 3 buffer-undo-list))) 'marker)) | ||
| 298 | (should (eq (type-of (car (nth 4 buffer-undo-list))) 'marker)) | ||
| 299 | (garbage-collect))) | ||
| 300 | |||
| 250 | ;;; editfns-tests.el ends here | 301 | ;;; editfns-tests.el ends here |