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.
This commit is contained in:
parent
a68eee50eb
commit
05d2fc7170
15 changed files with 72 additions and 47 deletions
|
@ -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
|
||||
|
|
25
src/buffer.c
25
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. */
|
||||
|
|
18
src/buffer.h
18
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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
18
src/insdel.c
18
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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
22
src/lisp.h
22
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Add table
Reference in a new issue