diff --git a/src/cmd/ksh93/sh/subshell.c b/src/cmd/ksh93/sh/subshell.c index 4ba0a5e48..fdb020729 100644 --- a/src/cmd/ksh93/sh/subshell.c +++ b/src/cmd/ksh93/sh/subshell.c @@ -470,11 +470,11 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub) { struct subshell sub_data; register struct subshell *sp = &sub_data; - int jmpval,nsig=0,duped=0; + int jmpval,isig,nsig=0,duped=0; unsigned int savecurenv = shp->curenv; int savejobpgid = job.curpgid; int *saveexitval = job.exitval; - char *savsig; + char **savsig; Sfio_t *iop=0; struct checkpt buff; struct sh_scoped savst; @@ -569,10 +569,24 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub) /* save trap table */ shp->st.otrapcom = 0; shp->st.otrap = savst.trap; - if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) + if((nsig=shp->st.trapmax)>0 || shp->st.trapcom[0]) { - nsig += sizeof(char*); - memcpy(savsig=malloc(nsig),(char*)&shp->st.trapcom[0],nsig); + ++nsig; + savsig = malloc(nsig * sizeof(char*)); + /* + * the data is, usually, modified in code like: + * tmp = buf[i]; buf[i] = strdup(tmp); free(tmp); + * so shp->st.trapcom needs a "deep copy" to properly save/restore pointers. + */ + for (isig = 0; isig < nsig; ++isig) + { + if(shp->st.trapcom[isig] == Empty) + savsig[isig] = Empty; + else if(shp->st.trapcom[isig]) + savsig[isig] = strdup(shp->st.trapcom[isig]); + else + savsig[isig] = NULL; + } /* this nonsense needed for $(trap) */ shp->st.otrapcom = (char**)savsig; } @@ -732,7 +746,10 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub) shp->st.otrap = 0; if(nsig) { - memcpy((char*)&shp->st.trapcom[0],savsig,nsig); + for (isig = 0; isig < nsig; ++isig) + if (shp->st.trapcom[isig] && shp->st.trapcom[isig]!=Empty) + free(shp->st.trapcom[isig]); + memcpy((char*)&shp->st.trapcom[0],savsig,nsig*sizeof(char*)); free((void*)savsig); } shp->options = sp->options; diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index a5c57a0a8..55ebaf39f 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -3042,10 +3042,10 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) struct dolnod *argsav=0,*saveargfor; struct sh_scoped savst, *prevscope = shp->st.self; struct argnod *envlist=0; - int jmpval; + int isig,jmpval; volatile int r = 0; int n; - char *savstak; + char **savsig; struct funenv *fp = 0; struct checkpt *buffp = (struct checkpt*)stkalloc(shp->stk,sizeof(struct checkpt)); Namval_t *nspace = shp->namespace; @@ -3091,10 +3091,24 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) } shp->st.cmdname = argv[0]; /* save trap table */ - if((nsig=shp->st.trapmax*sizeof(char*))>0 || shp->st.trapcom[0]) + if((nsig=shp->st.trapmax)>0 || shp->st.trapcom[0]) { - nsig += sizeof(char*); - memcpy(savstak=stakalloc(nsig),(char*)&shp->st.trapcom[0],nsig); + ++nsig; + savsig = malloc(nsig * sizeof(char*)); + /* + * the data is, usually, modified in code like: + * tmp = buf[i]; buf[i] = strdup(tmp); free(tmp); + * so shp->st.trapcom needs a "deep copy" to properly save/restore pointers. + */ + for (isig = 0; isig < nsig; ++isig) + { + if(shp->st.trapcom[isig] == Empty) + savsig[isig] = Empty; + else if(shp->st.trapcom[isig]) + savsig[isig] = strdup(shp->st.trapcom[isig]); + else + savsig[isig] = NULL; + } } sh_sigreset(0); argsav = sh_argnew(shp,argv,&saveargfor); @@ -3158,10 +3172,14 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg) shp->topscope = (Shscope_t*)prevscope; nv_getval(sh_scoped(shp,IFSNOD)); if(nsig) - memcpy((char*)&shp->st.trapcom[0],savstak,nsig); + { + for (isig = 0; isig < nsig; ++isig) + if (shp->st.trapcom[isig] && shp->st.trapcom[isig]!=Empty) + free(shp->st.trapcom[isig]); + memcpy((char*)&shp->st.trapcom[0],savsig,nsig*sizeof(char*)); + free((void*)savsig); + } shp->trapnote=0; - if(nsig) - stakset(savstak,0); shp->options = options; shp->last_root = last_root; if(jmpval == SH_JMPSUB) diff --git a/src/cmd/ksh93/tests/subshell.sh b/src/cmd/ksh93/tests/subshell.sh index 539ee9020..56d4115d3 100755 --- a/src/cmd/ksh93/tests/subshell.sh +++ b/src/cmd/ksh93/tests/subshell.sh @@ -847,5 +847,19 @@ actual=${ get_value; } actual=`get_value` [[ $actual == "$expect" ]] || err_exit "\`Comsub\` failed to return output (expected '$expect', got '$actual')" +# ====== +# https://bugzilla.redhat.com/1117404 + +cat >$tmp/crash_rhbz1117404.ksh <<-'EOF' + trap "" HUP # trigger part 1: signal ignored in main shell + i=0 + for((i=0; i<2500; i++)) + do (trap ": foo" HUP) # trigger part 2: any trap (empty or not) on same signal in subshell + done +EOF +got=$( { "$SHELL" "$tmp/crash_rhbz1117404.ksh"; } 2>&1) +((!(e = $?))) || err_exit 'crash while handling subshell trap' \ + "(got status $e$( ((e>128)) && print -n / && kill -l "$e"), $(printf %q "$got"))" + # ====== exit $((Errors<125?Errors:125))