1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix leak and crash upon defining functions in subshells

A memory leak occurred upon leaving a virtual subshell if a
function was defined within it. If this was done more than 32766
(= 2^15-2 = the 'short' max value - 1) times, the shell crashed.
Discussion and reproducer: https://github.com/ksh93/ksh/issues/114

src/cmd/ksh93/sh/subshell.c: table_unset():
- A subshell-defined function was never freed because a broken
  check for autoloaded functions (which must not be freed[*]). It
  looked for an initial '/' in the canonical path of the script
  file that defined the function, but that path is also stored for
  regular functions. Now use a check that executes nv_search() in
  fpathdict, the same method used in _nv_unset() in name.c for a
  regular function unset.

src/cmd/ksh93/bltins/misc.c: b_dot_cmd():
- Fix an additional memory leak introduced in bd88cc7f, that caused
  POSIX functions (which are run with b_dot_cmd() like dot scripts)
  to leak extra. This fix avoids both the crash fixed there and the
  memory leak by introducing a 'tofree' variable remembering the
  filename to free. Thanks to Johnothan King for the patch.

src/lib/libast/include/stk.h,
src/lib/libast/misc/stk.c,
src/lib/libast/man/stk.3,
src/lib/libast/man/stak.3:
- Make the stack more resilient by extending the stack reference
  counter 'stkref' from (signed) short to unsigned int. On modern
  systems with 32-bit ints, this extends the maximum number of
  elements on a stack from 2^15-1==32767 to 2^32-1==4294967295.
  The ref counter can never be negative, so there is no reason for
  signedness. sizeof(int) is defined as the size of a single CPU
  word, so this should not affect performance at all.
     On a 16-bit system (not that ksh still compiles there), this
  doubles the max number of entries to 2^16-1=65535.

src/cmd/ksh93/tests/leaks.sh:
- Add leak regression tests for ksh functions, POSIX functions, dot
  scripts run with '.', and dot scripts run with 'source'.

src/cmd/ksh93/tests/path.sh:
- Add an output builtin with a redirect to an autoloaded function
  so that a crash[*] is triggered if the check for an autoloaded
  function is ever removed from table_unset(), as was done in ksh
  93v- (which crashed).

[*] Freeing autoloaded functions after leaving a virtual subshell
    causes a crashing bug: https://github.com/att/ast/issues/803

Co-authored-by: Johnothan King <johnothanking@protonmail.com>
Fixes: https://github.com/ksh93/ksh/issues/114
This commit is contained in:
Martijn Dekker 2020-08-13 23:29:27 +01:00
parent 64d04e717b
commit 56805b25af
10 changed files with 75 additions and 18 deletions

View file

@ -397,7 +397,11 @@ Dt_t *sh_subfuntree(int create)
return(sp->shp->fun_tree);
}
static void table_unset(register Dt_t *root,int fun)
/*
* Remove and free a subshell table at *root after leaving a virtual subshell.
* Pass 'fun' as nonzero when removing a subshell's shell functions.
*/
static void table_unset(Shell_t *shp,register Dt_t *root,int fun)
{
register Namval_t *np,*nq;
int flag;
@ -405,7 +409,9 @@ static void table_unset(register Dt_t *root,int fun)
{
nq = (Namval_t*)dtnext(root,np);
flag=0;
if(fun && np->nvalue.rp && np->nvalue.rp->fname && *np->nvalue.rp->fname=='/')
/* Check for autoloaded function; it must not be freed. */
if(fun && np->nvalue.rp && np->nvalue.rp->fname && shp->fpathdict
&& nv_search(np->nvalue.rp->fname,shp->fpathdict,0))
{
np->nvalue.rp->fdict = 0;
flag = NV_NOFREE;
@ -693,7 +699,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
if(sp->sfun)
{
shp->fun_tree = dtview(sp->sfun,0);
table_unset(sp->sfun,1);
table_unset(shp,sp->sfun,1);
dtclose(sp->sfun);
}
n = shp->st.trapmax-savst.trapmax;