Subject: bug#30931: 27.0.50; Crash in "Automatic GC"

From: Noam Postavsky <[email-masked]>
Date: Fri, 30 Mar 2018 01:39:30 -0400

Noam Postavsky <[email-masked]> writes:

> Michał Kondraciuk <[email-masked]> writes:
>
>> I don't know if it helps, but I was able to reproduce a crash in the
>> same place (mark_object()) with bare Emacs, however only in 27.0.50.
>
> This is very helpful, thank you.

Okay, with this recipe, I was able to put a breakpoint in free_marker
and find where the problem is: save_restriction_save creates markers to
represent the current restriction, record_marker_adjustments (called
from delete-region) puts all buffer markers onto the buffer undo list,
and save_restriction_restore frees the markers created in
save_restriction_save.

    save_restriction_save (void)
    {
    [...]
          beg = build_marker (current_buffer, BEGV, BEGV_BYTE);
          end = build_marker (current_buffer, ZV, ZV_BYTE);

    record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
    {
    [...]
      for (m = BUF_MARKERS (current_buffer); m; m = m->next)
        {
        [...]
                  XSETMISC (marker, m);
                  bset_undo_list
                    (current_buffer,
                     Fcons (Fcons (marker, make_number (adjustment)),
                            BVAR (current_buffer, undo_list)));

    save_restriction_restore (Lisp_Object data)
    {
    [...]
          /* These aren't needed anymore, so don't wait for GC.  */
          free_marker (XCAR (data));
          free_marker (XCDR (data));

So the following is enough to trigger the bug:

  (with-temp-buffer
    (insert "1234567890")
    (setq buffer-undo-list nil)
    (narrow-to-region 2 5)
    (save-restriction
      (widen)
      (delete-region 1 6))
    (princ (format "%S" buffer-undo-list) #'external-debugging-output)
    (type-of (car (nth 1 buffer-undo-list))))

Surprisingly, printing works on a Lisp_Misc_Free object, so this prints

    (("12345" . 1) (#<misc free cell> . -1) (#<misc free cell> . 1))

before aborting in Ftype_of.  Calling garbage-collect instead of type-of
also aborts.  Calling neither seems to be okay, since in that case the
Lisp_Misc_Free objects somehow turn into #<marker in no buffer>.

For solving this, I guess the easiest would be to have
save_restriction_restore do (set-marker m nil) instead of free_marker.
Might make more sense to avoid putting those markers onto the undo list
in the first place though.