mirror of
				git://git.code.sf.net/p/cdesktopenv/code
				synced 2025-03-09 15:50:02 +00:00 
			
		
		
		
	DEBUG trap: restore status 2 trigger to skip command (re: d00b4b39)
				
					
				
			So now we know what that faulty check for shp->indebug in sh_trap()
was meant to do: it was meant to pass down the trap handler's exit
status, via sh_debug(), down to sh_exec() (xec.c) so that it could
then skip the execution of the next command if the trap's exit
status is 2, as documented in the manual page. As of d00b4b39, exit
status 2 was not passed down, so this stopped working.
This commit reinstates that functionality, but without the exit
status bug in command substitutions caused by the old way.
src/cmd/ksh93/sh/fault.c: sh_trap():
- Save the trap's exit status before restoring the parent
  envionment's exit status. Make this saved exit status the return
  value of the function. (This does not break anything, AFAICT; the
  majority of sh_trap() calls ignore the return value, and the few
  that don't ignore it seem to expect it to return exactly this.)
src/cmd/ksh93/sh/xec.c: sh_exec():
- The sh_trap() fix has one side effect: whereas the exit status of
  a skipped command was always 2 (as per the trap handler), now it
  is always 0, because it gets reset in sh_exec() but no command is
  executed. That is probably not a desirable change in behaviour,
  so let's fix that here instead: set sh.exitval to 2 when skipping
  commands.
src/cmd/ksh93/sh.1:
- Document that ${.sh.command} shell-quotes its arguments for use
  by 'eval' and such. This fact was not documented anywhere, AFAIK.
src/cmd/ksh93/shell.3:
- Document that $? (exit status) is made local to trap handlers.
- Document that sh_trap() returns the trap handler's exit status.
src/cmd/ksh93/tests/basic.sh:
- Add test for this bug.
- Add a missing test for the exit status 255 functionality (if a
  DEBUG trap handler yields this exit status and we're executing a
  function or dot script, a return is triggered).
Fixes: https://github.com/ksh93/ksh/issues/187
			
			
This commit is contained in:
		
							parent
							
								
									2b805f7f1c
								
							
						
					
					
						commit
						a959a35291
					
				
					 6 changed files with 56 additions and 3 deletions
				
			
		
							
								
								
									
										5
									
								
								NEWS
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								NEWS
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh
 | 
			
		|||
 | 
			
		||||
Any uppercase BUG_* names are modernish shell bug IDs.
 | 
			
		||||
 | 
			
		||||
2021-02-20:
 | 
			
		||||
 | 
			
		||||
- Fixed a bug introduced on 2021-01-20: if a DEBUG trap action yielded exit
 | 
			
		||||
  status 2, the execution of the next command was not skipped as documented.
 | 
			
		||||
 | 
			
		||||
2021-02-18:
 | 
			
		||||
 | 
			
		||||
- A bug was fixed in the 'read' builtin that caused it to fail to process
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1561,6 +1561,8 @@ When processing a
 | 
			
		|||
.B DEBUG
 | 
			
		||||
trap, this variable contains the current command line
 | 
			
		||||
that is about to run.
 | 
			
		||||
Each argument is shell-quoted as necessary
 | 
			
		||||
so that the value is safe for being evaluated by the shell.
 | 
			
		||||
.TP
 | 
			
		||||
.B .sh.edchar
 | 
			
		||||
This variable contains the value of the keyboard character
 | 
			
		||||
| 
						 | 
				
			
			@ -7429,7 +7431,7 @@ then
 | 
			
		|||
will be executed before each command.
 | 
			
		||||
The variable
 | 
			
		||||
.B .sh.command
 | 
			
		||||
will contain the contents of the current command line
 | 
			
		||||
will contain the shell-quoted arguments of the current command line
 | 
			
		||||
when
 | 
			
		||||
.I action\^
 | 
			
		||||
is running.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -442,11 +442,12 @@ void	sh_chktrap(Shell_t* shp)
 | 
			
		|||
/*
 | 
			
		||||
 * parse and execute the given trap string, stream or tree depending on mode
 | 
			
		||||
 * mode==0 for string, mode==1 for stream, mode==2 for parse tree
 | 
			
		||||
 * The return value is the exit status of the trap action.
 | 
			
		||||
 */
 | 
			
		||||
int sh_trap(const char *trap, int mode)
 | 
			
		||||
{
 | 
			
		||||
	Shell_t	*shp = sh_getinterp();
 | 
			
		||||
	int	jmpval, savxit = shp->exitval;
 | 
			
		||||
	int	jmpval, savxit = shp->exitval, savxit_return;
 | 
			
		||||
	int	was_history = sh_isstate(SH_HISTORY);
 | 
			
		||||
	int	was_verbose = sh_isstate(SH_VERBOSE);
 | 
			
		||||
	int	staktop = staktell();
 | 
			
		||||
| 
						 | 
				
			
			@ -487,6 +488,7 @@ int sh_trap(const char *trap, int mode)
 | 
			
		|||
	sh_popcontext(shp,&buff);
 | 
			
		||||
	shp->intrap--;
 | 
			
		||||
	sfsync(shp->outpool);
 | 
			
		||||
	savxit_return = shp->exitval;
 | 
			
		||||
	if(jmpval!=SH_JMPEXIT && jmpval!=SH_JMPFUN)
 | 
			
		||||
		shp->exitval=savxit;
 | 
			
		||||
	stakset(savptr,staktop);
 | 
			
		||||
| 
						 | 
				
			
			@ -498,7 +500,7 @@ int sh_trap(const char *trap, int mode)
 | 
			
		|||
	exitset();
 | 
			
		||||
	if(jmpval>SH_JMPTRAP && (((struct checkpt*)shp->jmpbuffer)->prev || ((struct checkpt*)shp->jmpbuffer)->mode==SH_JMPSCRIPT))
 | 
			
		||||
		siglongjmp(*shp->jmplist,jmpval);
 | 
			
		||||
	return(shp->exitval);
 | 
			
		||||
	return(savxit_return);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1192,7 +1192,11 @@ int sh_exec(register const Shnode_t *t, int flags)
 | 
			
		|||
						argp = 0;
 | 
			
		||||
					}
 | 
			
		||||
					else if(n==2)
 | 
			
		||||
					{
 | 
			
		||||
						/* Do not execute next command; keep exit status from trap handler */
 | 
			
		||||
						shp->exitval = n;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if(io)
 | 
			
		||||
					sfsync(shp->outpool);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -273,6 +273,10 @@ The complete file associated with the string or file
 | 
			
		|||
is compiled and then executed so that aliases defined
 | 
			
		||||
within the string or file will not take effect until
 | 
			
		||||
the next command is executed.
 | 
			
		||||
The shell's \f5$?\fP special parameter is made local to the string
 | 
			
		||||
or file executed so that it is not affected for subsequent commands.
 | 
			
		||||
The return value of \f5sh_trap()\fP is the exit status of
 | 
			
		||||
the last command executed by the string or file.
 | 
			
		||||
.PP
 | 
			
		||||
The \f5sh_run()\fP function will run the command given by
 | 
			
		||||
by the argument list \fIargv\fP containing \fIargc\fP elements. 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -662,6 +662,7 @@ got=$(eval 'x=`for i in test; do case $i in test) true;; esac; done`' 2>&1) \
 | 
			
		|||
 | 
			
		||||
# ======
 | 
			
		||||
# Various DEBUG trap fixes: https://github.com/ksh93/ksh/issues/155
 | 
			
		||||
#			    https://github.com/ksh93/ksh/issues/187
 | 
			
		||||
 | 
			
		||||
# Redirecting disabled the DEBUG trap
 | 
			
		||||
exp=$'LINENO: 4\nfoo\nLINENO: 5\nLINENO: 6\nbar\nLINENO: 7\nbaz'
 | 
			
		||||
| 
						 | 
				
			
			@ -713,6 +714,19 @@ r=`exit 123`
 | 
			
		|||
(((e=$?)==123)) || err_exit "DEBUG trap run in \`comsub\` affects exit status (expected 123, got $e)"
 | 
			
		||||
trap - DEBUG
 | 
			
		||||
 | 
			
		||||
# After fixing the previous, the DEBUG trap stopped honouring exit status 2 to skip command execution -- whoops
 | 
			
		||||
got=$(
 | 
			
		||||
	myfn()
 | 
			
		||||
	{
 | 
			
		||||
		[[ ${.sh.command} == echo* ]] && return 2
 | 
			
		||||
	}
 | 
			
		||||
	trap 'myfn' DEBUG
 | 
			
		||||
	print end
 | 
			
		||||
	echo "Hi, I'm a bug"
 | 
			
		||||
)
 | 
			
		||||
(((e=$?)==2)) && [[ $got == end ]] || err_exit 'DEBUG trap: next command not skipped upon status 2' \
 | 
			
		||||
	"(got status $e, $(printf %q "$got"))"
 | 
			
		||||
 | 
			
		||||
# The DEBUG trap was incorrectly inherited by subshells
 | 
			
		||||
exp=$'Subshell\nDebug 1\nParentshell'
 | 
			
		||||
got=$(
 | 
			
		||||
| 
						 | 
				
			
			@ -754,5 +768,27 @@ trap - DEBUG  # bug compat
 | 
			
		|||
[[ $got == "$exp" ]] || err_exit "DEBUG trap not inherited by POSIX function" \
 | 
			
		||||
	"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
 | 
			
		||||
 | 
			
		||||
# Make sure the DEBUG trap still exits a POSIX function on exit status 255
 | 
			
		||||
# TODO: same test for ksh function with -o functrace, once we add that option
 | 
			
		||||
exp=$'one\ntwo'
 | 
			
		||||
got=$(
 | 
			
		||||
	myfn()
 | 
			
		||||
	{
 | 
			
		||||
		echo one
 | 
			
		||||
		echo two
 | 
			
		||||
		echo three
 | 
			
		||||
		echo four
 | 
			
		||||
	}
 | 
			
		||||
	set255()
 | 
			
		||||
	{
 | 
			
		||||
		return 255
 | 
			
		||||
	}
 | 
			
		||||
	trap '[[ ${.sh.command} == *three ]] && set255' DEBUG
 | 
			
		||||
	myfn
 | 
			
		||||
)
 | 
			
		||||
trap - DEBUG  # bug compat
 | 
			
		||||
[[ $got == "$exp" ]] || err_exit "DEBUG trap did not trigger return from POSIX function on status 255" \
 | 
			
		||||
	"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
 | 
			
		||||
 | 
			
		||||
# ======
 | 
			
		||||
exit $((Errors<125?Errors:125))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue