diff --git a/src/cmd/ksh93/bltins/typeset.c b/src/cmd/ksh93/bltins/typeset.c index 8b91cc20bbc2..4e7e8ea2b4fa 100644 --- a/src/cmd/ksh93/bltins/typeset.c +++ b/src/cmd/ksh93/bltins/typeset.c @@ -1162,7 +1162,7 @@ static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) register const char *name; volatile int r; Dt_t *dp; - int nflag=0,all=0,isfun,jmpval; + int nflag=0,all=0,isfun,jmpval,nofree_attr; struct checkpt buff; NOT_USED(argc); if(troot==shp->alias_tree) @@ -1292,6 +1292,14 @@ static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) } } + /* + * When aliases are removed from the tree, the NV_NOFREE attribute must be used for + * preset aliases since those are given the NV_NOFREE attribute. _nv_unset discards + * NV_NOFREE so the status of NV_NOFREE is obtained now to prevent an invalid free crash. + */ + if(troot==shp->alias_tree) + nofree_attr = nv_isattr(np,NV_NOFREE); /* note: returns bitmask, not boolean */ + if(!nv_isnull(np) || nv_size(np) || nv_isattr(np,~(NV_MINIMAL|NV_NOFREE))) _nv_unset(np,0); if(troot==shp->var_tree && shp->st.real_fun && (dp=shp->var_tree->walk) && dp==shp->st.real_fun->sdict) @@ -1311,7 +1319,7 @@ static int unall(int argc, char **argv, register Dt_t *troot, Shell_t* shp) } /* The alias has been unset by call to _nv_unset, remove it from the tree */ else if(troot==shp->alias_tree) - nv_delete(np,troot,nv_isattr(np,NV_NOFREE)); + nv_delete(np,troot,nofree_attr); #if 0 /* causes unsetting local variable to expose global */ else if(shp->var_tree==troot && shp->var_tree!=shp->var_base && nv_search((char*)np,shp->var_tree,HASH_BUCKET|HASH_NOSCOPE)) diff --git a/src/cmd/ksh93/tests/alias.sh b/src/cmd/ksh93/tests/alias.sh index be0099f38b9f..e6a23e56c763 100755 --- a/src/cmd/ksh93/tests/alias.sh +++ b/src/cmd/ksh93/tests/alias.sh @@ -109,9 +109,9 @@ alias foo=bar unalias foo unalias foo && err_exit 'unalias should return non-zero when a previously set alias is unaliased twice' -# Removing a preset alias should work without an error from free(3) -err=$(set +x; { "$SHELL" -i -c 'unalias history'; } 2>&1) && [[ -z $err ]] \ -|| err_exit "removing a preset alias does not work (got $(printf %q "$err"))" +# Removing the history and r aliases should work without an error from free(3) +err=$(set +x; { "$SHELL" -i -c 'unalias history; unalias r'; } 2>&1) && [[ -z $err ]] \ +|| err_exit "the 'history' and 'r' aliases can't be removed (got $(printf %q "$err"))" # ====== exit $((Errors<125?Errors:125))