From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 25286 invoked by alias); 27 Jan 2012 05:00:28 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 30128 Received: (qmail 10803 invoked from network); 27 Jan 2012 05:00:15 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 Received-SPF: none (ns1.primenet.com.au: domain at closedmail.com does not designate permitted sender hosts) From: Bart Schaefer Message-id: <120126205957.ZM2607@torch.brasslantern.com> Date: Thu, 26 Jan 2012 20:59:57 -0800 In-reply-to: <20120126205702.6c3e2ab2@pws-pc.ntlworld.com> Comments: In reply to Peter Stephenson "Re: Obscure zsh history overflow with segfault" (Jan 26, 8:57pm) References: <87ty3q5ffx.fsf@gmail.com> <20120121023957.GA2643@daniel3.local> <120124122819.ZM31632@torch.brasslantern.com> <20120126205702.6c3e2ab2@pws-pc.ntlworld.com> X-Mailer: OpenZMail Classic (0.9.2 24April2005) To: zsh-workers@zsh.org Subject: Re: Obscure zsh history overflow with segfault MIME-version: 1.0 Content-type: text/plain; charset=us-ascii On Jan 26, 8:57pm, Peter Stephenson wrote: } Subject: Re: Obscure zsh history overflow with segfault } } On Tue, 24 Jan 2012 12:28:19 -0800 } } > 1521 if (last >= curhist) { } > 1522 last = curhist - 1; } > 1523 if (first > last) { } > 1529 return 1; } > } > In the situation in this bug, first > last is true but last >= curhist } > is false. I believe that means that even though this is an infinite } > loop, we don't detect that it will be. } } I'm not really following the problem, but do you mean something like } this? } } + if (first > last) { } + zwarnnam("fc", "history events are in wrong order, aborted"); } + if (f != stdout) } + fclose(f); } + return 1; } + } That would catch some nonsense inputs, but it doesn't prevent infinite recursion on other nonsense, so the question is whether to bother with catching nonsense at all, or just toss up our hands and say "garbage in, garbage out." Here's the easiest way to reproduce from "zsh -f": % echo Start here Start here % r 1 echo Start here % r 2 At this point "r 2" loads the command "r 1 echo" and executes it. This in turn runs all the commands from event 1 to event 3, which happens to include event 2, which is "r 1 echo" again, and we loop. Even if the original event 2 falls off the top due to HISTSIZE, there is always another "echo" to be found, and always another "r 1 echo" somewhere between the mininum history number and the "echo", so we never run out of "r 1 echo" commands until we run out of stack space to keep calling loop() recursively out of bin_fc(). The case of "r 100 foo" is the same thing except that the "too large" number 100 is treated as curhist. Incidentally, in zsh 4.2.x it was possible to stop this recursion with a tty interrupt, but in 4.3.13 the interrupt is ignored and the loop runs until stack overflow causes a segfault. There are definitely some signal handling "improvements" that have caused edge case regression in recent revisions. My other point was that one way to prevent the infinite recursion is to prevent *any* recursion: --- Src/builtin.c 20 Dec 2011 17:13:38 -0000 1.52 +++ Src/builtin.c 24 Jan 2012 20:54:08 -0000 @@ -1532,6 +1532,7 @@ ops->ind['n'] = 1; /* No line numbers here. */ if (!fclist(out, ops, first, last, asgf, pprog)) { char *editor; + static char *loop_editor = 0; if (func == BIN_R) editor = "-"; @@ -1545,12 +1546,19 @@ editor = DEFAULT_FCEDIT; unqueue_signals(); - if (fcedit(editor, fil)) { + if (loop_editor) { + zwarnnam("fc", + "-e %s would recurse, aborted", + loop_editor); + retval = 1; + } else if (fcedit(editor, fil)) { if (stuff(fil)) zwarnnam("fc", "%e: %s", errno, s); else { + loop_editor = editor; loop(0,1); retval = lastval; + loop_editor = 0; } } } else However, that may be too draconian. A static counter could be used to allow some limited recursion depth (as for recursive functions), but again it may be better just to say PEBKAC.