mirror of
				git://git.code.sf.net/p/cdesktopenv/code
				synced 2025-03-09 15:50:02 +00:00 
			
		
		
		
	Save $? when discipline triggered without command (#226)
A discipline function could incorrectly influence the value of $?
(exit status of last command) outside its context if it was
triggered without another command being run, e.g. when a prompt
variable is read, or COLUMNS or LINES is set.
Reproducers include:
PS1 prompt:
    $ PS1.get() { true; }
    $ false
    $ echo $?
    0
PS2 prompt:
    $ PS2.get() { return 13; }
    $ \
    > 
    $ echo $?
    13
The set discipline is affected too, e.g. COLUMNS and LINES:
    $ COLUMNS.set() { return 13; }
    $ true
    $ (press return)
    $ echo $?
    13
There are probably other contexts where the shell reads or changes
variables without running commands, allowing their get or set
disciplines to influence $?. So this commit makes ksh save $? for
all .get, .set, .append, and .unset discipline calls.
src/cmd/ksh93/sh/nvdisc.c:
- assign(): Save/restore $? when running a .set/.append/.unset
  discipline function.
- lookup(): Save/restore $? when running a .get discipline.
src/cmd/ksh93/tests/pty.sh:
- Add a regression test for $? after displaying a prompt
  and when setting a LINES.set discipline function.
src/cmd/ksh93/tests/return.sh:
- The above test fails in script form on ksh93u+ and ksh2020, as
  it exposes another form of #117 that occurs after running a
  subshell. Add the above regression test here as well
  (re: 092b90da).
Co-authored-by: Martijn Dekker <martijn@inlv.org>
			
			
This commit is contained in:
		
							parent
							
								
									715b815a28
								
							
						
					
					
						commit
						14352ba0a7
					
				
					 5 changed files with 39 additions and 2 deletions
				
			
		
							
								
								
									
										7
									
								
								NEWS
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								NEWS
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,6 +3,13 @@ For full details, see the git log at: https://github.com/ksh93/ksh
 | 
			
		|||
 | 
			
		||||
Any uppercase BUG_* names are modernish shell bug IDs.
 | 
			
		||||
 | 
			
		||||
2021-03-16:
 | 
			
		||||
 | 
			
		||||
- Fixed a bug in interactive shells: if a variable used by the shell called
 | 
			
		||||
  a discipline function (such as PS1.get() or COLUMNS.set()), the value of $?
 | 
			
		||||
  was set to the exit status of the discipline function instead of the last
 | 
			
		||||
  command run.
 | 
			
		||||
 | 
			
		||||
2021-03-15:
 | 
			
		||||
 | 
			
		||||
- If the HOME variable is unset, the bare tilde ~ now expands to the current
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@
 | 
			
		|||
 | 
			
		||||
#define SH_RELEASE_FORK	"93u+m"		/* only change if you develop a new ksh93 fork */
 | 
			
		||||
#define SH_RELEASE_SVER	"1.0.0-alpha"	/* semantic version number: https://semver.org */
 | 
			
		||||
#define SH_RELEASE_DATE	"2021-03-15"	/* must be in this format for $((.sh.version)) */
 | 
			
		||||
#define SH_RELEASE_DATE	"2021-03-16"	/* must be in this format for $((.sh.version)) */
 | 
			
		||||
#define SH_RELEASE_CPYR	"(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
 | 
			
		||||
 | 
			
		||||
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -289,7 +289,7 @@ static void	assign(Namval_t *np,const char* val,int flags,Namfun_t *handle)
 | 
			
		|||
		nq =  vp->disc[type=UNASSIGN];
 | 
			
		||||
	if(nq && !isblocked(bp,type))
 | 
			
		||||
	{
 | 
			
		||||
		int bflag=0;
 | 
			
		||||
		int bflag=0, savexit=sh.savexit;
 | 
			
		||||
		block(bp,type);
 | 
			
		||||
		if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS)))
 | 
			
		||||
			block(bp,LOOKUPS);
 | 
			
		||||
| 
						 | 
				
			
			@ -299,6 +299,7 @@ static void	assign(Namval_t *np,const char* val,int flags,Namfun_t *handle)
 | 
			
		|||
			unblock(bp,LOOKUPS);
 | 
			
		||||
		if(!vp->disc[type])
 | 
			
		||||
			chktfree(np,vp);
 | 
			
		||||
		sh.savexit = savexit;	/* avoid influencing $? */
 | 
			
		||||
	}
 | 
			
		||||
	if(nv_isarray(np))
 | 
			
		||||
		np->nvalue.up = up;
 | 
			
		||||
| 
						 | 
				
			
			@ -381,6 +382,7 @@ static char*	lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
 | 
			
		|||
	union Value		*up = np->nvalue.up;
 | 
			
		||||
	if(nq && !isblocked(bp,type))
 | 
			
		||||
	{
 | 
			
		||||
		int		savexit = sh.savexit;
 | 
			
		||||
		node = *SH_VALNOD;
 | 
			
		||||
		if(!nv_isnull(SH_VALNOD))
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -410,6 +412,7 @@ static char*	lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
 | 
			
		|||
			/* restore everything but the nvlink field */
 | 
			
		||||
			memcpy(&SH_VALNOD->nvname,  &node.nvname, sizeof(node)-sizeof(node.nvlink));
 | 
			
		||||
		}
 | 
			
		||||
		sh.savexit = savexit;	/* avoid influencing $? */
 | 
			
		||||
	}
 | 
			
		||||
	if(nv_isarray(np))
 | 
			
		||||
		np->nvalue.up = up;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -709,5 +709,29 @@ r ^:test-2: fc -lN1\r\n$
 | 
			
		|||
r \tdo something\r\n$
 | 
			
		||||
!
 | 
			
		||||
 | 
			
		||||
# err_exit #
 | 
			
		||||
tst $LINENO <<"!"
 | 
			
		||||
L value of $? after the shell uses a variable with a discipline function
 | 
			
		||||
 | 
			
		||||
w PS1.get() { true; }; PS2.get() { true; }; false
 | 
			
		||||
u PS1.get\(\) \{ true; \}; PS2.get\(\) \{ true; \}; false
 | 
			
		||||
w echo "Exit status is: $?"
 | 
			
		||||
u Exit status is: 1
 | 
			
		||||
w LINES.set() { return 13; }
 | 
			
		||||
u LINES.set\(\) \{ return 13; \}
 | 
			
		||||
w echo "Exit status is: $?"
 | 
			
		||||
u Exit status is: 0
 | 
			
		||||
 | 
			
		||||
# It's worth noting that the test below will always fail in ksh93u+ and ksh2020,
 | 
			
		||||
# even when $PS2 lacks a discipline function (see https://github.com/ksh93/ksh/issues/117).
 | 
			
		||||
# After that bug was fixed the test below could still fail if PS2.get() existed.
 | 
			
		||||
w false
 | 
			
		||||
w (
 | 
			
		||||
w exit
 | 
			
		||||
w )
 | 
			
		||||
w echo "Exit status is: $?"
 | 
			
		||||
u Exit status is: 1
 | 
			
		||||
!
 | 
			
		||||
 | 
			
		||||
# ======
 | 
			
		||||
exit $((Errors<125?Errors:125))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -237,5 +237,8 @@ foo && err_exit "'exit' within 'for' with redirection does not preserve exit sta
 | 
			
		|||
foo() ( false; { exit; } 2>&1 )
 | 
			
		||||
foo && err_exit "'exit' within { block; } with redirection does not preserve exit status"
 | 
			
		||||
 | 
			
		||||
foo() { false; (exit); }
 | 
			
		||||
foo && err_exit "'exit' within subshell does not preserve exit status"
 | 
			
		||||
 | 
			
		||||
# ======
 | 
			
		||||
exit $((Errors<125?Errors:125))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue