mirror of
				git://git.code.sf.net/p/cdesktopenv/code
				synced 2025-03-09 15:50:02 +00:00 
			
		
		
		
	Fix I/O redirection in -c script (Solaris patch 280-23332860)
This change is pulled from here: https://github.com/oracle/solaris-userland/blob/master/components/ksh93/patches/280-23332860.patch Info and reproducers: https://github.com/att/ast/issues/36 In a -c script (like ksh -c 'commands'), the last command misredirects standard output if an EXIT or ERR trap is set. This appears to be a side effect of the optimisation that runs the last command without forking. This applies a patch by George Lijo that flags these specific cases and disables the optimisation. src/cmd/ksh93/include/defs.h, src/cmd/ksh93/bltins/trap.c, src/cmd/ksh93/sh/init.c, src/cmd/ksh93/sh/main.c, src/cmd/ksh93/sh/xec.c: - Apply patch as above. src/cmd/ksh93/tests/io.sh: - Add the reproducers from the bug report as regression tests.
This commit is contained in:
		
							parent
							
								
									7c47ab56fe
								
							
						
					
					
						commit
						17ebfbf6a3
					
				
					 6 changed files with 78 additions and 1 deletions
				
			
		| 
						 | 
					@ -127,6 +127,14 @@ int	b_trap(int argc,char *argv[],Shbltin_t *context)
 | 
				
			||||||
						shp->trapnote |= SH_SIGTRAP;
 | 
											shp->trapnote |= SH_SIGTRAP;
 | 
				
			||||||
					else
 | 
										else
 | 
				
			||||||
						shp->trapnote = 0;
 | 
											shp->trapnote = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if(sig == SH_ERRTRAP)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if(clear)
 | 
				
			||||||
 | 
											shp->errtrap = 0;
 | 
				
			||||||
 | 
										else if(!shp->fn_depth || shp->end_fn)
 | 
				
			||||||
 | 
											shp->errtrap = 1;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -144,6 +152,8 @@ int	b_trap(int argc,char *argv[],Shbltin_t *context)
 | 
				
			||||||
			else if(clear)
 | 
								else if(clear)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				sh_sigclear(sig);
 | 
									sh_sigclear(sig);
 | 
				
			||||||
 | 
									if(sig == 0)
 | 
				
			||||||
 | 
										shp->exittrap = 0;
 | 
				
			||||||
				if(dflag)
 | 
									if(dflag)
 | 
				
			||||||
					signal(sig,SIG_DFL);
 | 
										signal(sig,SIG_DFL);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -156,6 +166,8 @@ int	b_trap(int argc,char *argv[],Shbltin_t *context)
 | 
				
			||||||
				shp->st.trapcom[sig] = (shp->sigflag[sig]&SH_SIGOFF) ? Empty : strdup(action);
 | 
									shp->st.trapcom[sig] = (shp->sigflag[sig]&SH_SIGOFF) ? Empty : strdup(action);
 | 
				
			||||||
				if(arg && arg != Empty)
 | 
									if(arg && arg != Empty)
 | 
				
			||||||
					free(arg);
 | 
										free(arg);
 | 
				
			||||||
 | 
									if(sig == 0 && (!shp->fn_depth || shp->end_fn))
 | 
				
			||||||
 | 
										shp->exittrap = 1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -272,7 +272,10 @@ struct shared
 | 
				
			||||||
	Namfun_t	nvfun; \
 | 
						Namfun_t	nvfun; \
 | 
				
			||||||
	char		*mathnodes; \
 | 
						char		*mathnodes; \
 | 
				
			||||||
	char		*bltin_dir; \
 | 
						char		*bltin_dir; \
 | 
				
			||||||
	struct Regress_s*regress;
 | 
						struct Regress_s*regress; \
 | 
				
			||||||
 | 
						char 		exittrap; \
 | 
				
			||||||
 | 
						char 		errtrap; \
 | 
				
			||||||
 | 
						char 		end_fn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include	<shell.h>
 | 
					#include	<shell.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1479,6 +1479,9 @@ Shell_t *sh_init(register int argc,register char *argv[], Shinit_f userinit)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if(shp->userinit=userinit)
 | 
						if(shp->userinit=userinit)
 | 
				
			||||||
		(*userinit)(shp, 0);
 | 
							(*userinit)(shp, 0);
 | 
				
			||||||
 | 
						shp->exittrap = 0;
 | 
				
			||||||
 | 
						shp->errtrap = 0;
 | 
				
			||||||
 | 
						shp->end_fn = 0;
 | 
				
			||||||
	return(shp);
 | 
						return(shp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1580,6 +1583,9 @@ int sh_reinit(char *argv[])
 | 
				
			||||||
	shp->inpipe = shp->outpipe = 0;
 | 
						shp->inpipe = shp->outpipe = 0;
 | 
				
			||||||
	job_clear();
 | 
						job_clear();
 | 
				
			||||||
	job.in_critical = 0;
 | 
						job.in_critical = 0;
 | 
				
			||||||
 | 
						shp->exittrap = 0;
 | 
				
			||||||
 | 
						shp->errtrap = 0;
 | 
				
			||||||
 | 
						shp->end_fn = 0;
 | 
				
			||||||
	/* update ${.sh.pid}, $$, $PPID */
 | 
						/* update ${.sh.pid}, $$, $PPID */
 | 
				
			||||||
	shgd->current_pid = shgd->pid = getpid();
 | 
						shgd->current_pid = shgd->pid = getpid();
 | 
				
			||||||
	shgd->ppid = getppid();
 | 
						shgd->ppid = getppid();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -455,6 +455,9 @@ static void	exfile(register Shell_t *shp, register Sfio_t *iop,register int fno)
 | 
				
			||||||
	error_info.line = 1;
 | 
						error_info.line = 1;
 | 
				
			||||||
	shp->inlineno = 1;
 | 
						shp->inlineno = 1;
 | 
				
			||||||
	shp->binscript = 0;
 | 
						shp->binscript = 0;
 | 
				
			||||||
 | 
						shp->exittrap = 0;
 | 
				
			||||||
 | 
						shp->errtrap = 0;
 | 
				
			||||||
 | 
						shp->end_fn = 0;
 | 
				
			||||||
	if(sfeof(iop))
 | 
						if(sfeof(iop))
 | 
				
			||||||
		goto eof_or_error;
 | 
							goto eof_or_error;
 | 
				
			||||||
	/* command loop */
 | 
						/* command loop */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -987,6 +987,8 @@ int sh_exec(register const Shnode_t *t, int flags)
 | 
				
			||||||
		shp->exitval=0;
 | 
							shp->exitval=0;
 | 
				
			||||||
		shp->lastsig = 0;
 | 
							shp->lastsig = 0;
 | 
				
			||||||
		shp->lastpath = 0;
 | 
							shp->lastpath = 0;
 | 
				
			||||||
 | 
							if(shp->exittrap || shp->errtrap)
 | 
				
			||||||
 | 
								execflg = 0;
 | 
				
			||||||
		switch(type&COMMSK)
 | 
							switch(type&COMMSK)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
		    case TCOM:
 | 
							    case TCOM:
 | 
				
			||||||
| 
						 | 
					@ -3119,6 +3121,8 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg)
 | 
				
			||||||
		nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
 | 
							nv_putval(SH_PATHNAMENOD,shp->st.filename,NV_NOFREE);
 | 
				
			||||||
		nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
 | 
							nv_putval(SH_FUNNAMENOD,shp->st.funname,NV_NOFREE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if((execflg & sh_state(SH_NOFORK)))
 | 
				
			||||||
 | 
							shp->end_fn = 1;
 | 
				
			||||||
	jmpval = sigsetjmp(buffp->buff,0);
 | 
						jmpval = sigsetjmp(buffp->buff,0);
 | 
				
			||||||
	if(jmpval == 0)
 | 
						if(jmpval == 0)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -3166,6 +3170,7 @@ int sh_funscope(int argn, char *argv[],int(*fun)(void*),void *arg,int execflg)
 | 
				
			||||||
	shp->st = *prevscope;
 | 
						shp->st = *prevscope;
 | 
				
			||||||
	shp->topscope = (Shscope_t*)prevscope;
 | 
						shp->topscope = (Shscope_t*)prevscope;
 | 
				
			||||||
	nv_getval(sh_scoped(shp,IFSNOD));
 | 
						nv_getval(sh_scoped(shp,IFSNOD));
 | 
				
			||||||
 | 
						shp->end_fn = 0;
 | 
				
			||||||
	if(nsig)
 | 
						if(nsig)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (isig = 0; isig < nsig; ++isig)
 | 
							for (isig = 0; isig < nsig; ++isig)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -649,5 +649,53 @@ err=$(
 | 
				
			||||||
((!(e = $?))) || err_exit 'crash on null-command redirection with DEBUG trap' \
 | 
					((!(e = $?))) || err_exit 'crash on null-command redirection with DEBUG trap' \
 | 
				
			||||||
	"(got status $e$( ((e>128)) && print -n / && kill -l "$e"), $(printf %q "$got"))"
 | 
						"(got status $e$( ((e>128)) && print -n / && kill -l "$e"), $(printf %q "$got"))"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ======
 | 
				
			||||||
 | 
					# stdout was misdirected if an EXIT/ERR trap handler was defined in a -c script
 | 
				
			||||||
 | 
					# https://github.com/att/ast/issues/36
 | 
				
			||||||
 | 
					exp=$'exit to stdout\ntrap to stdout'
 | 
				
			||||||
 | 
					exp2=$'exit to file\ntrap to file'
 | 
				
			||||||
 | 
					got=$(export tmp; "$SHELL" -ec \
 | 
				
			||||||
 | 
					'	function log
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							echo "$* to stdout"
 | 
				
			||||||
 | 
							echo "$* to file" >> $tmp/ast36_a.test.log
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						function test_exit
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log trap
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						trap test_exit EXIT
 | 
				
			||||||
 | 
						log exit
 | 
				
			||||||
 | 
					')
 | 
				
			||||||
 | 
					[[ $got == "$exp" ]] || err_exit 'stdout misdirected to file with EXIT/ERR trap defined (1)' \
 | 
				
			||||||
 | 
						"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
 | 
				
			||||||
 | 
					[[ $(< $tmp/ast36_a.test.log) == "$exp2" ]] || err_exit 'stdout not correctly redirected to file with EXIT/ERR trap defined (1)' \
 | 
				
			||||||
 | 
						"(expected $(printf %q "$exp2"), wrote $(printf %q "$(< $tmp/ast36_a.test.log)"))"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exp=$'trap to stdout\nexit to stdout'
 | 
				
			||||||
 | 
					exp2=$'trap to file\nexit to file'
 | 
				
			||||||
 | 
					got=$(export tmp; "$SHELL" -ec \
 | 
				
			||||||
 | 
					'	function log
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							echo "$* to stdout"
 | 
				
			||||||
 | 
							echo "$* to file" >> $tmp/ast36_b.test.log
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						function test_exit
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							trap test_exittrap EXIT
 | 
				
			||||||
 | 
							log trap
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						function test_exittrap
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log exit
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						test_exit
 | 
				
			||||||
 | 
					')
 | 
				
			||||||
 | 
					[[ $got == "$exp" ]] || err_exit 'stdout misdirected to file with EXIT/ERR trap defined (2)' \
 | 
				
			||||||
 | 
						"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
 | 
				
			||||||
 | 
					[[ $(< $tmp/ast36_b.test.log) == "$exp2" ]] || err_exit 'stdout not correctly redirected to file with EXIT/ERR trap defined (2)' \
 | 
				
			||||||
 | 
						"(expected $(printf %q "$exp2"), wrote $(printf %q "$(< $tmp/ast36_b.test.log)"))"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ======
 | 
					# ======
 | 
				
			||||||
exit $((Errors<125?Errors:125))
 | 
					exit $((Errors<125?Errors:125))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue