* /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? @ 2019-12-21 17:23 Alan Mackenzie 2019-12-21 18:11 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Alan Mackenzie @ 2019-12-21 17:23 UTC (permalink / raw) To: emacs-devel Hello, Emacs. I've just had a bug report on bug-cc-mode from "Sun, Wei" <waysun@amazon.com> (Subject: bug#38691: CC Mode 5.34 (C++//lhw); `Invalid search bound` when undo). Essentially, this bug is reproduced by inserting a single line comment (complete with CR) into an otherwise empty C++ Mode buffer: // 2019-12-20 17:57 , then doing C-x C-p (mark-page), C-u M-| <CR> sort <CR> (shell-command-on-region), then C-_ (undo). This throws an error. The cause of the error is that the C function call_process in src/callproc.c is calling before-change-functions, but fails to call after-change-functions. This is at callproc.c ~L790, where there is the helpful comment: /* FIXME: Call signal_after_change! */ (thanks, Stefan!). Well, I've tried adding this call to signal_after_change thusly: diff --git a/src/callproc.c b/src/callproc.c index b51594c2d5..6d74b34068 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -785,9 +785,11 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, { /* We have to decode the input. */ Lisp_Object curbuf; ptrdiff_t count1 = SPECPDL_INDEX (); + ptrdiff_t beg; XSETBUFFER (curbuf, current_buffer); /* FIXME: Call signal_after_change! */ + beg = PT; prepare_to_modify_buffer (PT, PT, NULL); /* We cannot allow after-change-functions be run during decoding, because that might modify the @@ -798,6 +800,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, decode_coding_c_string (&process_coding, (unsigned char *) buf, nread, curbuf); unbind_to (count1, Qnil); + signal_after_change (beg, 0, PT - beg); if (display_on_the_fly && CODING_REQUIRE_DETECTION (&saved_coding) && ! CODING_REQUIRE_DETECTION (&process_coding)) , and this appears to solve the OP's problem. However, a few lines further on, there's a del_range_2 call inside a condition I don't understand (though might, with a great deal of study). I suspect that the call to signal_after_change ought to take this del_range_2 into account, possibly coming after it. Would somebody who's familiar with this bit of callproc.c please help me out here, and explain what this call to del_range_2 is doing, and whether there's anything basically wrong with my simple-minded addition of signal_after_change. Thanks! -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-21 17:23 /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? Alan Mackenzie @ 2019-12-21 18:11 ` Eli Zaretskii 2019-12-21 21:47 ` Alan Mackenzie 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2019-12-21 18:11 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Sat, 21 Dec 2019 17:23:24 +0000 > From: Alan Mackenzie <acm@muc.de> > > /* FIXME: Call signal_after_change! */ > + beg = PT; Can you tell why you needed this variable and the assignment? AFAIK, PT doesn't change when we call decode_coding_c_string. > decode_coding_c_string (&process_coding, > (unsigned char *) buf, nread, curbuf); > unbind_to (count1, Qnil); > + signal_after_change (beg, 0, PT - beg); > if (display_on_the_fly > && CODING_REQUIRE_DETECTION (&saved_coding) > && ! CODING_REQUIRE_DETECTION (&process_coding)) > > > , and this appears to solve the OP's problem. > > However, a few lines further on, there's a del_range_2 call inside a condition > I don't understand (though might, with a great deal of study). I suspect that > the call to signal_after_change ought to take this del_range_2 into account, > possibly coming after it. > > Would somebody who's familiar with this bit of callproc.c please help me out > here, and explain what this call to del_range_2 is doing, and whether there's > anything basically wrong with my simple-minded addition of > signal_after_change. I'm not sure what you want to hear. The del_range_2 call deletes the just-inserted text, because the condition means that text was inserted using the wrong coding-system to decode the incoming bytes. What does that mean for the modification hooks, I don't know: the before-change-functions were already called, but nothing was inserted from the Lisp application's POV, so if you insist on having before and after hooks to be called in pairs, you are in a conundrum. It's possible that we should simplify all this by calling the before hooks just once before the loop and the after hooks just once after the loop, instead of calling them for each individual chunk inside the loop, but again I don't know what that means for applications which expects these hook calls to pair. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-21 18:11 ` Eli Zaretskii @ 2019-12-21 21:47 ` Alan Mackenzie 2019-12-22 18:38 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Alan Mackenzie @ 2019-12-21 21:47 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. Sorry my last post was not thought through. I hope this one is better. On Sat, Dec 21, 2019 at 20:11:01 +0200, Eli Zaretskii wrote: > > Date: Sat, 21 Dec 2019 17:23:24 +0000 > > From: Alan Mackenzie <acm@muc.de> > > > > /* FIXME: Call signal_after_change! */ > > + beg = PT; > Can you tell why you needed this variable and the assignment? AFAIK, > PT doesn't change when we call decode_coding_c_string. I'd misunderstood decode_coding_c_string. You're right, PT doesn't change with this macro. With this, the arguments I was getting to after-change-functions were wrong. However, I've kept BEG for the next version of the patch. > > decode_coding_c_string (&process_coding, > > (unsigned char *) buf, nread, curbuf); > > unbind_to (count1, Qnil); > > + signal_after_change (beg, 0, PT - beg); > > if (display_on_the_fly > > && CODING_REQUIRE_DETECTION (&saved_coding) > > && ! CODING_REQUIRE_DETECTION (&process_coding)) > > > > > > , and this appears to solve the OP's problem. > > > > However, a few lines further on, there's a del_range_2 call inside a condition > > I don't understand (though might, with a great deal of study). I suspect that > > the call to signal_after_change ought to take this del_range_2 into account, > > possibly coming after it. > > > > Would somebody who's familiar with this bit of callproc.c please help me out > > here, and explain what this call to del_range_2 is doing, and whether there's > > anything basically wrong with my simple-minded addition of > > signal_after_change. > I'm not sure what you want to hear. The del_range_2 call deletes the > just-inserted text, because the condition means that text was inserted > using the wrong coding-system to decode the incoming bytes. What does > that mean for the modification hooks, I don't know: the > before-change-functions were already called, but nothing was inserted > from the Lisp application's POV, so if you insist on having before and > after hooks to be called in pairs, you are in a conundrum. I think I've solved this with the new variable prepared_position. It records the position of BEG for prepare_to_modify_buffer, and only calls that function if it hasn't already done so for that BEG. It's not an elegant solution, but I think it will work. > It's possible that we should simplify all this by calling the before > hooks just once before the loop and the after hooks just once after > the loop, instead of calling them for each individual chunk inside the > loop, but again I don't know what that means for applications which > expects these hook calls to pair. I don't think this is necessary. (If we positively want to do it, that's a different matter.) Here's the latest version of my patch. It's only been slightly tested, but it doesn't produce any unexpected "successes" from 'make check'. diff --git a/src/callproc.c b/src/callproc.c index b51594c2d5..34da7af863 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -746,6 +746,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, int carryover = 0; bool display_on_the_fly = display_p; struct coding_system saved_coding = process_coding; + ptrdiff_t prepared_position = 0; + ptrdiff_t beg; while (1) { @@ -780,7 +782,13 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, ; else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) - insert_1_both (buf, nread, nread, 0, 1, 0); + { + beg = PT; + insert_1_both (buf, nread, nread, 0, prepared_position < PT, 0); + if (prepared_position < PT) + prepared_position = PT; + signal_after_change (beg, 0, PT - beg); + } else { /* We have to decode the input. */ Lisp_Object curbuf; @@ -788,7 +796,11 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, XSETBUFFER (curbuf, current_buffer); /* FIXME: Call signal_after_change! */ - prepare_to_modify_buffer (PT, PT, NULL); + if (prepared_position < PT) + { + prepare_to_modify_buffer (PT, PT, NULL); + prepared_position = PT; + } /* We cannot allow after-change-functions be run during decoding, because that might modify the buffer, while we rely on process_coding.produced to @@ -822,6 +834,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, continue; } + signal_after_change (PT, 0, process_coding.produced_char); TEMP_SET_PT_BOTH (PT + process_coding.produced_char, PT_BYTE + process_coding.produced); carryover = process_coding.carryover_bytes; -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-21 21:47 ` Alan Mackenzie @ 2019-12-22 18:38 ` Eli Zaretskii 2019-12-24 9:47 ` Alan Mackenzie 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2019-12-22 18:38 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Sat, 21 Dec 2019 21:47:52 +0000 > Cc: emacs-devel@gnu.org > From: Alan Mackenzie <acm@muc.de> > > else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) > && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) > - insert_1_both (buf, nread, nread, 0, 1, 0); > + { > + beg = PT; > + insert_1_both (buf, nread, nread, 0, prepared_position < PT, 0); > + if (prepared_position < PT) > + prepared_position = PT; > + signal_after_change (beg, 0, PT - beg); ^^^^^^^^ 'PT - beg' is just 'nread' in this case, since we are inserting 'nread' characters. Right? And I don't think you need the prepared_position stuff here, since PT doesn't move in signal_after_change. > @@ -788,7 +796,11 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, > > XSETBUFFER (curbuf, current_buffer); > /* FIXME: Call signal_after_change! */ > - prepare_to_modify_buffer (PT, PT, NULL); > + if (prepared_position < PT) > + { > + prepare_to_modify_buffer (PT, PT, NULL); > + prepared_position = PT; > + } > /* We cannot allow after-change-functions be run > during decoding, because that might modify the > buffer, while we rely on process_coding.produced to > @@ -822,6 +834,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, > continue; > } > > + signal_after_change (PT, 0, process_coding.produced_char); > TEMP_SET_PT_BOTH (PT + process_coding.produced_char, > PT_BYTE + process_coding.produced); > carryover = process_coding.carryover_bytes; This really ugly, IMO. And the code logic is very hard to follow and verify its correctness, given the various use cases. I think you should simply call signal_after_change after the call to del_range_2 (telling the after-change hooks that actually nothing was inserted or deleted). Then you won't need the prepared_position thingy. Thanks. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-22 18:38 ` Eli Zaretskii @ 2019-12-24 9:47 ` Alan Mackenzie 2019-12-24 12:51 ` Alan Mackenzie 2019-12-24 15:47 ` Eli Zaretskii 0 siblings, 2 replies; 17+ messages in thread From: Alan Mackenzie @ 2019-12-24 9:47 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. On Sun, Dec 22, 2019 at 20:38:41 +0200, Eli Zaretskii wrote: > > Date: Sat, 21 Dec 2019 21:47:52 +0000 > > Cc: emacs-devel@gnu.org > > From: Alan Mackenzie <acm@muc.de> > > > > else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) > > && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) > > - insert_1_both (buf, nread, nread, 0, 1, 0); > > + { > > + beg = PT; > > + insert_1_both (buf, nread, nread, 0, prepared_position < PT, 0); > > + if (prepared_position < PT) > > + prepared_position = PT; > > + signal_after_change (beg, 0, PT - beg); > ^^^^^^^^ > 'PT - beg' is just 'nread' in this case, since we are inserting > 'nread' characters. Right? Er, yes. ;-). So BEG is silly, and as you say, PT - beg should just be nread. > And I don't think you need the prepared_position stuff here, since PT > doesn't move in signal_after_change. The point is not to call prepare_to_modify_buffer twice at the same position. prepared_position records the most recent place p_t_m_b was called, thus enabling us to avoid calling it there again, should we remove the already inserted text, decode it, and insert it again. > > @@ -788,7 +796,11 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, > > > > XSETBUFFER (curbuf, current_buffer); > > /* FIXME: Call signal_after_change! */ > > - prepare_to_modify_buffer (PT, PT, NULL); > > + if (prepared_position < PT) > > + { > > + prepare_to_modify_buffer (PT, PT, NULL); > > + prepared_position = PT; > > + } > > /* We cannot allow after-change-functions be run > > during decoding, because that might modify the > > buffer, while we rely on process_coding.produced to > > @@ -822,6 +834,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, > > continue; > > } > > > > + signal_after_change (PT, 0, process_coding.produced_char); > > TEMP_SET_PT_BOTH (PT + process_coding.produced_char, > > PT_BYTE + process_coding.produced); > > carryover = process_coding.carryover_bytes; > This really ugly, IMO. And the code logic is very hard to follow and > verify its correctness, given the various use cases. Well, call_process was already ugly, with its inserting text once, sometimes deleting it and inserting a modified version. But I see my changes don't help its readability. > I think you should simply call signal_after_change after the call to > del_range_2 (telling the after-change hooks that actually nothing was > inserted or deleted). Then you won't need the prepared_position > thingy. After thinking it over a couple of days, I can't agree this is a good idea. Calling before/after-change-functions for a non-change would be very unusual in Emacs - I don't know of anywhere where this is currently done - and would surely cause problems somewhere, and would certainly cause some inefficiency. Also we would have to amend the Change Hooks page in the Elisp manual to warn of this possibility. And all that because a low level C function is a little tricky. I think the basic idea of my change is sound, but it is suboptimally coded. My confusion, I think, arose from the use of the PREPARE parameter in the call to insert_1_both, which creates several different cases. This is a bad idea. If instead we put in a single call to prepare_to_modify_buffer, this should be relatively easy to follow. One or two comments would also be helpful. > Thanks. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-24 9:47 ` Alan Mackenzie @ 2019-12-24 12:51 ` Alan Mackenzie 2019-12-24 15:58 ` Eli Zaretskii 2019-12-24 15:47 ` Eli Zaretskii 1 sibling, 1 reply; 17+ messages in thread From: Alan Mackenzie @ 2019-12-24 12:51 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. On Tue, Dec 24, 2019 at 09:47:24 +0000, Alan Mackenzie wrote: [ .... ] > The point is not to call prepare_to_modify_buffer twice at the same > position. prepared_position records the most recent place p_t_m_b was > called, thus enabling us to avoid calling it there again, should we > remove the already inserted text, decode it, and insert it again. [ .... ] > > This really ugly, IMO. And the code logic is very hard to follow and > > verify its correctness, given the various use cases. [ .... ] > I think the basic idea of my change is sound, but it is suboptimally > coded. My confusion, I think, arose from the use of the PREPARE > parameter in the call to insert_1_both, which creates several different > cases. This is a bad idea. If instead we put in a single call to > prepare_to_modify_buffer, this should be relatively easy to follow. One > or two comments would also be helpful. I think the following patch is better. What do you think? diff --git a/src/callproc.c b/src/callproc.c index b51594c2d5..0df0292633 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -746,6 +746,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, int carryover = 0; bool display_on_the_fly = display_p; struct coding_system saved_coding = process_coding; + ptrdiff_t prepared_pos = 0; /* prepare_to_modify_buffer was last + called here. */ while (1) { @@ -774,21 +776,29 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, break; } + /* Call `prepare_to_modify_buffer' exactly once for PT. */ + if ((prepared_pos < PT) && nread) + { + prepare_to_modify_buffer (PT, PT, NULL); + prepared_pos = PT; + } + /* Now NREAD is the total amount of data in the buffer. */ if (!nread) ; else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) - insert_1_both (buf, nread, nread, 0, 1, 0); + { + insert_1_both (buf, nread, nread, 0, 0, 0); + signal_after_change (PT, 0, nread); + } else { /* We have to decode the input. */ Lisp_Object curbuf; ptrdiff_t count1 = SPECPDL_INDEX (); XSETBUFFER (curbuf, current_buffer); - /* FIXME: Call signal_after_change! */ - prepare_to_modify_buffer (PT, PT, NULL); /* We cannot allow after-change-functions be run during decoding, because that might modify the buffer, while we rely on process_coding.produced to @@ -822,6 +832,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, continue; } + signal_after_change (PT, 0, process_coding.produced_char); TEMP_SET_PT_BOTH (PT + process_coding.produced_char, PT_BYTE + process_coding.produced); carryover = process_coding.carryover_bytes; > > Thanks. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-24 12:51 ` Alan Mackenzie @ 2019-12-24 15:58 ` Eli Zaretskii 0 siblings, 0 replies; 17+ messages in thread From: Eli Zaretskii @ 2019-12-24 15:58 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Tue, 24 Dec 2019 12:51:11 +0000 > Cc: emacs-devel@gnu.org > From: Alan Mackenzie <acm@muc.de> > > > > This really ugly, IMO. And the code logic is very hard to follow and > > > verify its correctness, given the various use cases. > > [ .... ] > > > I think the basic idea of my change is sound, but it is suboptimally > > coded. My confusion, I think, arose from the use of the PREPARE > > parameter in the call to insert_1_both, which creates several different > > cases. This is a bad idea. If instead we put in a single call to > > prepare_to_modify_buffer, this should be relatively easy to follow. One > > or two comments would also be helpful. > > I think the following patch is better. What do you think? Frankly, I don't like this, for the reasons I explained in my other message. If you insist on jumping through these hoops just to avoid an extra call to the modification hooks, please write a comment with the detailed description of the logic of these calls and their conditions, and how that ensures the paired calls with no extra calls. Thanks. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-24 9:47 ` Alan Mackenzie 2019-12-24 12:51 ` Alan Mackenzie @ 2019-12-24 15:47 ` Eli Zaretskii 2019-12-29 13:34 ` Alan Mackenzie 1 sibling, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2019-12-24 15:47 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Tue, 24 Dec 2019 09:47:24 +0000 > Cc: emacs-devel@gnu.org > From: Alan Mackenzie <acm@muc.de> > > The point is not to call prepare_to_modify_buffer twice at the same > position. Why is that a problem? Surely, something like that can happen in real life, and any modification hook should be prepared to deal with that? > > I think you should simply call signal_after_change after the call to > > del_range_2 (telling the after-change hooks that actually nothing was > > inserted or deleted). Then you won't need the prepared_position > > thingy. > > After thinking it over a couple of days, I can't agree this is a good > idea. Calling before/after-change-functions for a non-change would be > very unusual in Emacs - I don't know of anywhere where this is currently > done - and would surely cause problems somewhere, and would certainly > cause some inefficiency. Also we would have to amend the Change Hooks > page in the Elisp manual to warn of this possibility. Again, I don't see why this could cause any trouble. Inserting an empty string is not an outlandish situation, and any modification hook must be prepared to (trivially) deal with it. IOW, jumping through hoops in order to avoid such calls is IMNSHO unjustified. It will definitely complicate code, and thus will run higher risk of subtle bugs. Why risk that? ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-24 15:47 ` Eli Zaretskii @ 2019-12-29 13:34 ` Alan Mackenzie 2019-12-29 16:23 ` Stefan Monnier 2020-01-03 8:45 ` Eli Zaretskii 0 siblings, 2 replies; 17+ messages in thread From: Alan Mackenzie @ 2019-12-29 13:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. I've combined your two recent posts into one, to make it easier to answer them. <Post 1> On Tue, Dec 24, 2019 at 17:47:18 +0200, Eli Zaretskii wrote: > > Date: Tue, 24 Dec 2019 09:47:24 +0000 > > Cc: emacs-devel@gnu.org > > From: Alan Mackenzie <acm@muc.de> > > The point is not to call prepare_to_modify_buffer twice at the same > > position. > Why is that a problem? Surely, something like that can happen in real > life, and any modification hook should be prepared to deal with that? Well, the more we can issue balanced before- and after- calls, the better. It is true that the hook functions should be able to handle unbalanced calls, but we don't know for sure that they can, in all cases. CC Mode might not be the only casualty (though I intend to fix CC Mode, here). Besides, the Elisp manual page "Change Hooks" only describes one situation for unbalanced calls. This is one large enclosing before- followed by a sequence of smaller after-s. The situation in callproc.c is thus technically a bug. > > > I think you should simply call signal_after_change after the call to > > > del_range_2 (telling the after-change hooks that actually nothing was > > > inserted or deleted). Then you won't need the prepared_position > > > thingy. > > After thinking it over a couple of days, I can't agree this is a good > > idea. Calling before/after-change-functions for a non-change would be > > very unusual in Emacs - I don't know of anywhere where this is currently > > done - and would surely cause problems somewhere, and would certainly > > cause some inefficiency. Also we would have to amend the Change Hooks > > page in the Elisp manual to warn of this possibility. > Again, I don't see why this could cause any trouble. Inserting an > empty string is not an outlandish situation, and any modification hook > must be prepared to (trivially) deal with it. This may be true, but I wouldn't bet anything on it being true for all existing hooks. Doing this would necessitate amending the Elisp manual, and (if we're going to be honest) adding a NEWS item in the incompatible changes section. > IOW, jumping through hoops in order to avoid such calls is IMNSHO > unjustified. It will definitely complicate code, and thus will run > higher risk of subtle bugs. Why risk that? We have a real existing bug here, and any fix to it runs the risk of further bugs. I think introducing no-change change hooks is more likely to cause trouble than the relatively straightforward patch I'm proposing. My proposed patch is not complicated. Really, it isn't. It's the least messy way of fixing the bug we have. <Post 2> > > I think the following patch is better. What do you think? > Frankly, I don't like this, for the reasons I explained in my other > message. If you insist on jumping through these hoops just to avoid > an extra call to the modification hooks, please write a comment with > the detailed description of the logic of these calls and their > conditions, and how that ensures the paired calls with no extra calls. OK, I've done this. Writing this comment was actually more difficult than amending the code. :-) The current state of my proposed patch, unchanged except for the new comment, follows. Comments? diff --git a/src/callproc.c b/src/callproc.c index b51594c2d5..66eebdebb4 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -746,6 +746,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, int carryover = 0; bool display_on_the_fly = display_p; struct coding_system saved_coding = process_coding; + ptrdiff_t prepared_pos = 0; /* prepare_to_modify_buffer was last + called here. */ while (1) { @@ -773,6 +775,27 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, if (display_on_the_fly) break; } + /* CHANGE FUNCTIONS + For each typical iteration of the enclosing while (1) + loop which yields data (i.e. nread > 0), before- and + after-change-functions are invoked exactly once. The + call to prepare_to_modify_buffer follows this comment, + and there is one call to signal_after_change in each of + the branches of the next `else if'. + + Exceptionally, the insertion into the buffer is aborted + at the call to del_range_2 ~45 lines further down, + without signal_after_change being called. The data are + then inserted finally at the next iteration of the + while (1) loop. A second, unwanted, call to + prepare_to_modify_buffer is inhibited by the test + prepared_pos < PT, and signal_after_change is then + called normally after the insertion. */ + if ((prepared_pos < PT) && nread) + { + prepare_to_modify_buffer (PT, PT, NULL); + prepared_pos = PT; + } /* Now NREAD is the total amount of data in the buffer. */ @@ -780,15 +803,16 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, ; else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) - insert_1_both (buf, nread, nread, 0, 1, 0); + { + insert_1_both (buf, nread, nread, 0, 0, 0); + signal_after_change (PT, 0, nread); + } else { /* We have to decode the input. */ Lisp_Object curbuf; ptrdiff_t count1 = SPECPDL_INDEX (); XSETBUFFER (curbuf, current_buffer); - /* FIXME: Call signal_after_change! */ - prepare_to_modify_buffer (PT, PT, NULL); /* We cannot allow after-change-functions be run during decoding, because that might modify the buffer, while we rely on process_coding.produced to @@ -822,6 +846,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, continue; } + signal_after_change (PT, 0, process_coding.produced_char); TEMP_SET_PT_BOTH (PT + process_coding.produced_char, PT_BYTE + process_coding.produced); carryover = process_coding.carryover_bytes; > Thanks. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-29 13:34 ` Alan Mackenzie @ 2019-12-29 16:23 ` Stefan Monnier 2020-01-03 8:45 ` Eli Zaretskii 1 sibling, 0 replies; 17+ messages in thread From: Stefan Monnier @ 2019-12-29 16:23 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Eli Zaretskii, emacs-devel > Besides, the Elisp manual page "Change Hooks" only describes one > situation for unbalanced calls. This is one large enclosing before- > followed by a sequence of smaller after-s. That's right. And the sequence can be empty. >> Again, I don't see why this could cause any trouble. Inserting an >> empty string is not an outlandish situation, and any modification hook >> must be prepared to (trivially) deal with it. > This may be true, but I wouldn't bet anything on it being true for all > existing hooks. It's probably harmless to run the after change hook for such a non-change, but it should never be necessary. Stefan ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2019-12-29 13:34 ` Alan Mackenzie 2019-12-29 16:23 ` Stefan Monnier @ 2020-01-03 8:45 ` Eli Zaretskii 2020-01-04 22:47 ` Alan Mackenzie 1 sibling, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2020-01-03 8:45 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Sun, 29 Dec 2019 13:34:36 +0000 > Cc: emacs-devel@gnu.org > From: Alan Mackenzie <acm@muc.de> > > > > The point is not to call prepare_to_modify_buffer twice at the same > > > position. > > > Why is that a problem? Surely, something like that can happen in real > > life, and any modification hook should be prepared to deal with that? > > Well, the more we can issue balanced before- and after- calls, the > better. I wasn't suggesting to produce unbalanced calls, I was suggesting that calling the hooks in a balanced way twice for the same position cannot be a serious problem. > > > After thinking it over a couple of days, I can't agree this is a good > > > idea. Calling before/after-change-functions for a non-change would be > > > very unusual in Emacs - I don't know of anywhere where this is currently > > > done - and would surely cause problems somewhere, and would certainly > > > cause some inefficiency. Also we would have to amend the Change Hooks > > > page in the Elisp manual to warn of this possibility. > > > Again, I don't see why this could cause any trouble. Inserting an > > empty string is not an outlandish situation, and any modification hook > > must be prepared to (trivially) deal with it. > > This may be true, but I wouldn't bet anything on it being true for all > existing hooks. Really? I'd be surprised if such buggy hooks existed in any production code. How can a modification hook assume the insertion is always non-empty? > > IOW, jumping through hoops in order to avoid such calls is IMNSHO > > unjustified. It will definitely complicate code, and thus will run > > higher risk of subtle bugs. Why risk that? > > We have a real existing bug here, and any fix to it runs the risk of > further bugs. Sure, but the more complex the fix, the higher the risk. It's uneconomical to make fixes that are more complex than strictly necessary, I'm sure you agree. > > > I think the following patch is better. What do you think? > > > Frankly, I don't like this, for the reasons I explained in my other > > message. If you insist on jumping through these hoops just to avoid > > an extra call to the modification hooks, please write a comment with > > the detailed description of the logic of these calls and their > > conditions, and how that ensures the paired calls with no extra calls. > > OK, I've done this. Writing this comment was actually more difficult > than amending the code. :-) The current state of my proposed patch, > unchanged except for the new comment, follows. Comments? It falls short of what I'd like to see, because it doesn't cover the situation where this test: if (display_on_the_fly && CODING_REQUIRE_DETECTION (&saved_coding) && ! CODING_REQUIRE_DETECTION (&process_coding)) causes us to switch from using the 'else' branch to using the 'else if' branch in the following snippet: if (!nread) ; else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) insert_1_both (buf, nread, nread, 0, 1, 0); else { /* We have to decode the input. */ IOW, the commentary you wrote doesn't tell the reader what insert_1_both, decode_coding_c_string, and del_range_2 do (or don't do) with regards to the modification hooks, and without that the comment is incomplete, and doesn't explain the logic of what the code does. Thanks (and apologies for a delay in responding). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2020-01-03 8:45 ` Eli Zaretskii @ 2020-01-04 22:47 ` Alan Mackenzie 2020-01-05 18:17 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Alan Mackenzie @ 2020-01-04 22:47 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. On Fri, Jan 03, 2020 at 10:45:53 +0200, Eli Zaretskii wrote: > > Date: Sun, 29 Dec 2019 13:34:36 +0000 > > Cc: emacs-devel@gnu.org > > From: Alan Mackenzie <acm@muc.de> > > Well, the more we can issue balanced before- and after- calls, the > > better. > I wasn't suggesting to produce unbalanced calls, I was suggesting that > calling the hooks in a balanced way twice for the same position cannot > be a serious problem. It might, for example, cause some hook to invalidate some cache unnecessarily. But even if it caused no specific problem, it would cost a needless runtime penalty. [ .... ] > > We have a real existing bug here, and any fix to it runs the risk of > > further bugs. > Sure, but the more complex the fix, the higher the risk. It's > uneconomical to make fixes that are more complex than strictly > necessary, I'm sure you agree. I think I disagree with you generally on this point - I think it is uneconomical to install a simple workaround when a complete fix is only a little more difficult. This change of mine is NOT complicated. [ .... ] > It falls short of what I'd like to see, because it doesn't cover the > situation where this test: > if (display_on_the_fly > && CODING_REQUIRE_DETECTION (&saved_coding) > && ! CODING_REQUIRE_DETECTION (&process_coding)) > causes us to switch from using the 'else' branch to using the 'else if' > branch in the following snippet: > if (!nread) > ; > else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) > && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) > insert_1_both (buf, nread, nread, 0, 1, 0); > else > { /* We have to decode the input. */ > IOW, the commentary you wrote doesn't tell the reader what > insert_1_both, decode_coding_c_string, and del_range_2 do (or don't > do) with regards to the modification hooks, and without that the > comment is incomplete, and doesn't explain the logic of what the code > does. OK. I have to say here, I really don't believe such an extensive commentary is needed here. The code is there, and anybody generally familiar with our C code would understand it without a great deal of difficulty, even the mechanism which prevents a spurious second call to prepare_to_modify_buffer. Surely? Anyhow I've spent quite a bit of time trying to get the level of this comment right, and my current version of it reads as follows: /* CHANGE FUNCTIONS For each iteration of the enclosing while (1) loop which yields data (i.e. nread > 0), before- and after-change-functions are each invoked exactly once. This is done directly from the current function only, by calling prepare_to_modify_buffer and signal_after_change. It is never done by directing another function such as insert_1_both to call them. The call to prepare_to_modify_buffer follows this comment, and there is one call to signal_after_change in each of the branches of the next `else if'. Exceptionally, the insertion into the buffer is aborted at the call to del_range_2 ~45 lines further down, this function removing the newly inserted data. At this stage prepare_to_modify_buffer has been called, but signal_after_change hasn't. A continue statement restarts the enclosing while(1) loop. A second, unwanted, call to `prepare_to_modify_buffer' is inhibited by the test prepared_pos < PT. The data are inserted again, and this time signal_after_change gets called, balancing the previous call to prepare_to_modify_buffer. */ > Thanks (and apologies for a delay in responding). That's OK, I haven't exactly been prompt myself in posting to this thread. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2020-01-04 22:47 ` Alan Mackenzie @ 2020-01-05 18:17 ` Eli Zaretskii 2020-01-05 18:48 ` Alan Mackenzie 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2020-01-05 18:17 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Sat, 4 Jan 2020 22:47:30 +0000 > Cc: emacs-devel@gnu.org > From: Alan Mackenzie <acm@muc.de> > > OK. I have to say here, I really don't believe such an extensive > commentary is needed here. The code is there, and anybody generally > familiar with our C code would understand it without a great deal of > difficulty, even the mechanism which prevents a spurious second call to > prepare_to_modify_buffer. Surely? If you think this is a waste of effort, you can leave the commentary to me. > For each iteration of the enclosing while (1) loop which > yields data (i.e. nread > 0), before- and > after-change-functions are each invoked exactly once. > This is done directly from the current function only, by > calling prepare_to_modify_buffer and signal_after_change. > It is never done by directing another function such as > insert_1_both to call them. The last sentence above is inaccurate, since insert_1_both does call prepare_to_modify_buffer. Thanks. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2020-01-05 18:17 ` Eli Zaretskii @ 2020-01-05 18:48 ` Alan Mackenzie 2020-01-21 20:34 ` Alan Mackenzie 0 siblings, 1 reply; 17+ messages in thread From: Alan Mackenzie @ 2020-01-05 18:48 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. On Sun, Jan 05, 2020 at 20:17:44 +0200, Eli Zaretskii wrote: > > Date: Sat, 4 Jan 2020 22:47:30 +0000 > > Cc: emacs-devel@gnu.org > > From: Alan Mackenzie <acm@muc.de> > > OK. I have to say here, I really don't believe such an extensive > > commentary is needed here. The code is there, and anybody generally > > familiar with our C code would understand it without a great deal of > > difficulty, even the mechanism which prevents a spurious second call to > > prepare_to_modify_buffer. Surely? > If you think this is a waste of effort, you can leave the commentary > to me. It was more that that amount of commentary, 21 lines, could well get in the way, rather than being a help. > > For each iteration of the enclosing while (1) loop which > > yields data (i.e. nread > 0), before- and > > after-change-functions are each invoked exactly once. > > This is done directly from the current function only, by > > calling prepare_to_modify_buffer and signal_after_change. > > It is never done by directing another function such as > > insert_1_both to call them. > The last sentence above is inaccurate, since insert_1_both does call > prepare_to_modify_buffer. insert_1_both _can_ call prepare_to_modify_buffer, but only if it's directed to do so by setting its PREPARE parameter to true. Here it is set to false, to make it easier to keep control of the various prepare_to_modify_buffer's and signal_after_change's. How about changing the last sentence to: It is not done here by directing another function such as insert_1_both to call them. ? > Thanks. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2020-01-05 18:48 ` Alan Mackenzie @ 2020-01-21 20:34 ` Alan Mackenzie 2020-01-22 3:27 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Alan Mackenzie @ 2020-01-21 20:34 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. Ping? Could we move forward with this, please? On Sun, Jan 05, 2020 at 18:48:44 +0000, Alan Mackenzie wrote: > Hello, Eli. > On Sun, Jan 05, 2020 at 20:17:44 +0200, Eli Zaretskii wrote: > > > Date: Sat, 4 Jan 2020 22:47:30 +0000 > > > Cc: emacs-devel@gnu.org > > > From: Alan Mackenzie <acm@muc.de> > > > OK. I have to say here, I really don't believe such an extensive > > > commentary is needed here. The code is there, and anybody > > > generally familiar with our C code would understand it without a > > > great deal of difficulty, even the mechanism which prevents a > > > spurious second call to prepare_to_modify_buffer. Surely? > > If you think this is a waste of effort, you can leave the commentary > > to me. > It was more that that amount of commentary, 21 lines, could well get in > the way, rather than being a help. > > > For each iteration of the enclosing while (1) loop which > > > yields data (i.e. nread > 0), before- and > > > after-change-functions are each invoked exactly once. > > > This is done directly from the current function only, by > > > calling prepare_to_modify_buffer and signal_after_change. > > > It is never done by directing another function such as > > > insert_1_both to call them. > > The last sentence above is inaccurate, since insert_1_both does call > > prepare_to_modify_buffer. > insert_1_both _can_ call prepare_to_modify_buffer, but only if it's > directed to do so by setting its PREPARE parameter to true. Here it is > set to false, to make it easier to keep control of the various > prepare_to_modify_buffer's and signal_after_change's. How about > changing the last sentence to: > It is not done here by directing another function such as > insert_1_both to call them. > ? > > Thanks. > -- > Alan Mackenzie (Nuremberg, Germany). -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2020-01-21 20:34 ` Alan Mackenzie @ 2020-01-22 3:27 ` Eli Zaretskii 2020-01-22 20:05 ` Alan Mackenzie 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2020-01-22 3:27 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel > Date: Tue, 21 Jan 2020 20:34:53 +0000 > Cc: emacs-devel@gnu.org > From: Alan Mackenzie <acm@muc.de> > > Hello, Eli. > > Ping? > > Could we move forward with this, please? What holds this? I wasn't aware we had yet to discuss something or decide. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? 2020-01-22 3:27 ` Eli Zaretskii @ 2020-01-22 20:05 ` Alan Mackenzie 0 siblings, 0 replies; 17+ messages in thread From: Alan Mackenzie @ 2020-01-22 20:05 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel Hello, Eli. On Wed, Jan 22, 2020 at 05:27:46 +0200, Eli Zaretskii wrote: > > Date: Tue, 21 Jan 2020 20:34:53 +0000 > > Cc: emacs-devel@gnu.org > > From: Alan Mackenzie <acm@muc.de> > > Hello, Eli. > > Ping? > > Could we move forward with this, please? > What holds this? I wasn't aware we had yet to discuss something or > decide. Ah, sorry. I thought we were still negotiating it. I've committed the fix to the emacs-27 branch, and will now close bug #38691. -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2020-01-22 20:05 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-12-21 17:23 /* FIXME: Call signal_after_change! */ in callproc.c. Well, why not? Alan Mackenzie 2019-12-21 18:11 ` Eli Zaretskii 2019-12-21 21:47 ` Alan Mackenzie 2019-12-22 18:38 ` Eli Zaretskii 2019-12-24 9:47 ` Alan Mackenzie 2019-12-24 12:51 ` Alan Mackenzie 2019-12-24 15:58 ` Eli Zaretskii 2019-12-24 15:47 ` Eli Zaretskii 2019-12-29 13:34 ` Alan Mackenzie 2019-12-29 16:23 ` Stefan Monnier 2020-01-03 8:45 ` Eli Zaretskii 2020-01-04 22:47 ` Alan Mackenzie 2020-01-05 18:17 ` Eli Zaretskii 2020-01-05 18:48 ` Alan Mackenzie 2020-01-21 20:34 ` Alan Mackenzie 2020-01-22 3:27 ` Eli Zaretskii 2020-01-22 20:05 ` Alan Mackenzie
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).