aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoam Postavsky2018-03-30 16:44:24 -0400
committerNoam Postavsky2018-06-03 12:48:13 -0400
commitdaa602338fd91aced720b5555c8b6ed389383831 (patch)
treeb859b9a568d8b18d0f67cdfeee62c93a3bbcc299
parent7460840a6c9ab713e8ccc470011495fdb86a61d7 (diff)
downloademacs-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.c9
-rw-r--r--src/editfns.c10
-rw-r--r--src/insdel.c7
-rw-r--r--src/lisp.h1
-rw-r--r--test/src/editfns-tests.el51
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
3889void
3890free_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 *,
3728extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t); 3728extern Lisp_Object make_save_memory (Lisp_Object *, ptrdiff_t);
3729extern void free_save_value (Lisp_Object); 3729extern void free_save_value (Lisp_Object);
3730extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); 3730extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object);
3731extern void free_marker (Lisp_Object);
3732extern void free_cons (struct Lisp_Cons *); 3731extern void free_cons (struct Lisp_Cons *);
3733extern void init_alloc_once (void); 3732extern void init_alloc_once (void);
3734extern void init_alloc (void); 3733extern 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