diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2019-01-31 10:29:50 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2019-01-31 10:31:43 -0800 |
commit | 05d2fc7170fb66a87601b1c76ddae2c1b7b4b934 (patch) | |
tree | 217ddd3a45ea611069d85ac13e22e525bb965996 | |
parent | a68eee50eb515b28b448894299334afced26ef78 (diff) | |
download | emacs-05d2fc7170fb66a87601b1c76ddae2c1b7b4b934.tar.gz |
Widen modiff counts to avoid wraparound
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.
-rw-r--r-- | doc/lispref/buffers.texi | 1 | ||||
-rw-r--r-- | src/buffer.c | 25 | ||||
-rw-r--r-- | src/buffer.h | 18 | ||||
-rw-r--r-- | src/cmds.c | 2 | ||||
-rw-r--r-- | src/editfns.c | 9 | ||||
-rw-r--r-- | src/fileio.c | 4 | ||||
-rw-r--r-- | src/indent.c | 2 | ||||
-rw-r--r-- | src/insdel.c | 18 | ||||
-rw-r--r-- | src/keyboard.c | 2 | ||||
-rw-r--r-- | src/lisp.h | 22 | ||||
-rw-r--r-- | src/marker.c | 2 | ||||
-rw-r--r-- | src/pdumper.c | 2 | ||||
-rw-r--r-- | src/syntax.c | 6 | ||||
-rw-r--r-- | src/textprop.c | 2 | ||||
-rw-r--r-- | src/window.h | 4 |
15 files changed, 72 insertions, 47 deletions
diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi index e6e03ac27ae..2dbe9c27f2d 100644 --- a/doc/lispref/buffers.texi +++ b/doc/lispref/buffers.texi @@ -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 diff --git a/src/buffer.c b/src/buffer.c index a12c80ec0b0..e5cc5f367f0 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -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))); } 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 (¤t_buffer->text->modiff); + modiff_incr (&other_buffer->text->modiff); + modiff_incr (¤t_buffer->text->chars_modiff); + modiff_incr (&other_buffer->text->chars_modiff); + modiff_incr (¤t_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. */ diff --git a/src/buffer.h b/src/buffer.h index 82cc2ebfbf9..d3528ac50e9 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -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. */ diff --git a/src/cmds.c b/src/cmds.c index 239e3be5c07..9f3c8610e62 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -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); diff --git a/src/editfns.c b/src/editfns.c index 3edfd1dc201..360cdbe02ee 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -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 diff --git a/src/fileio.c b/src/fileio.c index aececcda305..55c9f26b753 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -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)); diff --git a/src/indent.c b/src/indent.c index 0970532f30d..bc1aa8ca2c6 100644 --- a/src/indent.c +++ b/src/indent.c @@ -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); diff --git a/src/insdel.c b/src/insdel.c index a6f006a521d..fd725ac8785 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -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; } @@ -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); diff --git a/src/keyboard.c b/src/keyboard.c index b3b55e73b63..cd1747ea88c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -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; diff --git a/src/lisp.h b/src/lisp.h index 5159f050a49..5a0de4b12c7 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -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, diff --git a/src/marker.c b/src/marker.c index 36d6b10c746..b58051a8c2b 100644 --- a/src/marker.c +++ b/src/marker.c @@ -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 diff --git a/src/pdumper.c b/src/pdumper.c index 7a8a90d4cf3..d4fbc4b0494 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -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; diff --git a/src/syntax.c b/src/syntax.c index 4616ae296f8..dd2f56f2cfa 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -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!"); diff --git a/src/textprop.c b/src/textprop.c index 7e29ed6e8b8..bb063d3eaaa 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -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); diff --git a/src/window.h b/src/window.h index 9c4aea85ea6..514bf1fb6ec 100644 --- a/src/window.h +++ b/src/window.h @@ -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. */ |