fix LP#1277691 (“nameref RHS not syntax checked”) and the inability to

use errorf() while nameref states were being changed (by almost completely
eliminating the global variable) and the readonly first array variable
bypass (typo/refactoro); also, whitespace, one int → bool, and add a
comment wrt. the parser rewrite talked about with igli during a fever ;)
This commit is contained in:
tg
2014-05-27 13:22:46 +00:00
parent d8461d400f
commit 033e1f4b9e
7 changed files with 90 additions and 49 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh #!/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, # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014 # 2011, 2012, 2013, 2014
@ -1777,7 +1777,7 @@ else
#define EXTERN #define EXTERN
#define MKSH_INCLUDES_ONLY #define MKSH_INCLUDES_ONLY
#include "sh.h" #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)); } int main(void) { printf("Hello, World!\n"); return (isatty(0)); }
EOF EOF
case $cm in case $cm in
@ -2300,7 +2300,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
addsrcs USE_PRINTF_BUILTIN printf.c addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose" 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 $e $bi$me: Finished configuration testing, now producing output.$ao

View File

@ -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, # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014 # 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_SETGROUPS=1 -DHAVE_STRERROR=0 -DHAVE_STRSIGNAL=0 \
-DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \ -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
-DHAVE_SYS_ERRLIST_DECL=1 -DHAVE_SYS_SIGLIST_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+= -D${${PROG:L}_tf:C/(Mir${MAN:E}{0,1}){2}/4/:S/x/mksh_BUILD/:U}
CPPFLAGS+= -I. CPPFLAGS+= -I.
COPTS+= -std=c89 -Wall COPTS+= -std=c89 -Wall

View File

@ -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 # OpenBSD src/regress/bin/ksh updated: 2013/12/02 20:39:44
#- #-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 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 # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R49 2014/01/16 @(#)MIRBSD KSH R49 2014/05/27
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -36,7 +36,7 @@ name: KSH_VERSION
category: shell:legacy-no category: shell:legacy-no
--- ---
expected-stdout: expected-stdout:
@(#)LEGACY KSH R49 2014/01/16 @(#)LEGACY KSH R49 2014/05/27
description: description:
Check version of legacy shell. Check version of legacy shell.
stdin: stdin:
@ -5488,7 +5488,6 @@ expected-stderr-pattern:
name: readonly-4 name: readonly-4
description: description:
Do not permit bypassing readonly for first array item Do not permit bypassing readonly for first array item
expected-fail: yes
stdin: stdin:
set -A arr -- foo bar set -A arr -- foo bar
readonly arr readonly arr

2
exec.c
View File

@ -23,7 +23,7 @@
#include "sh.h" #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 #ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL "/bin/sh" #define MKSH_DEFAULT_EXECSHELL "/bin/sh"

29
funcs.c
View File

@ -38,7 +38,7 @@
#endif #endif
#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 #if HAVE_KILLPG
/* /*
@ -648,6 +648,7 @@ c_typeset(const char **wp)
const char *opts; const char *opts;
const char *fieldstr = NULL, *basestr = NULL; const char *fieldstr = NULL, *basestr = NULL;
bool localv = false, func = false, pflag = false, istset = true; bool localv = false, func = false, pflag = false, istset = true;
enum namerefflag new_refflag = SRF_NOP;
switch (**wp) { switch (**wp) {
@ -728,7 +729,7 @@ c_typeset(const char **wp)
flag = LCASEV; flag = LCASEV;
break; break;
case 'n': case 'n':
set_refflag = (builtin_opt.info & GI_PLUS) ? new_refflag = (builtin_opt.info & GI_PLUS) ?
SRF_DISABLE : SRF_ENABLE; SRF_DISABLE : SRF_ENABLE;
break; break;
/* export, readonly: POSIX -p flag */ /* export, readonly: POSIX -p flag */
@ -752,8 +753,6 @@ c_typeset(const char **wp)
flag = EXPORT; flag = EXPORT;
break; break;
case '?': case '?':
errout:
set_refflag = SRF_NOP;
return (1); return (1);
} }
if (builtin_opt.info & GI_PLUS) { if (builtin_opt.info & GI_PLUS) {
@ -768,10 +767,10 @@ c_typeset(const char **wp)
} }
if (fieldstr && !bi_getn(fieldstr, &field)) if (fieldstr && !bi_getn(fieldstr, &field))
goto errout; return (1);
if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) { if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
bi_errorf("%s: %s", "bad integer base", basestr); bi_errorf("%s: %s", "bad integer base", basestr);
goto errout; return (1);
} }
if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] && 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)) || 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"); bi_errorf("only -t, -u and -x options may be used with -f");
goto errout; return (1);
} }
if (wp[builtin_opt.optind]) { if (wp[builtin_opt.optind]) {
/* /*
@ -809,10 +808,18 @@ c_typeset(const char **wp)
* are also set in this command * are also set in this command
*/ */
if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV | 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 | fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
LCASEV | INTEGER | INT_U | INT_L); 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 */ /* set variables and attributes */
if (wp[builtin_opt.optind] && if (wp[builtin_opt.optind] &&
@ -843,14 +850,12 @@ c_typeset(const char **wp)
} }
} else if (!typeset(wp[i], fset, fclr, field, base)) { } else if (!typeset(wp[i], fset, fclr, field, base)) {
bi_errorf("%s: %s", wp[i], "is not an identifier"); bi_errorf("%s: %s", wp[i], "is not an identifier");
goto errout; return (1);
} }
} }
set_refflag = SRF_NOP;
return (rv); return (rv);
} }
set_refflag = SRF_NOP;
/* list variables and attributes */ /* list variables and attributes */
/* no difference at this point.. */ /* no difference at this point.. */

12
sh.h
View File

@ -169,9 +169,9 @@
#endif #endif
#ifdef EXTERN #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 #endif
#define MKSH_VERSION "R49 2014/01/16" #define MKSH_VERSION "R49 2014/05/27"
/* arithmetic types: C implementation */ /* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES #if !HAVE_CAN_INTTYPES
@ -523,7 +523,7 @@ char *ucstrstr(char *, const char *);
#define mkssert(e) do { } while (/* CONSTCOND */ 0) #define mkssert(e) do { } while (/* CONSTCOND */ 0)
#endif #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. #error Must run Build.sh to compile this.
extern void thiswillneverbedefinedIhope(void); extern void thiswillneverbedefinedIhope(void);
int int
@ -1168,11 +1168,11 @@ EXTERN struct tbl vtemp;
#define arrayindex(vp) ((unsigned long)((vp)->flag & AINDEX ? \ #define arrayindex(vp) ((unsigned long)((vp)->flag & AINDEX ? \
(vp)->ua.index : 0)) (vp)->ua.index : 0))
EXTERN enum { enum namerefflag {
SRF_NOP, SRF_NOP,
SRF_ENABLE, SRF_ENABLE,
SRF_DISABLE SRF_DISABLE
} set_refflag E_INIT(SRF_NOP); };
/* command types */ /* command types */
#define CNONE 0 /* undefined */ #define CNONE 0 /* undefined */
@ -1956,7 +1956,7 @@ void setint(struct tbl *, mksh_ari_t);
void setint_n(struct tbl *, mksh_ari_t, int); void setint_n(struct tbl *, mksh_ari_t, int);
struct tbl *typeset(const char *, uint32_t, uint32_t, int, int); struct tbl *typeset(const char *, uint32_t, uint32_t, int, int);
void unset(struct tbl *, 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; const char *skip_wdvarname(const char *, bool) MKSH_A_PURE;
int is_wdvarname(const char *, bool) MKSH_A_PURE; int is_wdvarname(const char *, bool) MKSH_A_PURE;
int is_wdvarassign(const char *) MKSH_A_PURE; int is_wdvarassign(const char *) MKSH_A_PURE;

63
var.c
View File

@ -28,7 +28,7 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #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 * 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 struct table specials;
static uint32_t lcg_state = 5381, qh_state = 4711; 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 char *formatstr(struct tbl *, const char *);
static void exportprep(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 * 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 * 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 * static const char *
array_index_calc(const char *n, bool *arrayp, uint32_t *valp) 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; *arrayp = false;
redo_from_ref: redo_from_ref:
p = skip_varname(n, false); 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; struct tbl *vp;
char *vn; char *vn;
@ -196,6 +199,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp)
goto redo_from_ref; goto redo_from_ref;
} }
} }
innermost_refflag = SRF_NOP;
if (p != n && *p == '[' && (len = array_ref_len(p))) { if (p != n && *p == '[' && (len = array_ref_len(p))) {
char *sub, *tmp; char *sub, *tmp;
@ -226,7 +230,10 @@ global(const char *n)
bool array; bool array;
uint32_t h, val; 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); n = array_index_calc(n, &array, &val);
h = hash(n); h = hash(n);
c = (unsigned char)n[0]; c = (unsigned char)n[0];
@ -296,7 +303,10 @@ local(const char *n, bool copy)
bool array; bool array;
uint32_t h, val; 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); n = array_index_calc(n, &array, &val);
mkssert(n != NULL); mkssert(n != NULL);
h = hash(n); h = hash(n);
@ -701,6 +711,16 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
const char *val; const char *val;
size_t len; size_t len;
bool vappend = false; 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 */ /* check for valid variable name, search for value */
val = skip_varname(var, false); 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); return (NULL);
} }
if (*val == '[') { if (*val == '[') {
if (set_refflag != SRF_NOP) if (new_refflag != SRF_NOP)
errorf("%s: %s", var, errorf("%s: %s", var,
"reference variable can't be an array"); "reference variable can't be an array");
len = array_ref_len(val); 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'; tvar[len - 3] = '\0';
} }
if (set_refflag == SRF_ENABLE) { if (new_refflag == SRF_ENABLE) {
const char *qval; const char *qval, *ccp;
/* bail out on 'nameref foo+=bar' */ /* bail out on 'nameref foo+=bar' */
if (vappend) if (vappend)
errorfz(); errorf("appending not allowed for nameref");
/* find value if variable already exists */ /* find value if variable already exists */
if ((qval = val) == NULL) { if ((qval = val) == NULL) {
varsearch(e->loc, &vp, tvar, hash(tvar)); varsearch(e->loc, &vp, tvar, hash(tvar));
if (vp != NULL) if (vp != NULL)
qval = str_val(vp); 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 */ /* prevent nameref loops */
while (qval) { while (qval) {
if (!strcmp(qval, tvar)) if (!strcmp(qval, tvar))
@ -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)) strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
errorf("%s: %s", tvar, "restricted"); errorf("%s: %s", tvar, "restricted");
innermost_refflag = new_refflag;
vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) : vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) :
global(tvar); 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; vp->flag &= ~ASSOC;
else if (set_refflag == SRF_ENABLE) { else if (new_refflag == SRF_ENABLE) {
if (vp->flag & ARRAY) { if (vp->flag & ARRAY) {
struct tbl *a, *tmp; struct tbl *a, *tmp;
@ -808,7 +843,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
set &= ~(LOCAL|LOCAL_COPY); 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 * only allow export flag to be set; AT&T ksh allows any
@ -959,7 +994,7 @@ unset(struct tbl *vp, int flags)
* the terminating NUL if whole string is legal). * the terminating NUL if whole string is legal).
*/ */
const char * const char *
skip_varname(const char *s, int aok) skip_varname(const char *s, bool aok)
{ {
size_t alen; size_t alen;
@ -1377,6 +1412,8 @@ arraysearch(struct tbl *vp, uint32_t val)
* Return the length of an array reference (eg, [1+2]) - cp is assumed * 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 * to point to the open bracket. Returns 0 if there is no matching
* closing bracket. * closing bracket.
*
* XXX this should parse the actual arithmetic syntax
*/ */
size_t size_t
array_ref_len(const char *cp) array_ref_len(const char *cp)