Subject: Re: bug#36431: Crash in marker.c:337

From: Stefan Monnier <[email-masked]>
Date: Sat, 29 Jun 2019 18:56:53 -0400

>> > while sending an e-mail with `mew', I get the attached crash.  This is
>> > something new, which I haven't experienced before.  I can reliably
>> > repeat it.

Hmm... indeed insert-file-contents takes some shortcuts when inserting
the new text into the buffer which can break the expected invariants.

I don't really know how to reproduce your bug, but I think I have an
idea of what might be going on.
Can you try the patch below, to see if it fixes your problem?

        Stefan

diff --git a/src/fileio.c b/src/fileio.c
index ed1d2aedf3..a7be05ef5c 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3741,6 +3741,7 @@ because (1) it preserves some marker positions and (2) it puts less data
 	  CHECK_CODING_SYSTEM (Vcoding_system_for_read);
 	  Fset (Qbuffer_file_coding_system, Vcoding_system_for_read);
 	}
+      eassert (inserted == 0);
       goto notfound;
     }
 
@@ -3767,7 +3768,10 @@ because (1) it preserves some marker positions and (2) it puts less data
       not_regular = 1;
 
       if (! NILP (visit))
-	goto notfound;
+        {
+          eassert (inserted == 0);
+	  goto notfound;
+        }
 
       if (! NILP (replace) || ! NILP (beg) || ! NILP (end))
 	xsignal2 (Qfile_error,
@@ -4435,19 +4439,6 @@ because (1) it preserves some marker positions and (2) it puts less data
   if (how_much < 0)
     report_file_error ("Read error", orig_filename);
 
-  /* Make the text read part of the buffer.  */
-  GAP_SIZE -= inserted;
-  GPT      += inserted;
-  GPT_BYTE += inserted;
-  ZV       += inserted;
-  ZV_BYTE  += inserted;
-  Z        += inserted;
-  Z_BYTE   += inserted;
-
-  if (GAP_SIZE > 0)
-    /* Put an anchor to ensure multi-byte form ends at gap.  */
-    *GPT_ADDR = 0;
-
  notfound:
 
   if (NILP (coding_system))
@@ -4457,6 +4448,7 @@ because (1) it preserves some marker positions and (2) it puts less data
 
 	 Note that we can get here only if the buffer was empty
 	 before the insertion.  */
+      eassert (Z == BEG);
 
       if (!NILP (Vcoding_system_for_read))
 	coding_system = Vcoding_system_for_read;
@@ -4477,6 +4469,16 @@ because (1) it preserves some marker positions and (2) it puts less data
 	  bset_undo_list (current_buffer, Qt);
 	  record_unwind_protect (decide_coding_unwind, unwind_data);
 
+          /* Make the text read part of the buffer.  */
+          eassert (NILP (BVAR (current_buffer, enable_multibyte_characters)));
+          GAP_SIZE -= inserted;
+          GPT      += inserted;
+          GPT_BYTE += inserted;
+          ZV       += inserted;
+          ZV_BYTE  += inserted;
+          Z        += inserted;
+          Z_BYTE   += inserted;
+
 	  if (inserted > 0 && ! NILP (Vset_auto_coding_function))
 	    {
 	      coding_system = call2 (Vset_auto_coding_function,
@@ -4493,8 +4495,18 @@ because (1) it preserves some marker positions and (2) it puts less data
 	      if (CONSP (coding_system))
 		coding_system = XCAR (coding_system);
 	    }
-	  unbind_to (count1, Qnil);
+
+          /* Move the text back into the gap.  Do it now, before we set the
+             buffer back to multibyte, since the bytes may very well not be
+             valid for a multibyte buffer.  */
+          set_point_both (BEG, BEG_BYTE);
+          move_gap_both (BEG, BEG_BYTE);
 	  inserted = Z_BYTE - BEG_BYTE;
+          GAP_SIZE += inserted;
+          ZV = Z = BEG;
+          ZV_BYTE = Z_BYTE = BEG_BYTE;
+
+	  unbind_to (count1, Qnil);
 	}
 
       if (NILP (coding_system))
@@ -4528,22 +4540,28 @@ because (1) it preserves some marker positions and (2) it puts less data
 	}
     }
 
+  eassert (PT == GPT);
+
   coding.dst_multibyte = ! NILP (BVAR (current_buffer, enable_multibyte_characters));
   if (CODING_MAY_REQUIRE_DECODING (&coding)
       && (inserted > 0 || CODING_REQUIRE_FLUSHING (&coding)))
     {
-      move_gap_both (PT, PT_BYTE);
-      GAP_SIZE += inserted;
-      ZV_BYTE -= inserted;
-      Z_BYTE -= inserted;
-      ZV -= inserted;
-      Z -= inserted;
       decode_coding_gap (&coding, inserted, inserted);
       inserted = coding.produced_char;
       coding_system = CODING_ID_NAME (coding.id);
     }
   else if (inserted > 0)
     {
+      /* Make the text read part of the buffer.  */
+      eassert (NILP (BVAR (current_buffer, enable_multibyte_characters)));
+      GAP_SIZE -= inserted;
+      GPT      += inserted;
+      GPT_BYTE += inserted;
+      ZV       += inserted;
+      ZV_BYTE  += inserted;
+      Z        += inserted;
+      Z_BYTE   += inserted;
+
       invalidate_buffer_caches (current_buffer, PT, PT + inserted);
       adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
 			   inserted);