From 033e1f4b9e00b07d3a332e2a9a6fecafd5e68456 Mon Sep 17 00:00:00 2001 From: tg Date: Tue, 27 May 2014 13:22:46 +0000 Subject: [PATCH] =?UTF-8?q?fix=20LP#1277691=20(=E2=80=9Cnameref=20RHS=20no?= =?UTF-8?q?t=20syntax=20checked=E2=80=9D)=20and=20the=20inability=20to=20u?= =?UTF-8?q?se=20errorf()=20while=20nameref=20states=20were=20being=20chang?= =?UTF-8?q?ed=20(by=20almost=20completely=20eliminating=20the=20global=20v?= =?UTF-8?q?ariable)=20and=20the=20readonly=20first=20array=20variable=20by?= =?UTF-8?q?pass=20(typo/refactoro);=20also,=20whitespace,=20one=20int=20?= =?UTF-8?q?=E2=86=92=20bool,=20and=20add=20a=20comment=20wrt.=20the=20pars?= =?UTF-8?q?er=20rewrite=20talked=20about=20with=20igli=20during=20a=20feve?= =?UTF-8?q?r=20;)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Build.sh | 6 ++--- Makefile | 4 +-- check.t | 7 +++--- exec.c | 6 ++--- funcs.c | 29 +++++++++++++--------- sh.h | 12 ++++----- var.c | 75 ++++++++++++++++++++++++++++++++++++++++++-------------- 7 files changed, 90 insertions(+), 49 deletions(-) diff --git a/Build.sh b/Build.sh index edbffb3..de6a6f3 100644 --- a/Build.sh +++ b/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.657 2014/03/28 12:08:25 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.658 2014/05/27 13:22:41 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014 @@ -1777,7 +1777,7 @@ else #define EXTERN #define MKSH_INCLUDES_ONLY #include "sh.h" - __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.657 2014/03/28 12:08:25 tg Exp $"); + __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.658 2014/05/27 13:22:41 tg Exp $"); int main(void) { printf("Hello, World!\n"); return (isatty(0)); } EOF case $cm in @@ -2300,7 +2300,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c addsrcs USE_PRINTF_BUILTIN printf.c test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose" -add_cppflags -DMKSH_BUILD_R=491 +add_cppflags -DMKSH_BUILD_R=499 $e $bi$me: Finished configuration testing, now producing output.$ao diff --git a/Makefile b/Makefile index 8f1c15e..00a77c4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/Makefile,v 1.132 2014/02/09 22:49:29 tg Exp $ +# $MirOS: src/bin/mksh/Makefile,v 1.133 2014/05/27 13:22:42 tg Exp $ #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014 @@ -55,7 +55,7 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 -DMKSH_DISABLE_DEPRECATED \ -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=0 -DHAVE_STRSIGNAL=0 \ -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \ -DHAVE_SYS_ERRLIST_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \ - -DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=491 + -DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=499 CPPFLAGS+= -D${${PROG:L}_tf:C/(Mir${MAN:E}{0,1}){2}/4/:S/x/mksh_BUILD/:U} CPPFLAGS+= -I. COPTS+= -std=c89 -Wall diff --git a/check.t b/check.t index ba6c33d..13e0ca6 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.645 2014/05/27 13:00:31 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.646 2014/05/27 13:22:42 tg Exp $ # OpenBSD src/regress/bin/ksh updated: 2013/12/02 20:39:44 #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -27,7 +27,7 @@ # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD expected-stdout: - @(#)MIRBSD KSH R49 2014/01/16 + @(#)MIRBSD KSH R49 2014/05/27 description: Check version of shell. stdin: @@ -36,7 +36,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R49 2014/01/16 + @(#)LEGACY KSH R49 2014/05/27 description: Check version of legacy shell. stdin: @@ -5488,7 +5488,6 @@ expected-stderr-pattern: name: readonly-4 description: Do not permit bypassing readonly for first array item -expected-fail: yes stdin: set -A arr -- foo bar readonly arr diff --git a/exec.c b/exec.c index a5c0d1f..3ad792b 100644 --- a/exec.c +++ b/exec.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.129 2014/01/11 16:26:27 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.130 2014/05/27 13:22:43 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL "/bin/sh" @@ -652,7 +652,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* but assign in there as usual */ typeset(cp, type_flags, 0, 0, 0); if (bourne_function_call && !(type_flags & EXPORT)) - typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0); + typeset(cp, LOCAL | LOCAL_COPY | EXPORT, 0, 0, 0); } if (Flag(FXTRACE)) { @@ -812,7 +812,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* set $_ to programme's full path */ /* setstr() can't fail here */ - setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), + setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0), tp->val.s, KSH_RETURN_ERROR); if (flags&XEXEC) { diff --git a/funcs.c b/funcs.c index 9eae260..857b651 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.254 2014/01/05 19:20:31 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.255 2014/05/27 13:22:44 tg Exp $"); #if HAVE_KILLPG /* @@ -648,6 +648,7 @@ c_typeset(const char **wp) const char *opts; const char *fieldstr = NULL, *basestr = NULL; bool localv = false, func = false, pflag = false, istset = true; + enum namerefflag new_refflag = SRF_NOP; switch (**wp) { @@ -728,7 +729,7 @@ c_typeset(const char **wp) flag = LCASEV; break; case 'n': - set_refflag = (builtin_opt.info & GI_PLUS) ? + new_refflag = (builtin_opt.info & GI_PLUS) ? SRF_DISABLE : SRF_ENABLE; break; /* export, readonly: POSIX -p flag */ @@ -752,8 +753,6 @@ c_typeset(const char **wp) flag = EXPORT; break; case '?': - errout: - set_refflag = SRF_NOP; return (1); } if (builtin_opt.info & GI_PLUS) { @@ -768,10 +767,10 @@ c_typeset(const char **wp) } if (fieldstr && !bi_getn(fieldstr, &field)) - goto errout; + return (1); if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) { bi_errorf("%s: %s", "bad integer base", basestr); - goto errout; + return (1); } if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && @@ -783,9 +782,9 @@ c_typeset(const char **wp) } if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) || - set_refflag != SRF_NOP)) { + new_refflag != SRF_NOP)) { bi_errorf("only -t, -u and -x options may be used with -f"); - goto errout; + return (1); } if (wp[builtin_opt.optind]) { /* @@ -809,10 +808,18 @@ c_typeset(const char **wp) * are also set in this command */ if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | - INTEGER | INT_U | INT_L)) || set_refflag != SRF_NOP) + INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP) fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | INTEGER | INT_U | INT_L); } + if (new_refflag != SRF_NOP) { + fclr &= ~(ARRAY | ASSOC); + fset &= ~(ARRAY | ASSOC); + fclr |= EXPORT; + fset |= ASSOC; + if (new_refflag == SRF_DISABLE) + fclr |= ASSOC; + } /* set variables and attributes */ if (wp[builtin_opt.optind] && @@ -843,14 +850,12 @@ c_typeset(const char **wp) } } else if (!typeset(wp[i], fset, fclr, field, base)) { bi_errorf("%s: %s", wp[i], "is not an identifier"); - goto errout; + return (1); } } - set_refflag = SRF_NOP; return (rv); } - set_refflag = SRF_NOP; /* list variables and attributes */ /* no difference at this point.. */ diff --git a/sh.h b/sh.h index bcb490b..711cad3 100644 --- a/sh.h +++ b/sh.h @@ -169,9 +169,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.685 2014/01/22 19:53:52 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.686 2014/05/27 13:22:45 tg Exp $"); #endif -#define MKSH_VERSION "R49 2014/01/16" +#define MKSH_VERSION "R49 2014/05/27" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -523,7 +523,7 @@ char *ucstrstr(char *, const char *); #define mkssert(e) do { } while (/* CONSTCOND */ 0) #endif -#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 491) +#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 499) #error Must run Build.sh to compile this. extern void thiswillneverbedefinedIhope(void); int @@ -1168,11 +1168,11 @@ EXTERN struct tbl vtemp; #define arrayindex(vp) ((unsigned long)((vp)->flag & AINDEX ? \ (vp)->ua.index : 0)) -EXTERN enum { +enum namerefflag { SRF_NOP, SRF_ENABLE, SRF_DISABLE -} set_refflag E_INIT(SRF_NOP); +}; /* command types */ #define CNONE 0 /* undefined */ @@ -1956,7 +1956,7 @@ void setint(struct tbl *, mksh_ari_t); void setint_n(struct tbl *, mksh_ari_t, int); struct tbl *typeset(const char *, uint32_t, uint32_t, int, int); void unset(struct tbl *, int); -const char *skip_varname(const char *, int) MKSH_A_PURE; +const char *skip_varname(const char *, bool) MKSH_A_PURE; const char *skip_wdvarname(const char *, bool) MKSH_A_PURE; int is_wdvarname(const char *, bool) MKSH_A_PURE; int is_wdvarassign(const char *) MKSH_A_PURE; diff --git a/var.c b/var.c index 4074ac3..217e9bf 100644 --- a/var.c +++ b/var.c @@ -28,7 +28,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.177 2014/01/11 18:09:43 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.178 2014/05/27 13:22:46 tg Exp $"); /*- * Variables @@ -42,6 +42,8 @@ __RCSID("$MirOS: src/bin/mksh/var.c,v 1.177 2014/01/11 18:09:43 tg Exp $"); static struct table specials; static uint32_t lcg_state = 5381, qh_state = 4711; +/* may only be set by typeset() just before call to array_index_calc() */ +static enum namerefflag innermost_refflag = SRF_NOP; static char *formatstr(struct tbl *, const char *); static void exportprep(struct tbl *, const char *); @@ -165,7 +167,8 @@ varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h) /* * Used to calculate an array index for global()/local(). Sets *arrayp * to true if this is an array, sets *valp to the array index, returns - * the basename of the array. + * the basename of the array. May only be called from global()/local() + * and must be their first callee. */ static const char * array_index_calc(const char *n, bool *arrayp, uint32_t *valp) @@ -177,7 +180,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) *arrayp = false; redo_from_ref: p = skip_varname(n, false); - if (set_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) { + if (innermost_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) { struct tbl *vp; char *vn; @@ -185,8 +188,8 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) /* check if this is a reference */ varsearch(e->loc, &vp, vn, hash(vn)); afree(vn, ATEMP); - if (vp && (vp->flag & (DEFINED|ASSOC|ARRAY)) == - (DEFINED|ASSOC)) { + if (vp && (vp->flag & (DEFINED | ASSOC | ARRAY)) == + (DEFINED | ASSOC)) { char *cp; /* gotcha! */ @@ -196,6 +199,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp) goto redo_from_ref; } } + innermost_refflag = SRF_NOP; if (p != n && *p == '[' && (len = array_ref_len(p))) { char *sub, *tmp; @@ -226,7 +230,10 @@ global(const char *n) bool array; uint32_t h, val; - /* Check to see if this is an array */ + /* + * check to see if this is an array; + * dereference namerefs; must come first + */ n = array_index_calc(n, &array, &val); h = hash(n); c = (unsigned char)n[0]; @@ -296,7 +303,10 @@ local(const char *n, bool copy) bool array; uint32_t h, val; - /* check to see if this is an array */ + /* + * check to see if this is an array; + * dereference namerefs; must come first + */ n = array_index_calc(n, &array, &val); mkssert(n != NULL); h = hash(n); @@ -701,6 +711,16 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) const char *val; size_t len; bool vappend = false; + enum namerefflag new_refflag = SRF_NOP; + + if ((set & (ARRAY | ASSOC)) == ASSOC) { + new_refflag = SRF_ENABLE; + set &= ~(ARRAY | ASSOC); + } + if ((clr & (ARRAY | ASSOC)) == ASSOC) { + new_refflag = SRF_DISABLE; + clr &= ~(ARRAY | ASSOC); + } /* check for valid variable name, search for value */ val = skip_varname(var, false); @@ -709,7 +729,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) return (NULL); } if (*val == '[') { - if (set_refflag != SRF_NOP) + if (new_refflag != SRF_NOP) errorf("%s: %s", var, "reference variable can't be an array"); len = array_ref_len(val); @@ -755,18 +775,32 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) tvar[len - 3] = '\0'; } - if (set_refflag == SRF_ENABLE) { - const char *qval; + if (new_refflag == SRF_ENABLE) { + const char *qval, *ccp; /* bail out on 'nameref foo+=bar' */ if (vappend) - errorfz(); + errorf("appending not allowed for nameref"); /* find value if variable already exists */ if ((qval = val) == NULL) { varsearch(e->loc, &vp, tvar, hash(tvar)); if (vp != NULL) qval = str_val(vp); } + /* check target value for being a valid variable name */ + ccp = skip_varname(qval, false); + if (ccp == qval) + errorf("%s: %s", var, "empty nameref target"); + len = (*ccp == '[') ? array_ref_len(ccp) : 0; + if (ccp[len]) { + /* + * works for cases "no array", "valid array with + * junk after it" and "invalid array"; in the + * latter case, len is also 0 and points to '[' + */ + errorf("%s: %s", qval, + "nameref target not a valid parameter name"); + } /* prevent nameref loops */ while (qval) { if (!strcmp(qval, tvar)) @@ -774,7 +808,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) "expression recurses on parameter"); varsearch(e->loc, &vp, qval, hash(qval)); qval = NULL; - if (vp && ((vp->flag & (ARRAY|ASSOC)) == ASSOC)) + if (vp && ((vp->flag & (ARRAY | ASSOC)) == ASSOC)) qval = str_val(vp); } } @@ -784,11 +818,12 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0)) errorf("%s: %s", tvar, "restricted"); - vp = (set&LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : + innermost_refflag = new_refflag; + vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : global(tvar); - if (set_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) + if (new_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC) vp->flag &= ~ASSOC; - else if (set_refflag == SRF_ENABLE) { + else if (new_refflag == SRF_ENABLE) { if (vp->flag & ARRAY) { struct tbl *a, *tmp; @@ -808,14 +843,14 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base) set &= ~(LOCAL|LOCAL_COPY); - vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp; + vpbase = (vp->flag & ARRAY) ? global(arrayname(tvar)) : vp; /* * only allow export flag to be set; AT&T ksh allows any * attribute to be changed which means it can be truncated or * modified (-L/-R/-Z/-i) */ - if ((vpbase->flag&RDONLY) && + if ((vpbase->flag & RDONLY) && (val || clr || (set & ~EXPORT))) /* XXX check calls - is error here ok by POSIX? */ errorfx(2, "read-only: %s", tvar); @@ -959,7 +994,7 @@ unset(struct tbl *vp, int flags) * the terminating NUL if whole string is legal). */ const char * -skip_varname(const char *s, int aok) +skip_varname(const char *s, bool aok) { size_t alen; @@ -1337,7 +1372,7 @@ arraysearch(struct tbl *vp, uint32_t val) struct tbl *prev, *curr, *news; size_t len; - vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC; + vp->flag = (vp->flag | (ARRAY | DEFINED)) & ~ASSOC; /* the table entry is always [0] */ if (val == 0) return (vp); @@ -1377,6 +1412,8 @@ arraysearch(struct tbl *vp, uint32_t val) * Return the length of an array reference (eg, [1+2]) - cp is assumed * to point to the open bracket. Returns 0 if there is no matching * closing bracket. + * + * XXX this should parse the actual arithmetic syntax */ size_t array_ref_len(const char *cp)