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:
parent
64d04e717b
commit
56805b25af
10 changed files with 75 additions and 18 deletions
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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++);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue