mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix more "/dev/null: cannot create" (re: 411481eb
)
Reproducer: trap : USR1 while :; do kill -s USR1 $$ || exit; done & while :; do : >/dev/null; done It can take between a fraction of a second and a few minutes, but eventually it will fail like this: $ ksh foo foo[3]: /dev/null: cannot create kill: 77946: no such process It fails similarly with "cannot open" if </dev/null is used instead of >/dev/null. This is the same problem as in the referenced commit, except when handling traps -- so the same fix is required in sh_fault().
This commit is contained in:
parent
7af1d56e7f
commit
225323f138
3 changed files with 28 additions and 12 deletions
5
NEWS
5
NEWS
|
@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0
|
|||
|
||||
Any uppercase BUG_* names are modernish shell bug IDs.
|
||||
|
||||
2022-06-20:
|
||||
|
||||
- Fixed a race condition that could cause redirections to fail with a
|
||||
"cannot create" or "cannot open" error while processing a signal trap.
|
||||
|
||||
2022-06-18:
|
||||
|
||||
- Fixed a bug where, with the monitor or pipefail option on, the shell
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
|
||||
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
|
||||
#define SH_RELEASE_DATE "2022-06-18" /* must be in this format for $((.sh.version)) */
|
||||
#define SH_RELEASE_DATE "2022-06-20" /* must be in this format for $((.sh.version)) */
|
||||
#define SH_RELEASE_CPYR "(c) 2020-2022 Contributors to ksh " SH_RELEASE_FORK
|
||||
|
||||
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
|
||||
|
|
|
@ -67,6 +67,7 @@ void sh_fault(register int sig)
|
|||
register char *trap;
|
||||
register struct checkpt *pp = (struct checkpt*)sh.jmplist;
|
||||
int action=0;
|
||||
int save_errno = errno;
|
||||
/* reset handler */
|
||||
if(!(sig&SH_TRAP))
|
||||
signal(sig, sh_fault);
|
||||
|
@ -90,7 +91,7 @@ void sh_fault(register int sig)
|
|||
/* critical region, save and process later */
|
||||
if(!(sh.sigflag[sig]&SH_SIGIGNORE))
|
||||
sh.savesig = sig;
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
if(sig==SIGALRM && sh.bltinfun==b_sleep)
|
||||
{
|
||||
|
@ -99,18 +100,18 @@ void sh_fault(register int sig)
|
|||
sh.trapnote |= SH_SIGTRAP;
|
||||
sh.sigflag[sig] |= SH_SIGTRAP;
|
||||
}
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
if(sh.subshell && trap && sig!=SIGINT && sig!=SIGQUIT && sig!=SIGWINCH && sig!=SIGCONT)
|
||||
{
|
||||
sh.exitval = SH_EXITSIG|sig;
|
||||
sh_subfork();
|
||||
sh.exitval = 0;
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
/* handle ignored signals */
|
||||
if(trap && *trap==0)
|
||||
return;
|
||||
goto done;
|
||||
flag = sh.sigflag[sig]&~SH_SIGOFF;
|
||||
if(!trap)
|
||||
{
|
||||
|
@ -119,7 +120,7 @@ void sh_fault(register int sig)
|
|||
if(sh.subshell)
|
||||
sh.ignsig = sig;
|
||||
sigrelease(sig);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
if(flag&SH_SIGDONE)
|
||||
{
|
||||
|
@ -129,7 +130,7 @@ void sh_fault(register int sig)
|
|||
/* check for TERM signal between fork/exec */
|
||||
if(sig==SIGTERM && job.in_critical)
|
||||
sh.trapnote |= SH_SIGTERM;
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
sh.lastsig = sig;
|
||||
sigrelease(sig);
|
||||
|
@ -162,7 +163,7 @@ void sh_fault(register int sig)
|
|||
dp->exceptf = malloc_done;
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
errno = 0;
|
||||
|
@ -190,7 +191,7 @@ void sh_fault(register int sig)
|
|||
sigrelease(sig);
|
||||
sh_exit(SH_EXITSIG);
|
||||
}
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
#endif /* SIGTSTP */
|
||||
}
|
||||
|
@ -198,12 +199,12 @@ void sh_fault(register int sig)
|
|||
if((error_info.flags&ERROR_NOTIFY) && sh.bltinfun)
|
||||
action = (*sh.bltinfun)(-sig,(char**)0,(void*)0);
|
||||
if(action>0)
|
||||
return;
|
||||
goto done;
|
||||
#endif
|
||||
if(sh.bltinfun && sh.bltindata.notify)
|
||||
{
|
||||
sh.bltindata.sigset = 1;
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
sh.trapnote |= flag;
|
||||
if(sig <= sh.sigmax)
|
||||
|
@ -211,10 +212,20 @@ void sh_fault(register int sig)
|
|||
if(pp->mode==SH_JMPCMD && sh_isstate(SH_STOPOK))
|
||||
{
|
||||
if(action<0)
|
||||
return;
|
||||
goto done;
|
||||
sigrelease(sig);
|
||||
sh_exit(SH_EXITSIG);
|
||||
}
|
||||
done:
|
||||
/*
|
||||
* Always restore errno, because this code is run during signal handling which may interrupt loops like:
|
||||
* while((fd = open(path, flags, mode)) < 0)
|
||||
* if(errno!=EINTR)
|
||||
* <throw error>;
|
||||
* otherwise that may fail if a signal is caught between the open() call and the errno!=EINTR check.
|
||||
*/
|
||||
errno = save_errno;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue