mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-15 04:32:24 +00:00
Fix crash upon running many subshells (#113)
Co-authored-by: Martijn Dekker <martijn@inlv.org> An intermittent crash occurred after running many thousands of virtual/non-forked subshells. One reproducer is a crash in the shbench fibonacci.ksh test, as documented here: https://github.com/ksh-community/shbench/blob/f3d9e134/bench/fibonacci.ksh#L4-L10 The apparent cause was the signed and insufficiently large 'short' data type of 'curenv' and related variables which wrapped around to a negative number when overflowing. These IDs are necessary for the 'wait' builtin to obtain the exit status from a background job. This fix is inspired by a patch based on ksh 93v-: https://build.opensuse.org/package/view_file/shells/ksh/ksh93-longenv.dif?expand=1 https://src.fedoraproject.org/rpms/ksh/blob/f24/f/ksh-20130628-longer.patch However, we change the type to 'unsigned int' instead of 'long'. On all remotely modern systems, ints are 32-bit values, and using this type avoids a performance degradation on 32-bit sytems. Making them unsigned prevents an overflow to negative values. src/cmd/ksh93/include/defs.h, src/cmd/ksh93/include/jobs.h, src/cmd/ksh93/include/nval.h, src/cmd/ksh93/include/shell.h: - Change the types of the static global 'subenv' and the subshell structure members 'curenv', 'jobenv', 'subenv', 'p_env' and 'subshell' to one consistent type, unsigned int. src/cmd/ksh93/sh/jobs.c, src/cmd/ksh93/sh/macro.c: src/cmd/ksh93/sh/name.c: src/cmd/ksh93/sh/nvtype.c, src/cmd/ksh93/sh/subshell.c: - Updates to match new variable types. src/cmd/ksh93/tests/subshell.sh: - Show wrong exit status in message on failure of 'wait' builtin.
This commit is contained in:
parent
f485fe0f8d
commit
05ac1dbb41
13 changed files with 25 additions and 17 deletions
4
NEWS
4
NEWS
|
@ -3,6 +3,10 @@ For full details, see the git log at: https://github.com/ksh93/ksh
|
||||||
|
|
||||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
|
|
||||||
|
2020-08-11:
|
||||||
|
|
||||||
|
- Fixed an intermittent crash upon running a large number of subshells.
|
||||||
|
|
||||||
2020-08-10:
|
2020-08-10:
|
||||||
|
|
||||||
- A number of fixes have been applied to the printf formatting directives
|
- A number of fixes have been applied to the printf formatting directives
|
||||||
|
|
|
@ -167,8 +167,8 @@ struct shared
|
||||||
Namval_t *prev_table; /* previous table used in nv_open */ \
|
Namval_t *prev_table; /* previous table used in nv_open */ \
|
||||||
Sfio_t *outpool; /* output stream pool */ \
|
Sfio_t *outpool; /* output stream pool */ \
|
||||||
long timeout; /* read timeout */ \
|
long timeout; /* read timeout */ \
|
||||||
short curenv; /* current subshell number */ \
|
unsigned int curenv; /* current subshell number */ \
|
||||||
short jobenv; /* subshell number for jobs */ \
|
unsigned int jobenv; /* subshell number for jobs */ \
|
||||||
int infd; /* input file descriptor */ \
|
int infd; /* input file descriptor */ \
|
||||||
short nextprompt; /* next prompt is PS<nextprompt> */ \
|
short nextprompt; /* next prompt is PS<nextprompt> */ \
|
||||||
short poolfiles; \
|
short poolfiles; \
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct process
|
||||||
unsigned short p_exit; /* exit value or signal number */
|
unsigned short p_exit; /* exit value or signal number */
|
||||||
unsigned short p_exitmin; /* minimum exit value for xargs */
|
unsigned short p_exitmin; /* minimum exit value for xargs */
|
||||||
unsigned short p_flag; /* flags - see below */
|
unsigned short p_flag; /* flags - see below */
|
||||||
int p_env; /* subshell environment number */
|
unsigned int p_env; /* subshell environment number */
|
||||||
#ifdef JOBS
|
#ifdef JOBS
|
||||||
off_t p_name; /* history file offset for command */
|
off_t p_name; /* history file offset for command */
|
||||||
struct termios p_stty; /* terminal state for job */
|
struct termios p_stty; /* terminal state for job */
|
||||||
|
|
|
@ -75,7 +75,7 @@ struct Namfun
|
||||||
{
|
{
|
||||||
const Namdisc_t *disc;
|
const Namdisc_t *disc;
|
||||||
char nofree;
|
char nofree;
|
||||||
unsigned char subshell;
|
unsigned int subshell;
|
||||||
uint32_t dsize;
|
uint32_t dsize;
|
||||||
Namfun_t *next;
|
Namfun_t *next;
|
||||||
char *last;
|
char *last;
|
||||||
|
|
|
@ -143,7 +143,7 @@ struct Shell_s
|
||||||
int exitval; /* most recent exit value */
|
int exitval; /* most recent exit value */
|
||||||
unsigned char trapnote; /* set when trap/signal is pending */
|
unsigned char trapnote; /* set when trap/signal is pending */
|
||||||
char shcomp; /* set when running shcomp */
|
char shcomp; /* set when running shcomp */
|
||||||
short subshell; /* set for virtual subshell */
|
unsigned int subshell; /* set for virtual subshell */
|
||||||
#ifdef _SH_PRIVATE
|
#ifdef _SH_PRIVATE
|
||||||
_SH_PRIVATE
|
_SH_PRIVATE
|
||||||
#endif /* _SH_PRIVATE */
|
#endif /* _SH_PRIVATE */
|
||||||
|
|
|
@ -17,4 +17,4 @@
|
||||||
* David Korn <dgk@research.att.com> *
|
* David Korn <dgk@research.att.com> *
|
||||||
* *
|
* *
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
#define SH_RELEASE "93u+m 2020-08-10"
|
#define SH_RELEASE "93u+m 2020-08-11"
|
||||||
|
|
|
@ -748,7 +748,8 @@ void sh_setmatch(Shell_t *shp,const char *v, int vsize, int nmatch, regoff_t mat
|
||||||
{
|
{
|
||||||
struct match *mp = &ip->SH_MATCH_init;
|
struct match *mp = &ip->SH_MATCH_init;
|
||||||
Namval_t *np = nv_namptr(mp->node,0);
|
Namval_t *np = nv_namptr(mp->node,0);
|
||||||
register int i,n,x, savesub=shp->subshell;
|
register int i,n,x;
|
||||||
|
unsigned int savesub = shp->subshell;
|
||||||
Namarr_t *ap = nv_arrayptr(SH_MATCHNOD);
|
Namarr_t *ap = nv_arrayptr(SH_MATCHNOD);
|
||||||
shp->subshell = 0;
|
shp->subshell = 0;
|
||||||
#ifndef SHOPT_2DMATCH
|
#ifndef SHOPT_2DMATCH
|
||||||
|
|
|
@ -1647,7 +1647,7 @@ static struct process *job_unpost(register struct process *pwtop,int notify)
|
||||||
register struct process *pw;
|
register struct process *pw;
|
||||||
/* make sure all processes are done */
|
/* make sure all processes are done */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
sfprintf(sfstderr,"ksh: job line %4d: drop pid=%d critical=%d pid=%d env=%d\n",__LINE__,getpid(),job.in_critical,pwtop->p_pid,pwtop->p_env);
|
sfprintf(sfstderr,"ksh: job line %4d: drop pid=%d critical=%d pid=%d env=%u\n",__LINE__,getpid(),job.in_critical,pwtop->p_pid,pwtop->p_env);
|
||||||
sfsync(sfstderr);
|
sfsync(sfstderr);
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
pwtop = pw = job_byjid((int)pwtop->p_job);
|
pwtop = pw = job_byjid((int)pwtop->p_job);
|
||||||
|
|
|
@ -2716,6 +2716,7 @@ static char *sh_tilde(Shell_t *shp,register const char *string)
|
||||||
register int c;
|
register int c;
|
||||||
register struct passwd *pw;
|
register struct passwd *pw;
|
||||||
register Namval_t *np=0;
|
register Namval_t *np=0;
|
||||||
|
unsigned int save;
|
||||||
static Dt_t *logins_tree;
|
static Dt_t *logins_tree;
|
||||||
if(*string++!='~')
|
if(*string++!='~')
|
||||||
return(NIL(char*));
|
return(NIL(char*));
|
||||||
|
@ -2771,10 +2772,10 @@ skip:
|
||||||
logins_tree = dtopen(&_Nvdisc,Dtbag);
|
logins_tree = dtopen(&_Nvdisc,Dtbag);
|
||||||
if(np=nv_search(string,logins_tree,NV_ADD))
|
if(np=nv_search(string,logins_tree,NV_ADD))
|
||||||
{
|
{
|
||||||
c = shp->subshell;
|
save = shp->subshell;
|
||||||
shp->subshell = 0;
|
shp->subshell = 0;
|
||||||
nv_putval(np, pw->pw_dir,0);
|
nv_putval(np, pw->pw_dir,0);
|
||||||
shp->subshell = c;
|
shp->subshell = save;
|
||||||
}
|
}
|
||||||
return(pw->pw_dir);
|
return(pw->pw_dir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2464,7 +2464,7 @@ static void table_unset(Shell_t *shp, register Dt_t *root, int flags, Dt_t *oroo
|
||||||
{
|
{
|
||||||
if(nv_cover(nq))
|
if(nv_cover(nq))
|
||||||
{
|
{
|
||||||
int subshell = shp->subshell;
|
unsigned int subshell = shp->subshell;
|
||||||
shp->subshell = 0;
|
shp->subshell = 0;
|
||||||
if(nv_isattr(nq, NV_INTEGER))
|
if(nv_isattr(nq, NV_INTEGER))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1318,7 +1318,8 @@ int nv_settype(Namval_t* np, Namval_t *tp, int flags)
|
||||||
char *val=0;
|
char *val=0;
|
||||||
Namarr_t *ap=0;
|
Namarr_t *ap=0;
|
||||||
Shell_t *shp = sh_getinterp();
|
Shell_t *shp = sh_getinterp();
|
||||||
int nelem=0,subshell=shp->subshell;
|
int nelem = 0;
|
||||||
|
unsigned int subshell = shp->subshell;
|
||||||
#if SHOPT_TYPEDEF
|
#if SHOPT_TYPEDEF
|
||||||
Namval_t *tq;
|
Namval_t *tq;
|
||||||
if(nv_type(np)==tp)
|
if(nv_type(np)==tp)
|
||||||
|
|
|
@ -103,7 +103,7 @@ static struct subshell
|
||||||
char pwdclose;
|
char pwdclose;
|
||||||
} *subshell_data;
|
} *subshell_data;
|
||||||
|
|
||||||
static int subenv;
|
static unsigned int subenv;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -176,7 +176,7 @@ void sh_subfork(void)
|
||||||
{
|
{
|
||||||
register struct subshell *sp = subshell_data;
|
register struct subshell *sp = subshell_data;
|
||||||
Shell_t *shp = sp->shp;
|
Shell_t *shp = sp->shp;
|
||||||
int curenv = shp->curenv;
|
unsigned int curenv = shp->curenv;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char *trap = shp->st.trapcom[0];
|
char *trap = shp->st.trapcom[0];
|
||||||
if(trap)
|
if(trap)
|
||||||
|
@ -251,7 +251,7 @@ Namval_t *sh_assignok(register Namval_t *np,int add)
|
||||||
Dt_t *dp= shp->var_tree;
|
Dt_t *dp= shp->var_tree;
|
||||||
Namval_t *mpnext;
|
Namval_t *mpnext;
|
||||||
Namarr_t *ap;
|
Namarr_t *ap;
|
||||||
int save;
|
unsigned int save;
|
||||||
/* don't bother to save if in a ${ subshare; } */
|
/* don't bother to save if in a ${ subshare; } */
|
||||||
if(sp->subshare)
|
if(sp->subshare)
|
||||||
return(np);
|
return(np);
|
||||||
|
@ -456,7 +456,7 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
|
||||||
struct subshell sub_data;
|
struct subshell sub_data;
|
||||||
register struct subshell *sp = &sub_data;
|
register struct subshell *sp = &sub_data;
|
||||||
int jmpval,nsig=0,duped=0;
|
int jmpval,nsig=0,duped=0;
|
||||||
int savecurenv = shp->curenv;
|
unsigned int savecurenv = shp->curenv;
|
||||||
int savejobpgid = job.curpgid;
|
int savejobpgid = job.curpgid;
|
||||||
int *saveexitval = job.exitval;
|
int *saveexitval = job.exitval;
|
||||||
char *savsig;
|
char *savsig;
|
||||||
|
|
|
@ -529,7 +529,8 @@ err() { return $1; }
|
||||||
( err 12 ) & pid=$!
|
( err 12 ) & pid=$!
|
||||||
: $( $date)
|
: $( $date)
|
||||||
wait $pid
|
wait $pid
|
||||||
[[ $? == 12 ]] || err_exit 'exit status from subshells not being preserved'
|
exit_status=$?
|
||||||
|
[[ $exit_status == 12 ]] || err_exit "exit status from subshells not being preserved (expected 12, got $exit_status)"
|
||||||
|
|
||||||
if cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null
|
if cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null
|
||||||
then x="$(sed 's/^/Hello /' <(print "Fred" | sort))"
|
then x="$(sed 's/^/Hello /' <(print "Fred" | sort))"
|
||||||
|
|
Loading…
Reference in a new issue