1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix unsetting aliases in subshells

Aliases can now be correctly unset within subshell environments
(such as ( ... ), $(command substitutions), etc), as well as
non-subshell "shared" command substitutions (${ ...; }). Before,
attempts to unset aliases within these were silently ignored.

Prior discussion: https://github.com/att/ast/issues/108

Subshell alias trees are only referenced in a few places in the
code, *and* have always been broken, so this commit gets rid of the
whole notion of a subshell alias tree. Instead, there is now just
one flat alias tree, and subshells fork into a separate process
when aliases are set or unset within them. It is not really
conceivable that this could be a performance-sensitive operation,
or even a common one, so this is a clean fix with no downside.

src/cmd/ksh93/include/defs.h:
- Remove sh_subaliastree() definition.

src/cmd/ksh93/sh/subshell.c:
- Remove salias element (pointer to subshell alias tree) from
  subshell struct.
- Remove sh_subaliastree() function.
- sh_subshell(): Remove alias subshell tree cleanup.

src/cmd/ksh93/bltins/typeset.c:
- b_alias(): If in subshell, fork before setting alias.
- b_unalias(): If in subshell, fork before unsetting alias.
- unall(): Remove sh_subaliastree() call.

src/cmd/ksh93/sh/name.c:
- nv_open(): Remove sh_subaliastree() call.

src/cmd/ksh93/tests/subshell.sh:
- Add regression tests for unsetting or redefining aliases within
  subshells.

(cherry picked from commit 12a15605b9521a2564a6e657905705a060e89095)
This commit is contained in:
Martijn Dekker 2020-05-29 08:27:53 +01:00
parent 047cb3303c
commit ec888867fd
6 changed files with 36 additions and 32 deletions

3
NEWS
View file

@ -18,6 +18,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
This now correctly lists your directory and then prints "ls executed", This now correctly lists your directory and then prints "ls executed",
instead of printing "ls executed" twice. instead of printing "ls executed" twice.
- Fix a similar bug with aliases. These can now be correctly unset
in subshell environments.
2020-05-21: 2020-05-21:
- Fix truncating of files with the combined redirections '<>;file' and - Fix truncating of files with the combined redirections '<>;file' and

View file

@ -197,6 +197,8 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
troot = tdata.sh->track_tree; troot = tdata.sh->track_tree;
} }
} }
if(context->shp->subshell && !context->shp->subshare)
sh_subfork();
return(setall(argv,flag,troot,&tdata)); return(setall(argv,flag,troot,&tdata));
} }
@ -1142,6 +1144,8 @@ int b_set(int argc,register char *argv[],Shbltin_t *context)
int b_unalias(int argc,register char *argv[],Shbltin_t *context) int b_unalias(int argc,register char *argv[],Shbltin_t *context)
{ {
Shell_t *shp = context->shp; Shell_t *shp = context->shp;
if(shp->subshell && !shp->subshare)
sh_subfork();
return(unall(argc,argv,shp->alias_tree,shp)); return(unall(argc,argv,shp->alias_tree,shp));
} }
@ -1161,11 +1165,7 @@ static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp)
struct checkpt buff; struct checkpt buff;
NOT_USED(argc); NOT_USED(argc);
if(troot==shp->alias_tree) if(troot==shp->alias_tree)
{
name = sh_optunalias; name = sh_optunalias;
if(shp->subshell)
troot = sh_subaliastree(0);
}
else else
name = sh_optunset; name = sh_optunset;
while(r = optget(argv,name)) switch(r) while(r = optget(argv,name)) switch(r)

View file

@ -423,7 +423,6 @@ extern void sh_printopts(Shopt_t,int,Shopt_t*);
extern int sh_readline(Shell_t*,char**,volatile int,int,ssize_t,long); extern int sh_readline(Shell_t*,char**,volatile int,int,ssize_t,long);
extern Sfio_t *sh_sfeval(char*[]); extern Sfio_t *sh_sfeval(char*[]);
extern void sh_setmatch(Shell_t*,const char*,int,int,int[],int); extern void sh_setmatch(Shell_t*,const char*,int,int,int[],int);
extern Dt_t *sh_subaliastree(int);
extern void sh_scope(Shell_t*, struct argnod*, int); extern void sh_scope(Shell_t*, struct argnod*, int);
extern Namval_t *sh_scoped(Shell_t*, Namval_t*); extern Namval_t *sh_scoped(Shell_t*, Namval_t*);
extern Dt_t *sh_subfuntree(int); extern Dt_t *sh_subfuntree(int);

View file

@ -1390,8 +1390,6 @@ Namval_t *nv_open(const char *name, Dt_t *root, int flags)
msg = e_aliname; msg = e_aliname;
while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') && while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
(c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON)); (c>=0x200 || !(c=sh_lexstates[ST_NORM][c]) || c==S_EPAT || c==S_COLON));
if(shp->subshell && c=='=')
root = sh_subaliastree(1);
if(c= *--cp) if(c= *--cp)
*cp = 0; *cp = 0;
np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD); np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);

View file

@ -71,7 +71,6 @@ static struct subshell
Dt_t *var; /* variable table at time of subshell */ Dt_t *var; /* variable table at time of subshell */
struct Link *svar; /* save shell variable table */ struct Link *svar; /* save shell variable table */
Dt_t *sfun; /* function scope for subshell */ Dt_t *sfun; /* function scope for subshell */
Dt_t *salias;/* alias scope for subshell */
Pathcomp_t *pathlist; /* for PATH variable */ Pathcomp_t *pathlist; /* for PATH variable */
#if (ERROR_VERSION >= 20030214L) #if (ERROR_VERSION >= 20030214L)
struct Error_context_s *errcontext; struct Error_context_s *errcontext;
@ -375,24 +374,6 @@ static void nv_restore(struct subshell *sp)
sp->shpwd=save; sp->shpwd=save;
} }
/*
* return pointer to alias tree
* create new one if in a subshell and one doesn't exist and create is non-zero
*/
Dt_t *sh_subaliastree(int create)
{
register struct subshell *sp = subshell_data;
if(!sp || sp->shp->curenv==0)
return(sh.alias_tree);
if(!sp->salias && create)
{
sp->salias = dtopen(&_Nvdisc,Dtoset);
dtview(sp->salias,sp->shp->alias_tree);
sp->shp->alias_tree = sp->salias;
}
return(sp->salias);
}
/* /*
* return pointer to function tree * return pointer to function tree
* create new one if in a subshell and one doesn't exist and create is non-zero * create new one if in a subshell and one doesn't exist and create is non-zero
@ -710,12 +691,6 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
{ {
int n; int n;
shp->options = sp->options; shp->options = sp->options;
if(sp->salias)
{
shp->alias_tree = dtview(sp->salias,0);
table_unset(sp->salias,0);
dtclose(sp->salias);
}
if(sp->sfun) if(sp->sfun)
{ {
shp->fun_tree = dtview(sp->sfun,0); shp->fun_tree = dtview(sp->sfun,0);

View file

@ -652,5 +652,34 @@ v=$("$SHELL" -c "$(cat "$a")") && [[ $v == ok ]] || err_exit 'fail: more fun 2'
v=$("$SHELL" -c 'eval "$(cat "$1")"' x "$a") && [[ $v == ok ]] || err_exit "fail: more fun 3" v=$("$SHELL" -c 'eval "$(cat "$1")"' x "$a") && [[ $v == ok ]] || err_exit "fail: more fun 3"
v=$("$SHELL" -c '. "$1"' x "$a") && [[ $v == ok ]] || err_exit "fail: more fun 4" v=$("$SHELL" -c '. "$1"' x "$a") && [[ $v == ok ]] || err_exit "fail: more fun 4"
# ======
# Unsetting or redefining aliases within subshells
# ...alias can be unset in subshell
alias al="echo 'mainalias'"
(unalias al; alias al >/dev/null) && err_exit 'alias fails to be unset in subshell'
v=$(unalias al; alias al >/dev/null) && err_exit 'alias fails to be unset in comsub'
[[ $(eval 'al') == 'mainalias' ]] || err_exit 'main alias fails to survive unset in subshell(s)'
v=${ eval 'al'; unalias al 2>&1; } && [[ $v == 'mainalias' ]] && ! alias al >/dev/null \
|| err_exit 'main shell alias wrongly survives unset within ${ ...; }'
# ...alias can be redefined in subshell
alias al="echo 'mainalias'"
(alias al='echo sub'; [[ $(eval 'al') == sub ]]) || err_exit 'alias fails to be redefined in subshell'
v=$(alias al='echo sub'; eval 'al') && [[ $v == sub ]] || err_exit 'alias fails to be redefined in comsub'
[[ $(eval 'al') == 'mainalias' ]] || err_exit 'main alias fails to survive redefinition in subshell(s)'
v=${ eval 'al'; alias al='echo subshare'; } && [[ $v == 'mainalias' && $(eval 'al') == subshare ]] \
|| err_exit 'alias redefinition fails to survive ${ ...; }'
# ====== # ======
exit $((Errors<125?Errors:125)) exit $((Errors<125?Errors:125))