]> git.eshelyaron.com Git - emacs.git/commitdiff
Widen modiff counts to avoid wraparound
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 31 Jan 2019 18:29:50 +0000 (10:29 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 31 Jan 2019 18:31:43 +0000 (10:31 -0800)
Widen modification counts to at least 64 bits, to make
wraparound practically impossible.
* doc/lispref/buffers.texi (Buffer Modification):
Don’t say the modification-count can wrap around.
* src/buffer.c (Frestore_buffer_modified_p, Fbuffer_swap_text)
(modify_overlay):
* src/insdel.c (insert_1_both, insert_from_string_1)
(insert_from_gap, insert_from_buffer_1)
(adjust_after_replace, replace_range, replace_range_2)
(del_range_2, modify_text):
* src/textprop.c (modify_text_properties):
Use modiff_incr instead of incrementing directly.
(Fbuffer_modified_tick, Fbuffer_chars_modified_tick):
Don’t assume modification counts fit into fixnums.
* src/buffer.h (struct buffer_text, struct buffer):
* src/cmds.c (internal_self_insert):
* src/fileio.c (Finsert_file_contents):
* src/indent.c (last_known_column_modified):
* src/keyboard.c (command_loop_1):
* src/marker.c (cached_modiff):
* src/syntax.c (find_start_modiff, parse_sexp_propertize)
(find_defun_start):
* src/window.h (struct window):
Use modiff_count for modification counts.
* src/editfns.c (Fsubst_char_in_region):
Copy instead of incrementing modification counts,
since integer overflow checking is not needed here.
* src/lisp.h (modiff_count): New type.
(modiff_incr, modiff_to_integer): New inline functions.
* src/pdumper.c (dump_buffer): Update hash.

15 files changed:
doc/lispref/buffers.texi
src/buffer.c
src/buffer.h
src/cmds.c
src/editfns.c
src/fileio.c
src/indent.c
src/insdel.c
src/keyboard.c
src/lisp.h
src/marker.c
src/pdumper.c
src/syntax.c
src/textprop.c
src/window.h

index e6e03ac27ae1aa402efe9c8c97e248bf2fb5013b..2dbe9c27f2d0594625522ba36ee1d5897c56a879 100644 (file)
@@ -573,7 +573,6 @@ echo area; use @code{set-buffer-modified-p} (above) instead.
 This function returns @var{buffer}'s modification-count.  This is a
 counter that increments every time the buffer is modified.  If
 @var{buffer} is @code{nil} (or omitted), the current buffer is used.
-The counter can wrap around occasionally.
 @end defun
 
 @defun buffer-chars-modified-tick &optional buffer
index a12c80ec0b0268b7d0f645f7c26478d3a4670de0..e5cc5f367f019149b82acd33432fd2b431b838c2 100644 (file)
@@ -1413,7 +1413,7 @@ state of the current buffer.  Use with care.  */)
                 /* If SAVE_MODIFF == auto_save_modified == MODIFF,
                    we can either decrease SAVE_MODIFF and auto_save_modified
                    or increase MODIFF.  */
-                : MODIFF++);
+                : modiff_incr (&MODIFF));
 
   return flag;
 }
@@ -1422,11 +1422,11 @@ DEFUN ("buffer-modified-tick", Fbuffer_modified_tick, Sbuffer_modified_tick,
        0, 1, 0,
        doc: /* Return BUFFER's tick counter, incremented for each change in text.
 Each buffer has a tick counter which is incremented each time the
-text in that buffer is changed.  It wraps around occasionally.
-No argument or nil as argument means use current buffer as BUFFER.  */)
-  (register Lisp_Object buffer)
+text in that buffer is changed.  No argument or nil as argument means
+use current buffer as BUFFER.  */)
+  (Lisp_Object buffer)
 {
-  return make_fixnum (BUF_MODIFF (decode_buffer (buffer)));
+  return modiff_to_integer (BUF_MODIFF (decode_buffer (buffer)));
 }
 
 DEFUN ("buffer-chars-modified-tick", Fbuffer_chars_modified_tick,
@@ -1439,9 +1439,9 @@ values returned by two individual calls of `buffer-chars-modified-tick',
 you can tell whether a character change occurred in that buffer in
 between these calls.  No argument or nil as argument means use current
 buffer as BUFFER.  */)
-  (register Lisp_Object buffer)
+  (Lisp_Object buffer)
 {
-  return make_fixnum (BUF_CHARS_MODIFF (decode_buffer (buffer)));
+  return modiff_to_integer (BUF_CHARS_MODIFF (decode_buffer (buffer)));
 }
 \f
 DEFUN ("rename-buffer", Frename_buffer, Srename_buffer, 1, 2,
@@ -2375,9 +2375,12 @@ results, see Info node `(elisp)Swapping Text'.  */)
   bset_point_before_scroll (current_buffer, Qnil);
   bset_point_before_scroll (other_buffer, Qnil);
 
-  current_buffer->text->modiff++;        other_buffer->text->modiff++;
-  current_buffer->text->chars_modiff++;          other_buffer->text->chars_modiff++;
-  current_buffer->text->overlay_modiff++; other_buffer->text->overlay_modiff++;
+  modiff_incr (&current_buffer->text->modiff);
+  modiff_incr (&other_buffer->text->modiff);
+  modiff_incr (&current_buffer->text->chars_modiff);
+  modiff_incr (&other_buffer->text->chars_modiff);
+  modiff_incr (&current_buffer->text->overlay_modiff);
+  modiff_incr (&other_buffer->text->overlay_modiff);
   current_buffer->text->beg_unchanged = current_buffer->text->gpt;
   current_buffer->text->end_unchanged = current_buffer->text->gpt;
   other_buffer->text->beg_unchanged = other_buffer->text->gpt;
@@ -3913,7 +3916,7 @@ modify_overlay (struct buffer *buf, ptrdiff_t start, ptrdiff_t end)
 
   bset_redisplay (buf);
 
-  ++BUF_OVERLAY_MODIFF (buf);
+  modiff_incr (&BUF_OVERLAY_MODIFF (buf));
 }
 
 /* Remove OVERLAY from LIST.  */
index 82cc2ebfbf9d4debaf258ad4c952c0413cf2f290..d3528ac50e97e09b49af2f6bdce9ce9e9965e561 100644 (file)
@@ -422,20 +422,20 @@ struct buffer_text
     ptrdiff_t gpt_byte;                /* Byte pos of gap in buffer.  */
     ptrdiff_t z_byte;          /* Byte pos of end of buffer.  */
     ptrdiff_t gap_size;                /* Size of buffer's gap.  */
-    EMACS_INT modiff;          /* This counts buffer-modification events
+    modiff_count modiff;       /* This counts buffer-modification events
                                   for this buffer.  It is incremented for
                                   each such event, and never otherwise
                                   changed.  */
-    EMACS_INT chars_modiff;    /* This is modified with character change
+    modiff_count chars_modiff; /* This is modified with character change
                                   events for this buffer.  It is set to
                                   modiff for each such event, and never
                                   otherwise changed.  */
-    EMACS_INT save_modiff;     /* Previous value of modiff, as of last
+    modiff_count save_modiff;  /* Previous value of modiff, as of last
                                   time buffer visited or saved a file.  */
 
-    EMACS_INT overlay_modiff;  /* Counts modifications to overlays.  */
+    modiff_count overlay_modiff; /* Counts modifications to overlays.  */
 
-    EMACS_INT compact;         /* Set to modiff each time when compact_buffer
+    modiff_count compact;      /* Set to modiff each time when compact_buffer
                                   is called for this buffer.  */
 
     /* Minimum value of GPT - BEG since last redisplay that finished.  */
@@ -446,12 +446,12 @@ struct buffer_text
 
     /* MODIFF as of last redisplay that finished; if it matches MODIFF,
        beg_unchanged and end_unchanged contain no useful information.  */
-    EMACS_INT unchanged_modified;
+    modiff_count unchanged_modified;
 
     /* BUF_OVERLAY_MODIFF of current buffer, as of last redisplay that
        finished; if it matches BUF_OVERLAY_MODIFF, beg_unchanged and
        end_unchanged contain no useful information.  */
-    EMACS_INT overlay_unchanged_modified;
+    modiff_count overlay_unchanged_modified;
 
     /* Properties of this buffer's text.  */
     INTERVAL intervals;
@@ -812,11 +812,11 @@ struct buffer
   off_t modtime_size;
 
   /* The value of text->modiff at the last auto-save.  */
-  EMACS_INT auto_save_modified;
+  modiff_count auto_save_modified;
 
   /* The value of text->modiff at the last display error.
      Redisplay of this buffer is inhibited until it changes again.  */
-  EMACS_INT display_error_modiff;
+  modiff_count display_error_modiff;
 
   /* The time at which we detected a failure to auto-save,
      Or 0 if we didn't have a failure.  */
index 239e3be5c07bf109eec16cbef998a69476968be0..9f3c8610e62ddf2ef83c07cbab1643ef3482f760 100644 (file)
@@ -423,7 +423,7 @@ internal_self_insert (int c, EMACS_INT n)
                  : UNIBYTE_TO_CHAR (XFIXNAT (Fprevious_char ())))
          == Sword))
     {
-      EMACS_INT modiff = MODIFF;
+      modiff_count modiff = MODIFF;
       Lisp_Object sym;
 
       sym = call0 (Qexpand_abbrev);
index 3edfd1dc201d19832bc7eaef3038ebbfe6a19483..360cdbe02ee1eab3aecd7155fc71c484ffbf759e 100644 (file)
@@ -2291,10 +2291,11 @@ Both characters must have the same length of multi-byte form.  */)
 
              if (! NILP (noundo))
                {
-                 if (MODIFF - 1 == SAVE_MODIFF)
-                   SAVE_MODIFF++;
-                 if (MODIFF - 1 == BUF_AUTOSAVE_MODIFF (current_buffer))
-                   BUF_AUTOSAVE_MODIFF (current_buffer)++;
+                 modiff_count m = MODIFF;
+                 if (SAVE_MODIFF == m - 1)
+                   SAVE_MODIFF = m;
+                 if (BUF_AUTOSAVE_MODIFF (current_buffer) == m - 1)
+                   BUF_AUTOSAVE_MODIFF (current_buffer) = m;
                }
 
              /* The before-change-function may have moved the gap
index aececcda3055f43cef9436c2be6a6e68280a6d1b..55c9f26b7539b73644ecb51d89dddd6d68053c98 100644 (file)
@@ -4618,7 +4618,7 @@ by calling `format-decode', which see.  */)
          ptrdiff_t opoint = PT;
          ptrdiff_t opoint_byte = PT_BYTE;
          ptrdiff_t oinserted = ZV - BEGV;
-         EMACS_INT ochars_modiff = CHARS_MODIFF;
+         modiff_count ochars_modiff = CHARS_MODIFF;
 
          TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
          insval = call3 (Qformat_decode,
@@ -4658,7 +4658,7 @@ by calling `format-decode', which see.  */)
              ptrdiff_t opoint = PT;
              ptrdiff_t opoint_byte = PT_BYTE;
              ptrdiff_t oinserted = ZV - BEGV;
-             EMACS_INT ochars_modiff = CHARS_MODIFF;
+             modiff_count ochars_modiff = CHARS_MODIFF;
 
              TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
              insval = call1 (XCAR (p), make_fixnum (oinserted));
index 0970532f30d69517865500493cacde697fc1ce13..bc1aa8ca2c65961d747a9b600ff0fcc73fad65f5 100644 (file)
@@ -49,7 +49,7 @@ ptrdiff_t last_known_column_point;
 
 /* Value of MODIFF when current_column was called.  */
 
-static EMACS_INT last_known_column_modified;
+static modiff_count last_known_column_modified;
 
 static ptrdiff_t current_column_1 (void);
 static ptrdiff_t position_indentation (ptrdiff_t);
index a6f006a521d363903161b596dd0bb783991f989a..fd725ac878546c496ebc262dd4cadcc63f7d8ee1 100644 (file)
@@ -903,7 +903,7 @@ insert_1_both (const char *string,
      the insertion.  This, together with recording the insertion,
      will add up to the right stuff in the undo list.  */
   record_insert (PT, nchars);
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 
   memcpy (GPT_ADDR, string, nbytes);
@@ -1031,7 +1031,7 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
 #endif
 
   record_insert (PT, nchars);
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
@@ -1088,7 +1088,7 @@ insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail)
      of this dance.  */
   invalidate_buffer_caches (current_buffer, GPT, GPT);
   record_insert (GPT, nchars);
-  MODIFF++;
+  modiff_incr (&MODIFF);
 
   GAP_SIZE -= nbytes;
   if (! text_at_gap_tail)
@@ -1228,7 +1228,7 @@ insert_from_buffer_1 (struct buffer *buf,
 #endif
 
   record_insert (PT, nchars);
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 
   GAP_SIZE -= outgoing_nbytes;
@@ -1329,7 +1329,7 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
 
   if (len == 0)
     evaporate_overlays (from);
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 }
 
@@ -1524,7 +1524,7 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new,
 
   check_markers ();
 
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 
   if (adjust_match_data)
@@ -1655,7 +1655,7 @@ replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
 
   check_markers ();
 
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 }
 \f
@@ -1830,7 +1830,7 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,
      at the end of the text before the gap.  */
   adjust_markers_for_delete (from, from_byte, to, to_byte);
 
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 
   /* Relocate point as if it were a marker.  */
@@ -1884,7 +1884,7 @@ modify_text (ptrdiff_t start, ptrdiff_t end)
   BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end);
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
-  MODIFF++;
+  modiff_incr (&MODIFF);
   CHARS_MODIFF = MODIFF;
 
   bset_point_before_scroll (current_buffer, Qnil);
index b3b55e73b63637fec5cf90ff4380ee207bb07f8b..cd1747ea88c269fc96d55b2416fb849d1331f1d1 100644 (file)
@@ -1238,7 +1238,7 @@ static void adjust_point_for_property (ptrdiff_t, bool);
 Lisp_Object
 command_loop_1 (void)
 {
-  EMACS_INT prev_modiff = 0;
+  modiff_count prev_modiff = 0;
   struct buffer *prev_buffer = NULL;
   bool already_adjusted = 0;
 
index 5159f050a490d749268e858d71fafd793c930190..5a0de4b12c73b1b3f6001860e218a626483bb023 100644 (file)
@@ -3490,6 +3490,28 @@ integer_to_uintmax (Lisp_Object num, uintmax_t *n)
     }
 }
 
+/* A modification count.  These are wide enough, and incremented
+   rarely enough, so that they should never overflow a 60-bit counter
+   in practice, and the code below assumes this so a compiler can
+   generate better code if EMACS_INT is 64 bits.  */
+typedef intmax_t modiff_count;
+
+INLINE modiff_count
+modiff_incr (modiff_count *a)
+{
+  modiff_count a0 = *a;
+  bool modiff_overflow = INT_ADD_WRAPV (a0, 1, a);
+  eassert (!modiff_overflow && *a >> 30 >> 30 == 0);
+  return a0;
+}
+
+INLINE Lisp_Object
+modiff_to_integer (modiff_count a)
+{
+  eassume (0 <= a && a >> 30 >> 30 == 0);
+  return make_int (a);
+}
+
 /* Defined in data.c.  */
 extern _Noreturn void wrong_choice (Lisp_Object, Lisp_Object);
 extern void notify_variable_watchers (Lisp_Object, Lisp_Object,
index 36d6b10c7461c1d6dbe388a5c7ec9f38d681f524..b58051a8c2b9dc2739f804b8e9034d441345d013 100644 (file)
@@ -30,7 +30,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 static ptrdiff_t cached_charpos;
 static ptrdiff_t cached_bytepos;
 static struct buffer *cached_buffer;
-static EMACS_INT cached_modiff;
+static modiff_count cached_modiff;
 
 /* Juanma Barranquero <lekktu@gmail.com> reported ~3x increased
    bootstrap time when byte_char_debug_check is enabled; so this
index 7a8a90d4cf33c605ca5a7b549494fca05e27aca9..d4fbc4b04947f25b9620cbec3cb089e8c5bca1ba 100644 (file)
@@ -2797,7 +2797,7 @@ dump_hash_table (struct dump_context *ctx,
 static dump_off
 dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer)
 {
-#if CHECK_STRUCTS && !defined (HASH_buffer_E8695CAE09)
+#if CHECK_STRUCTS && !defined HASH_buffer_AE2C8CE357
 # error "buffer changed. See CHECK_STRUCTS comment."
 #endif
   struct buffer munged_buffer = *in_buffer;
index 4616ae296f86c356db4d5f34ab610683ebc462d5..dd2f56f2cface8aff49dcfe2a775363e4b3398f5 100644 (file)
@@ -175,7 +175,7 @@ static ptrdiff_t find_start_value;
 static ptrdiff_t find_start_value_byte;
 static struct buffer *find_start_buffer;
 static ptrdiff_t find_start_begv;
-static EMACS_INT find_start_modiff;
+static modiff_count find_start_modiff;
 
 
 static Lisp_Object skip_chars (bool, Lisp_Object, Lisp_Object, bool);
@@ -489,7 +489,7 @@ parse_sexp_propertize (ptrdiff_t charpos)
   if (syntax_propertize__done <= charpos
       && syntax_propertize__done < zv)
     {
-      EMACS_INT modiffs = CHARS_MODIFF;
+      modiff_count modiffs = CHARS_MODIFF;
       safe_call1 (Qinternal__syntax_propertize,
                  make_fixnum (min (zv, 1 + charpos)));
       if (modiffs != CHARS_MODIFF)
@@ -608,7 +608,7 @@ find_defun_start (ptrdiff_t pos, ptrdiff_t pos_byte)
 
   if (!NILP (Vcomment_use_syntax_ppss))
     {
-      EMACS_INT modiffs = CHARS_MODIFF;
+      modiff_count modiffs = CHARS_MODIFF;
       Lisp_Object ppss = call1 (Qsyntax_ppss, make_fixnum (pos));
       if (modiffs != CHARS_MODIFF)
        error ("syntax-ppss modified the buffer!");
index 7e29ed6e8b810830d13bf135758c781d7006b183..bb063d3eaaa87dbedfd867247f48d2396acace84 100644 (file)
@@ -89,7 +89,7 @@ modify_text_properties (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
   BUF_COMPUTE_UNCHANGED (buf, b - 1, e);
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
-  MODIFF++;
+  modiff_incr (&MODIFF);
 
   bset_point_before_scroll (current_buffer, Qnil);
 
index 9c4aea85ea6f5c28a839fdd17ec226a38c8e57ec..514bf1fb6ecbef6c7cdf92b2272b7178e7749bf1 100644 (file)
@@ -281,11 +281,11 @@ struct window
 
     /* Displayed buffer's text modification events counter as of last time
        display completed.  */
-    EMACS_INT last_modified;
+    modiff_count last_modified;
 
     /* Displayed buffer's overlays modification events counter as of last
        complete update.  */
-    EMACS_INT last_overlay_modified;
+    modiff_count last_overlay_modified;
 
     /* Value of point at that time.  Since this is a position in a buffer,
        it should be positive.  */