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

Fix unreliable behavior when special vars are readonly or unset (#27)

src/cmd/ksh93/data/variables.c:
 - Running 'unset .sh.lineno' creates a memory fault, so fix that
   by giving it the NV_NOFREE attribute. This crash was happening
   because ${.sh.lineno} is an integer that cannot be freed from
   memory with free(3).

src/cmd/ksh93/sh/init.c:
 - Tell _nv_unset to ignore NV_RDONLY when $RANDOM and $LINENO are
   restored from the subshell scope. This is required to fully
   restore the original state of these variables after a virtual
   subshell finishes.

src/cmd/ksh93/bltins/typeset.c,
src/cmd/ksh93/sh/subshell.c:
 - Disabled some optimizations for two instances of 'sh_assignok' to
   fix 'readonly' in virtual subshells and '(unset .sh.level)' in
   nested functions. This fixes the following variables when
   '(readonly $varname); enum varname=' is run:

   $_
   ${.sh.name}
   ${.sh.subscript}
   ${.sh.level}

   The optimization in question prevents sh_assignok from saving the
   original state of these variables by making the sh_assignok call
   a no-op. Ksh needs the original state of a variable for it to be
   properly restored after a virtual subshell has run, otherwise ksh
   will simply carry over any new flags (being NV_RDONLY in this case)
   from the subshell into the main shell.

src/cmd/ksh93/tests/variables.sh:
 - Add regression tests from Martijn Dekker for setting special
   variables as readonly in virtual subshells and for unsetting
   special variables in general.

Fixes #4
This commit is contained in:
Johnothan King 2020-06-20 10:08:41 -07:00 committed by GitHub
parent ee698e89d5
commit bd3e2a8001
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 9 deletions

View file

@ -638,7 +638,7 @@ static void put_rand(register Namval_t* np,const char *val,int flags,Namfun_t *f
fp = nv_stack(np, NIL(Namfun_t*));
if(fp && !fp->nofree)
free((void*)fp);
_nv_unset(np,0);
_nv_unset(np,NV_RDONLY);
return;
}
if(flags&NV_INTEGER)
@ -696,7 +696,7 @@ static void put_lineno(Namval_t* np,const char *val,int flags,Namfun_t *fp)
fp = nv_stack(np, NIL(Namfun_t*));
if(fp && !fp->nofree)
free((void*)fp);
_nv_unset(np,0);
_nv_unset(np,NV_RDONLY);
return;
}
if(flags&NV_INTEGER)

View file

@ -235,8 +235,15 @@ int nv_subsaved(register Namval_t *np)
/*
* This routine will make a copy of the given node in the
* layer created by the most recent subshell_fork if the
* node hasn't already been copied
* layer created by the most recent virtual subshell if the
* node hasn't already been copied.
*
* add == 0: Move the node pointer from the parent shell to the current virtual subshell.
* add == 1: Create a copy of the node pointer in the current virtual subshell.
* add == 2: This will create a copy of the node pointer like 1, but it will disable the
* optimization for ${.sh.level}.
* add == 3: This is like 1, but it will never skip the following variables:
* ${.sh.level}, $_, ${.sh.subscript} and ${.sh.name}.
*/
Namval_t *sh_assignok(register Namval_t *np,int add)
{
@ -252,7 +259,7 @@ Namval_t *sh_assignok(register Namval_t *np,int add)
if(sp->subshare)
return(np);
/* don't bother with this */
if(!sp->shpwd || np==SH_LEVELNOD || np==L_ARGNOD || np==SH_SUBSCRNOD || np==SH_NAMENOD)
if(!sp->shpwd || (add != 3 && ((add != 2 && np==SH_LEVELNOD) || np==L_ARGNOD || np==SH_SUBSCRNOD || np==SH_NAMENOD)))
return(np);
if((ap=nv_arrayptr(np)) && (mp=nv_opensub(np)))
{