From 5491fe9724d8b7f76605d7621669ec08a3903cb2 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 1 Feb 2021 16:19:04 +0000 Subject: [PATCH] Correctly block invalid values for arrays of an enum type This fixes part of https://github.com/ksh93/ksh/issues/87: Scalar arrays (-a) and associative arrays (-A) of a type created by 'enum' did not consistently block values not specified by the enum type, yielding corrupted results. An expansion of type "${array[@]}" yielded random numbers instead of values for associative arrays of a type created by 'enum'. This does not yet fix another problem: ${array[@]} does not yield all values for associative enum arrays. src/cmd/ksh93/bltins/enum.c: put_enum(): - Always throw an error if the value is not in the list of possible values for an enum type. Remove incorrect check for the NV_NOFREE flag. Whatever that was meant to accomplish, I've no idea. src/cmd/ksh93/sh/array.c: nv_arraysettype(): - Instead of sh_eval()ing a shell assignment, use nv_putval() directly. Also use the stack (see src/lib/libast/man/stk.3) instead of malloc to save the value; it's faster and will be auto-freed at some point. This shortens the function and makes it faster by not entering into a whole new shell context -- which also fixes another problem: the error message from put_enum() didn't cause the shell to exit for indexed enum arrays. src/cmd/ksh93/sh/name.c: nv_setlist(): - Apply a patch from David Korn that correctly sets the data type for associative arrays, fixing the ${array[@]} expansion yielding random numbers. Thanks to @JohnoKing for the pointer. https://github.com/ksh93/ksh/issues/87#issuecomment-662613887 https://www.mail-archive.com/ast-developers@lists.research.att.com/msg00697.html src/cmd/ksh93/tests/enum.sh: - Add tests checking that invalid values are correctly blocked for indexed and associative arrays of an enum type. Makes progress on: https://github.com/ksh93/ksh/issues/87 --- NEWS | 10 +++++++++- src/cmd/ksh93/bltins/enum.c | 3 +-- src/cmd/ksh93/include/version.h | 2 +- src/cmd/ksh93/sh/array.c | 24 +++++------------------- src/cmd/ksh93/sh/name.c | 2 ++ src/cmd/ksh93/tests/enum.sh | 12 ++++++++++++ 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/NEWS b/NEWS index bdea546ec..6997b58ba 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,14 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2021-02-01: + +- Fixed: scalar arrays (-a) and associative arrays (-A) of a type created by + 'enum' allowed values not specified by the enum type, corrupting results. + +- Fixed: the "${array[@]}" expansion for associative arrays of a type created + by 'enum' expanded to random numbers instead of the array's values. + 2021-01-30: - The -x option to the 'command' built-in now causes it to bypass built-ins @@ -12,7 +20,7 @@ Any uppercase BUG_* names are modernish shell bug IDs. a command with many arguments was divided into several command invocations. - The 2020-08-16 fix is improved with a compile-time feature test that - detects if and how the OS uses data alignment in the arguments list, + detects if the OS requires extra bytes per argument in the arguments list, maximising the efficiency of 'command -x' for the system it runs on. 2021-01-24: diff --git a/src/cmd/ksh93/bltins/enum.c b/src/cmd/ksh93/bltins/enum.c index 1bb99abf1..672593e17 100644 --- a/src/cmd/ksh93/bltins/enum.c +++ b/src/cmd/ksh93/bltins/enum.c @@ -150,8 +150,7 @@ static void put_enum(Namval_t* np,const char *val,int flags,Namfun_t *fp) } i++; } - if(nv_isattr(np,NV_NOFREE)) - error(ERROR_exit(1), "%s: invalid value %s",nv_name(np),val); + error(ERROR_exit(1), "%s: invalid value %s",nv_name(np),val); } static char* get_enum(register Namval_t* np, Namfun_t *fp) diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 073c261cd..42e2399b7 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -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-01-31" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2021-02-01" /* 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. */ diff --git a/src/cmd/ksh93/sh/array.c b/src/cmd/ksh93/sh/array.c index bfc1ba059..9adefe927 100644 --- a/src/cmd/ksh93/sh/array.c +++ b/src/cmd/ksh93/sh/array.c @@ -407,11 +407,7 @@ static Namval_t *array_find(Namval_t *np,Namarr_t *arp, int flag) int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags) { Namval_t *nq; - char *av[2]; - int rdonly = nv_isattr(np,NV_RDONLY); - int xtrace = sh_isoption(SH_XTRACE); Namarr_t *ap = nv_arrayptr(np); - av[1] = 0; sh.last_table = 0; if(!ap->table) { @@ -420,30 +416,20 @@ int nv_arraysettype(Namval_t *np, Namval_t *tp, const char *sub, int flags) } if(nq = nv_search(sub, ap->table, NV_ADD)) { + char *saved_value; + int rdonly = nv_isattr(np,NV_RDONLY); if(!nq->nvfun && nq->nvalue.cp && *nq->nvalue.cp==0) _nv_unset(nq,NV_RDONLY); nv_arraychild(np,nq,0); if(!nv_isattr(tp,NV_BINARY)) - { - sfprintf(sh.strbuf,"%s=%s",nv_name(nq),nv_getval(np)); - av[0] = strdup(sfstruse(sh.strbuf)); - } + saved_value = stkcopy(stkstd,nv_getval(np)); if(!nv_clone(tp,nq,flags|NV_NOFREE)) return(0); - ap->nelem |= ARRAY_SCAN; if(!rdonly) nv_offattr(nq,NV_RDONLY); if(!nv_isattr(tp,NV_BINARY)) - { - if(xtrace) - sh_offoption(SH_XTRACE); - ap->nelem &= ~ARRAY_SCAN; - sh_eval(sh_sfeval(av),0); - ap->nelem |= ARRAY_SCAN; - free((void*)av[0]); - if(xtrace) - sh_onoption(SH_XTRACE); - } + nv_putval(nq,saved_value,0); + ap->nelem |= ARRAY_SCAN; return(1); } return(0); diff --git a/src/cmd/ksh93/sh/name.c b/src/cmd/ksh93/sh/name.c index 5ebf6abbe..4a0b0667c 100644 --- a/src/cmd/ksh93/sh/name.c +++ b/src/cmd/ksh93/sh/name.c @@ -389,6 +389,8 @@ void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ) if(array&NV_ARRAY) { nv_setarray(np,nv_associative); + if(typ) + nv_settype(np,typ,0); } else { diff --git a/src/cmd/ksh93/tests/enum.sh b/src/cmd/ksh93/tests/enum.sh index 0cd63d96e..6e5fcbb0a 100755 --- a/src/cmd/ksh93/tests/enum.sh +++ b/src/cmd/ksh93/tests/enum.sh @@ -74,4 +74,16 @@ arr[green]=foo read -A arr <<< 'x y z xx yy' [[ ${arr[1]} == ${arr[green]} ]] || err_exit 'arr[1] != arr[green] after read' +# enum arrays didn't block unspecified values +# https://github.com/ksh93/ksh/issues/87 +exp=': Color_t: clr[2]: invalid value WRONG' +got=$(set +x; redirect 2>&1; Color_t -a clr=(red blue WRONG yellow); printf '%s\n' "${clr[@]}") +(((e = $?) == 1)) && [[ $got == *"$exp" ]] || err_exit "indexed enum array, unspecified value:" \ + "expected status 1, *$(printf %q "$exp"); got status $e, $(printf %q "$got")" +exp=': clr: invalid value BAD' +got=$(set +x; redirect 2>&1; Color_t -A clr=([foo]=red [bar]=blue [bad]=BAD); printf '%s\n' "${clr[@]}") +(((e = $?) == 1)) && [[ $got == *"$exp" ]] || err_exit "associative enum array, unspecified value:" \ + "expected status 1, *$(printf %q "$exp"); got status $e, $(printf %q "$got")" + +# ====== exit $((Errors<125?Errors:125))