mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-12-29 16:25:35 +01:00
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.
This commit is contained in:
parent
d6e69b7299
commit
8f5fe841a6
3 changed files with 49 additions and 1 deletions
|
@ -1,3 +1,8 @@
|
|||
2023-04-17 Peter Stephenson <p.stephenson@samsung.com>
|
||||
|
||||
* 51652 (plus typo correction): Src/exec.c, Test/C03traps.ztst:
|
||||
fix running of TRAPEXIT explicitly.
|
||||
|
||||
2023-04-11 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
|
||||
|
||||
* 51639: Doc/Zsh/params.yo, Src/init.c, configure.ac: add new
|
||||
|
|
34
Src/exec.c
34
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();
|
||||
|
||||
/*
|
||||
|
|
|
@ -1083,6 +1083,17 @@ F:Must be tested with a top-level script rather than source or function
|
|||
>trap1
|
||||
# As of 5.7.1-test-2, the output was "out1 fn1 trap1 fn2" (on separate lines).
|
||||
|
||||
TRAPEXIT() { echo This is TRAPEXIT; }
|
||||
TRAPEXIT
|
||||
TRAPEXIT
|
||||
TRAPEXIT
|
||||
0:No memory problems with explicit call to TRAPEXIT.
|
||||
>This is TRAPEXIT
|
||||
>This is TRAPEXIT
|
||||
>This is TRAPEXIT
|
||||
>This is TRAPEXIT
|
||||
# Three explicit calls, one implicit call at function exit.
|
||||
|
||||
%clean
|
||||
|
||||
rm -f TRAPEXIT
|
||||
|
|
Loading…
Reference in a new issue