Subject: bug#78042: 31.0.50; Improper sequence of `before/after-change-functions` calls

From: Stefan Monnier <[email-masked]>
Date: Thu, 24 Apr 2025 11:38:59 -0400

Package: Emacs
Version: 31.0.50

I just found another case where we break our promises w.r.t
`before/after-change-functions`:

    src/emacs -Q src/regexp-emacs.c
    M-: (decode-coding-region 123 (point-max) 'windows-1252) RET

[ The details of the file and buffer positions don't really
  matter, AFAIK.  ]

I first get a run of `before-change-functions` for 123...point-max, as
expected at the beginning and a run of `after-change-functions` for
123...point-max, as expected at the end, but between the two I get
another run of `before-change-functions` for 123..16497:

    #0  signal_before_change
        (start_int=start_int@entry=123, end_int=end_int@entry=16497, preserve_ptr=preserve_ptr@entry=0x0) at insdel.c:2157
    #1  0x0000555555702c3a in prepare_to_modify_buffer_1
        (start=start@entry=123, end=end@entry=16497, preserve_ptr=preserve_ptr@entry=0x0) at insdel.c:2024
    #2  0x00005555557c9f36 in modify_text_properties (buffer=MISSING, 
        buffer@entry=XIL(0x555555dfac0d), start=MISSING, end=MISSING) at textprop.c:85
    #3  0x00005555557cb5cc in add_text_properties_1
        (start=make_fixnum(123), end=make_fixnum(16497), properties=XIL(0x7fffffffce33), object=XIL(0x555555dfac0d), set_type=set_type@entry=TEXT_PROPERTY_REPLACE, destructive=destructive@entry=true) at textprop.c:1236
    #4  0x00005555557cb9b8 in Fadd_text_properties (start=MISSING, 
        start@entry=make_fixnum(123), end=MISSING, 
        end@entry=make_fixnum(16497), properties=MISSING, object=MISSING, 
        object@entry=XIL(0x555555dfac0d)) at textprop.c:1308
    #5  0x00005555557cba12 in Fput_text_property
        (start=make_fixnum(123), end=end@entry=make_fixnum(16497), property=MISSING, 
        property@entry=XIL(0x55b0), value=MISSING, 
        value@entry=XIL(0x2aaa9984e428), object=XIL(0x555555dfac0d))
        at textprop.c:1326
    #6  0x0000555555644852 in produce_charset
        (coding=coding@entry=0x7fffffffd080, charbuf=charbuf@entry=0x555556a7ef88, pos=pos@entry=16497) at coding.c:7277
    #7  0x00005555556448e8 in produce_annotation
        (coding=coding@entry=0x7fffffffd080, pos=16497, pos@entry=123)
        at coding.c:7320
    #8  0x000055555564578f in decode_coding (coding=coding@entry=0x7fffffffd080)
        at coding.c:7421
    #9  0x000055555564cc32 in decode_coding_object
        (coding=coding@entry=0x7fffffffd080, src_object=src_object@entry=XIL(0x555555dfac0d), from=from@entry=123, from_byte=from_byte@entry=123, to=to@entry=161558, to_byte=to_byte@entry=161558, dst_object=XIL(0x555555dfac0d))
        at coding.c:8183
    #10 0x000055555564e1c7 in code_convert_region
        (start=make_fixnum(123), end=make_fixnum(161558), coding_system=XIL(0x2aaa9984e428), dst_object=XIL(0x555555dfac0d), encodep=encodep@entry=false, norecord=norecord@entry=false) at coding.c:9510

There's probably also a corresponding run of `after-change-functions`,
I haven't checked, but the problem is that the "final run of
`after-change-functions` for 123...point-max is now "invalid" in the
sense that it modifies a range of the buffer beyond the last run of
`before-change-functions`, contrary to what we promise.

- Stefan