| Summary: | [patch] vi(1) silently corrupts open file on SIGINT when entering :wq in command mode | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | lfrigault <lfrigault> | ||||||||||||||||
| Component: | bin | Assignee: | Jaakko Heinonen <jh> | ||||||||||||||||
| Status: | Closed FIXED | ||||||||||||||||||
| Severity: | Affects Only Me | ||||||||||||||||||
| Priority: | Normal | ||||||||||||||||||
| Version: | 4.1-STABLE | ||||||||||||||||||
| Hardware: | Any | ||||||||||||||||||
| OS: | Any | ||||||||||||||||||
| Attachments: |
|
||||||||||||||||||
|
Description
lfrigault
2000-09-07 11:00:01 UTC
On Thu, 07 Sep 2000 02:50:34 MST, lfrigault@teaser.fr wrote: > >Number: 21089 > >Category: misc > >Synopsis: vi silently corrupt open file on SIGINT when entering :wq in command mode As a datapoint, I don't see this behaviour in the development branch. In fact, SIGINT doesn't even kill vi when it's in command state! It just aborts out of command-state, as expected. Can anyone else confirm the results reported? Ciao, Sheldon. On Fri, Sep 08, 2000 at 03:33:40PM +0200, Sheldon Hearn wrote: > > >Number: 21089 > > >Category: misc > > >Synopsis: vi silently corrupt open file on SIGINT when entering :wq in > command mode > > As a datapoint, I don't see this behaviour in the development branch. > In fact, SIGINT doesn't even kill vi when it's in command state! It > just aborts out of command-state, as expected. > > Can anyone else confirm the results reported? If you enter <ESC>: SIGINT has no effect If you enter <ESC>:w The file is corrupted on SIGINT and you have a message : ================================= +=+=+=+=+=+=+=+ :w Interrupted Press any key to continue: ================================= and the file is save corrupted but you can re-write it with <ESC>:wq<ENTER> If you enter <ESC>:wq The file is save corrupted on SIGINT and vi terminate silently I have reproduced the problem under : FreeBSD victor.teaser.fr 5.0-CURRENT FreeBSD 5.0-CURRENT #10: Wed Aug 9 16:34:08 CEST 2000 lwa@victor.teaser.fr:/usr/src/sys/compile/VICTOR i386 Hope, this helps Laurent -- Laurent Frigault | <url:http://www.teaser.fr/~lfrigault> Hello,
the bug seems to persist:
$ wc -l article.txt
1756 article.txt
<vi file, type ':wq', enter killall -INT on different console>
$ wc -l article.txt
99 article.txt
System: FreeBSD 5.3-STABLE #0: Sat Jan 22 18:58:33 CET 2005, i386
Regards.
Mario
The bug still exists in 7.0-RC1. I believe that the attached patch fixes it. Can you confirm? -- Jaakko On Wed, Feb 06, 2008 at 08:55:06AM +0200, Jaakko Heinonen wrote: > > The bug still exists in 7.0-RC1. I believe that the attached patch fixes > it. Can you confirm? Yes. I just apply the patch to 7.0-RC1 and that fixes the problem. Regards, -- Laurent Frigault | <url:http://www.agneau.org/> State Changed From-To: open->analyzed Sumbitter notes that the suggested patch cures the problem. Jaakko, I think that you looked in the right direction but applied the fix at a wrong level. In fact, we shouldn't put a test for INTERRUPTED(sp) into each ex command's implementation. In ex mode, the call stack is as follows: main -> editor -> ex -> ex_cmd -> <individual command> Among the functions, it's ex() that takes care of INTERRUPTED(sp). Therefore we should do something similar, too, when ex_cmd() is called from vi mode. In the latter case the call stack looks as follows: main -> editor -> vi -> v_ex -> ex_cmd -> <individual command> So we should be looking at somewhere around v_ex(). But, in fact, a similar problem is found in all consumers of v_tcmd(): ^C doesn't abort the command being typed, it commits the command instead. That applies both to colon commands and to search commands. In the case of `:w' the problem just gets much worse because interrupted status remains set and blows up the command later. To make things even more complicated, a window resize event behaves much like ^C in that it commits the command being typed, which can have an unwanted result. The NetBSD folks seem to have fixed this bug generally in v_ex.c and v_text.c, but their fix is hackish, too: they now pretend that ^C or a window resize event is the same as <Esc>. What perhaps is needed is a clear indication from v_txt() to its caller that a special event ended text input, so that it can be up to the caller to decide how to handle the event. But for now the ^C bug can be fixed quickly as shown in the attached patch. With the patch applied, ^C will commit neither ex commands nor search commands: it'll abort them instead, which makes much more sense IMHO. Yar Index: vi/v_txt.c =================================================================== RCS file: /home/ncvs/src/contrib/nvi/vi/v_txt.c,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 v_txt.c --- vi/v_txt.c 1 Nov 1996 06:45:33 -0000 1.1.1.1 +++ vi/v_txt.c 9 Feb 2008 22:06:02 -0000 @@ -110,6 +110,10 @@ v_tcmd(sp, vp, prompt, flags) sp->lno = vp->m_final.lno; sp->cno = vp->m_final.cno; + /* Interrupt aborts the command. */ + if (INTERRUPTED(sp)) + return (1); + return (0); } Hi, On 2008-02-10, Yar Tikhiy wrote: > I think that you looked in the right direction but applied the fix > at a wrong level. In fact, we shouldn't put a test for INTERRUPTED(sp) > into each ex command's implementation. Agreed. [thanks for good analysis of the problem] > What perhaps is needed is a clear indication from v_txt() to its > caller that a special event ended text input, so that it can be up > to the caller to decide how to handle the event. What do you think about the attached patch? It sets a global state flag when a resize event occurs. I am not sure if it's a good way to do it. > But for now the ^C bug can be fixed quickly as shown in the attached > patch. Looks much better than my original patch. -- Jaakko On Tue, Feb 12, 2008 at 08:02:25PM +0200, Jaakko Heinonen wrote:
>
> On 2008-02-10, Yar Tikhiy wrote:
> > I think that you looked in the right direction but applied the fix
> > at a wrong level. In fact, we shouldn't put a test for INTERRUPTED(sp)
> > into each ex command's implementation.
>
> Agreed.
>
> [thanks for good analysis of the problem]
>
> > What perhaps is needed is a clear indication from v_txt() to its
> > caller that a special event ended text input, so that it can be up
> > to the caller to decide how to handle the event.
>
> What do you think about the attached patch? It sets a global state flag
> when a resize event occurs. I am not sure if it's a good way to do it.
Well, on the one hand, it's exactly the way interrupt events are
handled by nvi now. But, on the other hand, using a global state
flag has a remarkable downside: We'll have to remember to clear
it in each code path where it can be set. Otherwise problems similar
to this one will be likely to arise.
Upon a second thought, I'd rather follow the NetBSD way of dealing
with this issue. Their way was hackish not for nothing: it had to
deal with such complex cases of nvi text input as file name completion
and former input replay.
As a general remark, the NetBSD folks have invested a considerable
effort in fixing nvi bugs, and we may want to investigate if it would
be possible to borrow their patches and apply them to our tree.
--
Yar
Hi,
On 2008-02-15, Yar Tikhiy wrote:
> Upon a second thought, I'd rather follow the NetBSD way of dealing
> with this issue. Their way was hackish not for nothing: it had to
> deal with such complex cases of nvi text input as file name completion
> and former input replay.
I have obtained a patch series from NetBSD to fix the ^C and SIGWINCH
problems. The series contains also all other NetBSD bug fixes for v_txt.c
excluding fixes for compile warnings. Also OpeBSD seems to use the same
^C fix.
I have attached the patches including the original NetBSD cvs log
messages to this mail.
--
Jaakko
Responsible Changed From-To: freebsd-bugs->jh Take. Author: jh Date: Fri May 28 09:30:13 2010 New Revision: 208612 URL: http://svn.freebsd.org/changeset/base/208612 Log: Fixes from NetBSD for nvi visual mode: - Fix handling of ^@ when reading an ex command. Don't try to replay the previous input. - Fix handling of ^C in insert mode and when reading an ex command. Repeating an interrupted input could cause a crash and interrupting ex command input could cause a file corruption. - Fix a bug which causes crashes in file name completion when a file name is longer than the screen width. - When an error occurs in v_txt(), leave the input mode. PR: bin/21089, bin/136393 Obtained from: NetBSD Modified: head/contrib/nvi/vi/v_ex.c head/contrib/nvi/vi/v_txt.c Modified: head/contrib/nvi/vi/v_ex.c ============================================================================== --- head/contrib/nvi/vi/v_ex.c Fri May 28 09:26:53 2010 (r208611) +++ head/contrib/nvi/vi/v_ex.c Fri May 28 09:30:13 2010 (r208612) @@ -428,6 +428,10 @@ v_ex(sp, vp) if (tp->term == TERM_BS) break; + /* If the user changed their mind, return. */ + if (tp->term != TERM_OK) + break; + /* Log the command. */ if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp)) return (1); Modified: head/contrib/nvi/vi/v_txt.c ============================================================================== --- head/contrib/nvi/vi/v_txt.c Fri May 28 09:26:53 2010 (r208611) +++ head/contrib/nvi/vi/v_txt.c Fri May 28 09:30:13 2010 (r208612) @@ -510,15 +510,6 @@ next: if (v_event_get(sp, evp, 0, ec_fla case E_EOF: F_SET(sp, SC_EXIT_FORCE); return (1); - case E_INTERRUPT: - /* - * !!! - * Historically, <interrupt> exited the user from text input - * mode or cancelled a colon command, and returned to command - * mode. It also beeped the terminal, but that seems a bit - * excessive. - */ - goto k_escape; case E_REPAINT: if (vs_repaint(sp, &ev)) return (1); @@ -526,10 +517,37 @@ next: if (v_event_get(sp, evp, 0, ec_fla case E_WRESIZE: /* <resize> interrupts the input mode. */ v_emsg(sp, NULL, VIM_WRESIZE); - goto k_escape; + /* FALLTHROUGH */ default: - v_event_err(sp, evp); - goto k_escape; + if (evp->e_event != E_INTERRUPT && evp->e_event != E_WRESIZE) + v_event_err(sp, evp); + /* + * !!! + * Historically, <interrupt> exited the user from text input + * mode or cancelled a colon command, and returned to command + * mode. It also beeped the terminal, but that seems a bit + * excessive. + */ + /* + * If we are recording, morph into <escape> key so that + * we can repeat the command safely: there is no way to + * invalidate the repetition of an instance of a command, + * which would be the alternative possibility. + * If we are not recording (most likely on the command line), + * simply discard the input and return to command mode + * so that an INTERRUPT doesn't become for example a file + * completion request. -aymeric + */ + if (LF_ISSET(TXT_RECORD)) { + evp->e_event = E_CHARACTER; + evp->e_c = 033; + evp->e_flags = 0; + evp->e_value = K_ESCAPE; + break; + } else { + tp->term = TERM_ESC; + goto k_escape; + } } /* @@ -539,7 +557,7 @@ next: if (v_event_get(sp, evp, 0, ec_fla * This was not documented as far as I know, and is a great test of vi * clones. */ - if (rcol == 0 && !LF_ISSET(TXT_REPLAY) && evp->e_c == '\0') { + if (LF_ISSET(TXT_RECORD) && rcol == 0 && evp->e_c == '\0') { if (vip->rep == NULL) goto done; @@ -1456,6 +1474,7 @@ done: /* Leave input mode. */ err: alloc_err: + F_CLR(sp, SC_TINPUT); txt_err(sp, &sp->tiq); return (1); } @@ -2216,8 +2235,8 @@ txt_fc_col(sp, argc, argv) /* If the largest file name is too large, just print them. */ if (colwidth > sp->cols) { - p = msg_print(sp, av[0]->bp + prefix, &nf); for (ac = argc, av = argv; ac > 0; --ac, ++av) { + p = msg_print(sp, av[0]->bp + prefix, &nf); (void)ex_printf(sp, "%s\n", p); if (F_ISSET(gp, G_INTERRUPTED)) break; _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" State Changed From-To: analyzed->patched Patched in head (r208611). Author: jh Date: Sun Aug 8 07:34:37 2010 New Revision: 211060 URL: http://svn.freebsd.org/changeset/base/211060 Log: MFC r208612: Fixes from NetBSD for nvi visual mode PR: bin/21089, bin/136393 Modified: stable/8/contrib/nvi/vi/v_ex.c stable/8/contrib/nvi/vi/v_txt.c Directory Properties: stable/8/contrib/nvi/ (props changed) Modified: stable/8/contrib/nvi/vi/v_ex.c ============================================================================== --- stable/8/contrib/nvi/vi/v_ex.c Sun Aug 8 07:04:27 2010 (r211059) +++ stable/8/contrib/nvi/vi/v_ex.c Sun Aug 8 07:34:37 2010 (r211060) @@ -428,6 +428,10 @@ v_ex(sp, vp) if (tp->term == TERM_BS) break; + /* If the user changed their mind, return. */ + if (tp->term != TERM_OK) + break; + /* Log the command. */ if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp)) return (1); Modified: stable/8/contrib/nvi/vi/v_txt.c ============================================================================== --- stable/8/contrib/nvi/vi/v_txt.c Sun Aug 8 07:04:27 2010 (r211059) +++ stable/8/contrib/nvi/vi/v_txt.c Sun Aug 8 07:34:37 2010 (r211060) @@ -510,15 +510,6 @@ next: if (v_event_get(sp, evp, 0, ec_fla case E_EOF: F_SET(sp, SC_EXIT_FORCE); return (1); - case E_INTERRUPT: - /* - * !!! - * Historically, <interrupt> exited the user from text input - * mode or cancelled a colon command, and returned to command - * mode. It also beeped the terminal, but that seems a bit - * excessive. - */ - goto k_escape; case E_REPAINT: if (vs_repaint(sp, &ev)) return (1); @@ -526,10 +517,37 @@ next: if (v_event_get(sp, evp, 0, ec_fla case E_WRESIZE: /* <resize> interrupts the input mode. */ v_emsg(sp, NULL, VIM_WRESIZE); - goto k_escape; + /* FALLTHROUGH */ default: - v_event_err(sp, evp); - goto k_escape; + if (evp->e_event != E_INTERRUPT && evp->e_event != E_WRESIZE) + v_event_err(sp, evp); + /* + * !!! + * Historically, <interrupt> exited the user from text input + * mode or cancelled a colon command, and returned to command + * mode. It also beeped the terminal, but that seems a bit + * excessive. + */ + /* + * If we are recording, morph into <escape> key so that + * we can repeat the command safely: there is no way to + * invalidate the repetition of an instance of a command, + * which would be the alternative possibility. + * If we are not recording (most likely on the command line), + * simply discard the input and return to command mode + * so that an INTERRUPT doesn't become for example a file + * completion request. -aymeric + */ + if (LF_ISSET(TXT_RECORD)) { + evp->e_event = E_CHARACTER; + evp->e_c = 033; + evp->e_flags = 0; + evp->e_value = K_ESCAPE; + break; + } else { + tp->term = TERM_ESC; + goto k_escape; + } } /* @@ -539,7 +557,7 @@ next: if (v_event_get(sp, evp, 0, ec_fla * This was not documented as far as I know, and is a great test of vi * clones. */ - if (rcol == 0 && !LF_ISSET(TXT_REPLAY) && evp->e_c == '\0') { + if (LF_ISSET(TXT_RECORD) && rcol == 0 && evp->e_c == '\0') { if (vip->rep == NULL) goto done; @@ -1456,6 +1474,7 @@ done: /* Leave input mode. */ err: alloc_err: + F_CLR(sp, SC_TINPUT); txt_err(sp, &sp->tiq); return (1); } @@ -2216,8 +2235,8 @@ txt_fc_col(sp, argc, argv) /* If the largest file name is too large, just print them. */ if (colwidth > sp->cols) { - p = msg_print(sp, av[0]->bp + prefix, &nf); for (ac = argc, av = argv; ac > 0; --ac, ++av) { + p = msg_print(sp, av[0]->bp + prefix, &nf); (void)ex_printf(sp, "%s\n", p); if (F_ISSET(gp, G_INTERRUPTED)) break; _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" Author: jh Date: Wed Sep 8 18:06:05 2010 New Revision: 212328 URL: http://svn.freebsd.org/changeset/base/212328 Log: MFC r208612: Fixes from NetBSD for nvi visual mode PR: bin/21089, bin/136393 Modified: stable/7/contrib/nvi/vi/v_ex.c stable/7/contrib/nvi/vi/v_txt.c Directory Properties: stable/7/contrib/nvi/ (props changed) Modified: stable/7/contrib/nvi/vi/v_ex.c ============================================================================== --- stable/7/contrib/nvi/vi/v_ex.c Wed Sep 8 18:03:40 2010 (r212327) +++ stable/7/contrib/nvi/vi/v_ex.c Wed Sep 8 18:06:05 2010 (r212328) @@ -428,6 +428,10 @@ v_ex(sp, vp) if (tp->term == TERM_BS) break; + /* If the user changed their mind, return. */ + if (tp->term != TERM_OK) + break; + /* Log the command. */ if (O_STR(sp, O_CEDIT) != NULL && v_ecl_log(sp, tp)) return (1); Modified: stable/7/contrib/nvi/vi/v_txt.c ============================================================================== --- stable/7/contrib/nvi/vi/v_txt.c Wed Sep 8 18:03:40 2010 (r212327) +++ stable/7/contrib/nvi/vi/v_txt.c Wed Sep 8 18:06:05 2010 (r212328) @@ -510,15 +510,6 @@ next: if (v_event_get(sp, evp, 0, ec_fla case E_EOF: F_SET(sp, SC_EXIT_FORCE); return (1); - case E_INTERRUPT: - /* - * !!! - * Historically, <interrupt> exited the user from text input - * mode or cancelled a colon command, and returned to command - * mode. It also beeped the terminal, but that seems a bit - * excessive. - */ - goto k_escape; case E_REPAINT: if (vs_repaint(sp, &ev)) return (1); @@ -526,10 +517,37 @@ next: if (v_event_get(sp, evp, 0, ec_fla case E_WRESIZE: /* <resize> interrupts the input mode. */ v_emsg(sp, NULL, VIM_WRESIZE); - goto k_escape; + /* FALLTHROUGH */ default: - v_event_err(sp, evp); - goto k_escape; + if (evp->e_event != E_INTERRUPT && evp->e_event != E_WRESIZE) + v_event_err(sp, evp); + /* + * !!! + * Historically, <interrupt> exited the user from text input + * mode or cancelled a colon command, and returned to command + * mode. It also beeped the terminal, but that seems a bit + * excessive. + */ + /* + * If we are recording, morph into <escape> key so that + * we can repeat the command safely: there is no way to + * invalidate the repetition of an instance of a command, + * which would be the alternative possibility. + * If we are not recording (most likely on the command line), + * simply discard the input and return to command mode + * so that an INTERRUPT doesn't become for example a file + * completion request. -aymeric + */ + if (LF_ISSET(TXT_RECORD)) { + evp->e_event = E_CHARACTER; + evp->e_c = 033; + evp->e_flags = 0; + evp->e_value = K_ESCAPE; + break; + } else { + tp->term = TERM_ESC; + goto k_escape; + } } /* @@ -539,7 +557,7 @@ next: if (v_event_get(sp, evp, 0, ec_fla * This was not documented as far as I know, and is a great test of vi * clones. */ - if (rcol == 0 && !LF_ISSET(TXT_REPLAY) && evp->e_c == '\0') { + if (LF_ISSET(TXT_RECORD) && rcol == 0 && evp->e_c == '\0') { if (vip->rep == NULL) goto done; @@ -1456,6 +1474,7 @@ done: /* Leave input mode. */ err: alloc_err: + F_CLR(sp, SC_TINPUT); txt_err(sp, &sp->tiq); return (1); } @@ -2216,8 +2235,8 @@ txt_fc_col(sp, argc, argv) /* If the largest file name is too large, just print them. */ if (colwidth > sp->cols) { - p = msg_print(sp, av[0]->bp + prefix, &nf); for (ac = argc, av = argv; ac > 0; --ac, ++av) { + p = msg_print(sp, av[0]->bp + prefix, &nf); (void)ex_printf(sp, "%s\n", p); if (F_ISSET(gp, G_INTERRUPTED)) break; _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" State Changed From-To: patched->closed Fixed in head, stable/8 and stable/7. |