Date: Wed, 19 Apr 2000 16:20:02 -0700 (PDT) From: Anatoly Vorobey <mellon@pobox.com> To: freebsd-bugs@FreeBSD.org Subject: Re: bin/3170: vi freaks and dump core if user doesn't exist Message-ID: <200004192320.QAA64259@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/3170; it has been noted by GNATS. From: Anatoly Vorobey <mellon@pobox.com> To: Bill Fenner <fenner@research.att.com> Cc: freebsd-gnats-submit@FreeBSD.ORG Subject: Re: bin/3170: vi freaks and dump core if user doesn't exist Date: Thu, 20 Apr 2000 02:13:26 +0000 I've tracked down the bug to a fundamental conflict between vi's refresh engine and its warning display engine. The reason "deleted user" is at all relevant for reproducing the bug is that vi in that case tries to display two warnings at once (about nonexistent user and about impossibility of recovering the file in case of failure). In such a case, vi will want to prompt user with "Press a key to continue" and until it does, it won't refresh the screen; but if this whole condition was caused by a multiple-chars key (such as Up, mapped to Esc-something), then it also won't display the prompt until the rest of the chars in the buffer are processed, and to do that it needs to refresh the screen. Hence, a deadlock. The bug is there in all nvi versions including the latest one. That was a tricky bastard. I've no idea how to fix it though, the refresh code is a living nightmare and several of straightforward attempts were to no avail. I attach for the reference a message I sent to the maintainer a few days ago. Date: Mon, 17 Apr 2000 01:08:45 +0000 From: Anatoly Vorobey <mellon@pobox.com> To: bostic@bostic.com Subject: an nvi bug Dear Keith, I've been trying to find the bug which apparently has been in nvi for quite some time, and is currently manifestable e.g. in all versions of FreeBSD (I work with -CURRENT). Although FreeBSD uses an old version, I just verified that the bug is still there in 1.79. There's some description of how to repeat the bug at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/3170 ; and see also below for more exact reproduction which never fails. Reproduction: Create a user, login as the user, delete the user with vipw(1) while the user stays logged in. Now the user goes into vi and tries to edit a small file with several rows (I used his default ~/.login_conf, for example). Immediately after invoking vi with the filename at command line, the user presses 'i', then preses Enter until all but the first line of the file have scrolled down and the first line is on the last screen row, and at that moment he presses the Up key. vi tried to display the warning about nonexistent user and impossibility of recovering the file, freaks, hangs and eventually dumps core. On the other hand, if instead of the Up key you simply press Esc, vi successfully displays the warning, lets you press a key to continue and goes on fine. I think I've found what the reason is, but I don't know the best way to fix the bug, hence this letter. The fact that the user has been deleted is only relevant insomuch as vi tries to present two-line warning (two separate warnings in fact) with calls to msgq(). The warnings come from rcv_init() and rcv_mailfile(), and rcv_init() is called from bd_set() which is the first function to be called by txt_resolve() in order to finally assimilate the inputed text into the file (it's followed by a bunch of bd_append()'s which are irrelevant). Now when the user pressed the Up key, the first character to register was Escape, with more mapped ones on the way. Escape triggered txt_resolve() and eventual exit from the 'insert' function in v_itxt.c which was working all along till now since we started by Inserting. As the control goes one more time through the main loop of vi.c, we see: /* Resolve messages. */ if (!MAPPED_KEYS_WAITING(sp) && vs_resolve(sp, NULL, 0)) goto ret; /* * If not skipping a refresh, return to command mode and * refresh the screen. */ if (F_ISSET(vip, VIP_S_REFRESH)) F_CLR(vip, VIP_S_REFRESH); else { sp->showmode = SM_COMMAND; if (vs_refresh(sp, 0)) goto ret; } Now when the user was pressing Escape, the !MAPPED_KEYS_WAITING condition succeeded and vs_resolve() was called, which called vs_scroll(), and the latter displayed the "press any key" line and after pressing a key cleared up the two lines of scrolled warnings that were still there. But with a mapped key such as Up, the condition fails, and the control goes straight to vs_refresh(). Maybe vs_refresh() should be denied running until all remaining chars keys have been processed? I am not sure. Anyway, vs_refresh() goes to vs_paint() and only asks it to UPDATE_CURSOR. vs_paint() eventually needs to call vs_line() to find out where the cursor is. But in the beginning of vs_line(): /* * If ex modifies the screen after ex output is already on the * screen\ * don't touch it -- we'll get scrolling wrong, at best. */ if (!F_ISSET(sp, SC_TINPUT_INFO) && VIP(sp)->totalcount > 1) return (0); if (F_ISSET(sp, SC_SCR_EXWROTE) && smp - HMAP != LASTLINE(sp)) return (0); The first test succeeds, since totalcount *is* >1 as we have two warnings pending on the screen -- and vs_line() immediately returns. vs_paint() freaks and calls itself recursively with the same flags, and we have an infinite recursion which gives way to the dump core when the stack is exhausted. That's it. In the case of Escape key, vs_resolve() had been called earlier and cleared totalcount, so the test fails and vs_line() dutifully does its work. However, one obviously can't introduce a call to vs_resolve() before the mapped characters have been processed. So I don't know exactly how to handle this best; the source of vs_paint() and friends is too complicated for me. Hopefully you'll know what to do with it, and please drop a line if you do so that I could submit a patch to the FreeBSD tree as well. Thanks, and all the best, Anatoly. -- Anatoly Vorobey, mellon@pobox.com http://pobox.com/~mellon/ "Angels can fly because they take themselves lightly" - G.K.Chesterton -- Anatoly Vorobey, mellon@pobox.com http://pobox.com/~mellon/ "Angels can fly because they take themselves lightly" - G.K.Chesterton To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200004192320.QAA64259>