Skip to content

Commit

Permalink
Fix unsetting aliases in subshells
Browse files Browse the repository at this point in the history
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: att#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)
  • Loading branch information
McDutchie committed Jun 11, 2020
1 parent 047cb33 commit ec88886
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 32 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
This now correctly lists your directory and then prints "ls executed",
instead of printing "ls executed" twice.

- Fix a similar bug with aliases. These can now be correctly unset
in subshell environments.

2020-05-21:

- Fix truncating of files with the combined redirections '<>;file' and
Expand Down
8 changes: 4 additions & 4 deletions src/cmd/ksh93/bltins/typeset.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
troot = tdata.sh->track_tree;
}
}
if(context->shp->subshell && !context->shp->subshare)
sh_subfork();
return(setall(argv,flag,troot,&tdata));
}

Expand Down Expand Up @@ -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)
{
Shell_t *shp = context->shp;
if(shp->subshell && !shp->subshare)
sh_subfork();
return(unall(argc,argv,shp->alias_tree,shp));
}

Expand All @@ -1161,11 +1165,7 @@ static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp)
struct checkpt buff;
NOT_USED(argc);
if(troot==shp->alias_tree)
{
name = sh_optunalias;
if(shp->subshell)
troot = sh_subaliastree(0);
}
else
name = sh_optunset;
while(r = optget(argv,name)) switch(r)
Expand Down
1 change: 0 additions & 1 deletion src/cmd/ksh93/include/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 Sfio_t *sh_sfeval(char*[]);
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 Namval_t *sh_scoped(Shell_t*, Namval_t*);
extern Dt_t *sh_subfuntree(int);
Expand Down
2 changes: 0 additions & 2 deletions src/cmd/ksh93/sh/name.c
Original file line number Diff line number Diff line change
Expand Up @@ -1390,8 +1390,6 @@ Namval_t *nv_open(const char *name, Dt_t *root, int flags)
msg = e_aliname;
while((c= *(unsigned char*)cp++) && (c!='=') && (c!='/') &&
(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)
*cp = 0;
np = nv_search(name, root, (flags&NV_NOADD)?0:NV_ADD);
Expand Down
25 changes: 0 additions & 25 deletions src/cmd/ksh93/sh/subshell.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ static struct subshell
Dt_t *var; /* variable table at time of subshell */
struct Link *svar; /* save shell variable table */
Dt_t *sfun; /* function scope for subshell */
Dt_t *salias;/* alias scope for subshell */
Pathcomp_t *pathlist; /* for PATH variable */
#if (ERROR_VERSION >= 20030214L)
struct Error_context_s *errcontext;
Expand Down Expand Up @@ -375,24 +374,6 @@ static void nv_restore(struct subshell *sp)
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
* create new one if in a subshell and one doesn't exist and create is non-zero
Expand Down Expand Up @@ -710,12 +691,6 @@ Sfio_t *sh_subshell(Shell_t *shp,Shnode_t *t, volatile int flags, int comsub)
{
int n;
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)
{
shp->fun_tree = dtview(sp->sfun,0);
Expand Down
29 changes: 29 additions & 0 deletions src/cmd/ksh93/tests/subshell.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 '. "$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))

0 comments on commit ec88886

Please sign in to comment.