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

@ -65,7 +65,7 @@ extern Sfio_t _Stk_data;
extern Stk_t* stkopen(int);
extern Stk_t* stkinstall(Stk_t*, char*(*)(int));
extern int stkclose(Stk_t*);
extern int stklink(Stk_t*);
extern unsigned int stklink(Stk_t*);
extern char* stkalloc(Stk_t*, size_t);
extern char* stkcopy(Stk_t*, const char*);
extern char* stkset(Stk_t*, char*, size_t);

View file

@ -12,7 +12,7 @@
Stak_t *stakcreate(int \fIflags\fP);
Stak_t *stakinstall(Stak_t *\fIstack\fP, char *(\fIoverflow\fP)(int));
int stakdelete(Stak_t *\fIstack\fP);
void staklink(Stak_t *\fIstack\fP)
unsigned int staklink(Stak_t *\fIstack\fP)
char *stakalloc(unsigned \fIsize\fP);
char *stakcopy(const char *\fIstring\fP);
@ -62,7 +62,7 @@ If successful,
count is 1.
Otherwise, \f5stakcreate\fP() returns a null pointer.
The \f5staklink\fP() function increases the reference count for the
given \fIstack\fP.
given \fIstack\fP and returns the increased count.
The \f5stakinstall\fP() function
makes the specified \fIstack\fP the active stack and returns a pointer
to the previous active stack.

View file

@ -12,7 +12,7 @@
Stk_t *stkopen(int \fIflags\fP);
Stk_t *stkinstall(Stk_t *\fIstack\fP, char *(\fIoverflow\fP)(int));
int stkclose(Stk_t *\fIstack\fP);
void stklink(Stk_t *\fIstack\fP)
unsigned int stklink(Stk_t *\fIstack\fP)
char *stkalloc(Stk_t *\fIstack\fP, unsigned \fIsize\fP);
char *stkcopy(Stk_t *\fIstack\fP, const char *\fIstring\fP);
@ -63,7 +63,7 @@ If successful,
count is 1.
Otherwise, \f5stkopen\fP() returns a null pointer.
The \f5stklink\fP() function increases the reference count for the
given \fIstack\fP.
given \fIstack\fP and returns the increased count.
The \f5stkinstall\fP() function
makes the specified \fIstack\fP the active stack and returns a pointer
to the previous active stack.

View file

@ -76,7 +76,7 @@ struct frame
struct stk
{
_stk_overflow_ stkoverflow; /* called when malloc fails */
short stkref; /* reference count; */
unsigned int stkref; /* reference count */
short stkflags; /* stack attributes */
char *stkbase; /* beginning of current stack frame */
char *stkend; /* end of current stack frame */
@ -152,7 +152,7 @@ static int stkexcept(register Sfio_t *stream, int type, void* val, Sfdisc_t* dp)
register struct stk *sp = stream2stk(stream);
register char *cp = sp->stkbase;
register struct frame *fp;
if(--sp->stkref<=0)
if(--sp->stkref == 0)
{
increment(delete);
if(stream==stkstd)
@ -294,7 +294,7 @@ Sfio_t *stkinstall(Sfio_t *stream, _stk_overflow_ oflow)
/*
* increase the reference count on the given <stack>
*/
int stklink(register Sfio_t* stream)
unsigned int stklink(register Sfio_t* stream)
{
register struct stk *sp = stream2stk(stream);
return(sp->stkref++);