diff options
author | Peter Stephenson <p.stephenson@samsung.com> | 2023-04-17 09:30:34 +0100 |
---|---|---|
committer | Peter Stephenson <p.stephenson@samsung.com> | 2023-04-17 09:30:34 +0100 |
commit | 8f5fe841a63fecdab4416578653549689f2c592f (patch) | |
tree | 3d4385680711236021e38f2705c1e01baa65a46d /Src/exec.c | |
parent | d6e69b72990f42549fbe8fc54dd7edd14bc66701 (diff) | |
download | zsh-8f5fe841a63fecdab4416578653549689f2c592f.tar.gz zsh-8f5fe841a63fecdab4416578653549689f2c592f.tar.xz zsh-8f5fe841a63fecdab4416578653549689f2c592f.zip |
51652: fix running of TRAPEXIT explicitly.
This is a special case where TRAPEXIT is unset within a TRAPEXIT as it should never run in a nested context, so just save the function structure temporarily on the heap.
Diffstat (limited to 'Src/exec.c')
-rw-r--r-- | Src/exec.c | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/Src/exec.c b/Src/exec.c index 3b3d1235e..8f9d5a885 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -5779,12 +5779,25 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) char *name = shfunc->node.nam; int flags = shfunc->node.flags; char *fname = dupstring(name); - Eprog prog; + Eprog prog, marked_prog; static int oflags; static int funcdepth; Heap funcheap; queue_signals(); /* Lots of memory and global state changes coming */ + /* + * In case this is a special function such as a trap, mark it + * as in use right now, so it doesn't get freed early. The + * worst that can happen is this hangs around in memory a little + * longer than strictly needed. + * + * Classic example of this happening is running TRAPEXIT directly. + * + * Because the shell function's contents may change, we'll ensure + * we use a consistent structure for use / free. + */ + marked_prog = shfunc->funcdef; + useeprog(marked_prog); NEWHEAPS(funcheap) { /* @@ -5818,6 +5831,22 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) memcpy(funcsave->pipestats, pipestats, bytes); } + if (!strcmp(fname, "TRAPEXIT")) { + /* + * If we are executing TRAPEXIT directly, starttrapscope() + * will pull the rug out from under us to ensure the + * exit trap isn't run inside the function. We just need + * the information locally here, so copy it on the heap. + * + * The funcdef is separately handled by reference counting. + */ + Shfunc shcopy = (Shfunc)zhalloc(sizeof(struct shfunc)); + memcpy(shcopy, shfunc, sizeof(struct shfunc)); + shcopy->node.nam = dupstring(shfunc->node.nam); + shfunc = shcopy; + name = shfunc->node.nam; + } + starttrapscope(); startpatternscope(); @@ -5942,6 +5971,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) funcsave->fstack.filename = getshfuncfile(shfunc); prog = shfunc->funcdef; + DPUTS1(!prog->nref, "function definition %s has zero reference count", + (fname && *fname) ? fname : "<anon>"); if (prog->flags & EF_RUN) { Shfunc shf; @@ -6046,6 +6077,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) } } OLDHEAPS; + freeeprog(marked_prog); unqueue_signals(); /* |