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
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

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,
# 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

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
#-
# 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

6
exec.c
View File

@ -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) {

29
funcs.c
View File

@ -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.. */

12
sh.h
View File

@ -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;

75
var.c
View File

@ -28,7 +28,7 @@
#include <sys/sysctl.h>
#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)