Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Crash when completion script call itself.

On Tue, Oct 3, 2017 at 4:45 PM, Kamil Dudka <kdudka@xxxxxxxxxx> wrote:
> On Monday, October 2, 2017 5:40:18 PM CEST Peter Stephenson wrote:
>> On Fri, 29 Sep 2017 15:16:14 +0100
>> Peter Stephenson <p.stephenson@xxxxxxxxxxx> wrote:
>> > I see this flag introduces a heuristic based on frame size, so tweaking
>> > memory management internally might have a similar but more controllable
>> > effect; on the other hand, it simultaneously removes any easy trade-off
>> > you can make directly using compiler flags, and I'm not keen on
>> > introducing #ifdef's where one branch would be underused and rot.
>> This looks like low-hanging fruit.  Allocating memory to save over a
>> shell function happens just at the point where we've created the new
>> heap for the function, which expires immediately after the call.  The
>> allocation itself should take very little time and on most architectures
>> accessing the structure should have a similar overhead to accessing the
>> stack.
> I was experimenting with a similar, slightly smaller, patch in April:
> http://www.zsh.org/mla/workers/2017/msg00630.html
> Now I tried to run the following command on my system:
> % FUNCNEST=4096 Src/zsh -c 'i=0; fn() { print $(( ++i )); fn; }; fn'
> With the current upstream HEAD, it counted to 1180.  With my old patch,
> it counted to 1224.  With your current patch, it counted to 1242.
> The difference becomes slightly more significant when zsh is compiled
> with -fconserve-stack.  Then it counts to 2682 with the current version
> and 3024 with your patch applied.

If you want to do very deep nesting you can always increase the stack
limit with ulimit -s (it's 8192kB on most distributions by default I
believe). For example if I set it to 256 the above command only counts
to 29, with ulimit -s unlimited I got this cool error with a higher
fn: maximum nested function level reached; increase FUNCNEST?
 parse.c:2745: Overlarge EPROG nref
 parse.c:2745: Overlarge EPROG nref
 parse.c:2745: Overlarge EPROG nref
 parse.c:2745: Overlarge EPROG nref
but looking at the code that's just a debug code error, it only
compares with the defined limit rather than the runtime limit. With a
very high FUNCNEST it just keeps running until I run out of physical
RAM, I had to ctrl-c at 92375.

Does this look right?

diff --git i/Src/parse.c w/Src/parse.c
index 6e0856bbc1..ee1a1230ba 100644
--- i/Src/parse.c
+++ w/Src/parse.c
@@ -2742,7 +2742,7 @@ freeeprog(Eprog p)
        DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0");
        DPUTS(p->nref < -1, "Uninitialised EPROG nref");
-       DPUTS(p->nref > MAX_FUNCTION_DEPTH + 10, "Overlarge EPROG nref");
+       DPUTS(zsh_funcnest >= 0 && p->nref > zsh_funcnest + 10,
"Overlarge EPROG nref");
        if (p->nref > 0 && !--p->nref) {
            for (i = p->npats, pp = p->pats; i--; pp++)

Mikael Magnusson

Messages sorted by: Reverse Date, Date, Thread, Author