diff options
| author | Bart Schaefer <schaefer@zsh.org> | 2025-11-10 15:13:36 -0800 |
|---|---|---|
| committer | Bart Schaefer <schaefer@zsh.org> | 2025-11-10 15:13:36 -0800 |
| commit | 8eec2c793cf782b0b067a94cf3442d6e118e8d77 (patch) | |
| tree | 6ea2faa47e9e80106cf7d575a2686a12ac77f497 | |
| parent | 53402, 54042: make timeout for terminal queries configurable via a .term.quer... (diff) | |
| download | zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.tar zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.tar.gz zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.tar.bz2 zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.tar.lz zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.tar.xz zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.tar.zst zsh-8eec2c793cf782b0b067a94cf3442d6e118e8d77.zip | |
54064: avoid crash on named references to argv/ARGC, improve valid_nameref()
Leaves some edgecase issues unresolved (see tests).
| -rw-r--r-- | ChangeLog | 6 | ||||
| -rw-r--r-- | Src/params.c | 67 | ||||
| -rw-r--r-- | Test/K01nameref.ztst | 87 |
3 files changed, 134 insertions, 26 deletions
@@ -1,3 +1,9 @@ +2025-11-10 Bart Schaefer <schaefer@zsh.org> + + * 54064: Src/params.c, Test/K01nameref.ztst: avoid crash on named + references to argv/ARGC, improve syntax checks in valid_nameref(). + Leaves some edgecase issues unresolved (see tests). + 2025-11-10 Oliver Kiddle <opk@zsh.org> * 53402, 54042: Src/Zle/termquery.c, Src/Zle/zle_main.c, diff --git a/Src/params.c b/Src/params.c index b76fb8a6b..ccb73c9b6 100644 --- a/Src/params.c +++ b/Src/params.c @@ -1309,7 +1309,6 @@ isident(char *s) /* Require balanced [ ] pairs with something between */ if (!(ss = parse_subscript(++ss, 1, ']'))) return 0; - untokenize(s); return !ss[1]; } @@ -3247,8 +3246,8 @@ assignsparam(char *s, char *val, int flags) return NULL; } if (*val && (v->pm->node.flags & PM_NAMEREF)) { - if (!valid_refname(val)) { - zerr("invalid variable name: %s", val); + if (!valid_refname(val, v->pm->node.flags)) { + zerr("invalid name reference: %s", val); zsfree(val); unqueue_signals(); errflag |= ERRFLAG_ERROR; @@ -6505,30 +6504,48 @@ upscope_upper(Param pm, int reflevel) /**/ static int -valid_refname(char *val) +valid_refname(char *val, int flags) { - char *t = itype_end(val, INAMESPC, 0); + char *t; - if (idigit(*val)) - return 0; - if (*t != 0) { - if (*t == '[') { - tokenize(t = dupstring(t+1)); - while ((t = parse_subscript(t, 0, ']')) && *t++ == Outbrack) { - if (*t == Inbrack) - ++t; - else - break; - } - if (t && *t) { - /* zwarn("%s: stuff after subscript: %s", val, t); */ - t = NULL; - } - } else if (t[1] || !(*t == '!' || *t == '?' || - *t == '$' || *t == '-' || - *t == '0' || *t == '_')) { - /* Skipping * @ # because of doshfunc() implementation */ - t = NULL; + if (flags & PM_UPPER) { + /* Upward reference to positionals is doomed to fail */ + if (idigit(*val)) + return 0; + t = itype_end(val, INAMESPC, 0); + if ((t - val == 4) && + (!strncmp(val, "argv", 4) || + !strncmp(val, "ARGC", 4))) + return 0; + } else if (idigit(*val)) { + t = val; + while (*++t) + if (!idigit(*t)) + break; + if (*t && *t != '[') /* Need to test Inbrack here too? */ + return 0; + } else + t = itype_end(val, INAMESPC, 0); + + if (t == val) { + if (!(*t == '!' || *t == '?' || + *t == '$' || *t == '-' || + *t == '_')) + return 0; + ++t; + } + if (*t == '[') { + /* Another bit of isident() to emulate */ + tokenize(t = dupstring(t+1)); + while ((t = parse_subscript(t, 0, ']')) && *t++ == Outbrack) { + if (*t == Inbrack) + ++t; + else + break; + } + if (t && *t) { + /* zwarn("%s: stuff after subscript: %s", val, t); */ + return 0; } } return !!t; diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst index 5d229a94e..29a7af0de 100644 --- a/Test/K01nameref.ztst +++ b/Test/K01nameref.ztst @@ -531,7 +531,7 @@ F:ksh93 does not implement this either unset -n ptr1 typeset -n ptr1='not[2]good' 1:invalid nameref -*?*invalid variable name: not\[2\]good +*?*invalid name reference: not\[2\]good unset -n ptr1 unset hash @@ -1182,6 +1182,91 @@ F:previously this could create an infinite recursion and crash >f1: ref1=f1 ref2=f1 ref3=f1 # +# The following two tests are linked, do not separate +# + + edgelocal() ( local -n x=$1; typeset -p x; print -r $x ) + edgeupper() ( local -nu x=$1; typeset -p x; print -r $x ) + for edge in argv ARGC \@ \* \# 0 1 01 \! \? - _ + do + edgelocal $edge + edgelocal "$edge""[1]" + edgeupper $edge + done +0:references to builtin specials +F:Subscripting on 1 01 ! ? - should print first character but do not +>typeset -n x=argv +>argv +>typeset -n x='argv[1]' +>argv[1] +>typeset -n x=ARGC +>1 +>typeset -n x='ARGC[1]' +>1 +>typeset -n x=0 +>edgelocal +>typeset -n x='0[1]' +>e +>typeset -n x=1 +> +>typeset -n x='1[1]' +> +>typeset -n x=01 +> +>typeset -n x='01[1]' +> +>typeset -n x=! +>0 +>typeset -n x='![1]' +> +>typeset -un x=! +>0 +>typeset -n x='?' +>0 +>typeset -n x='?[1]' +> +>typeset -un x='?' +>0 +>typeset -n x=- +>569X +>typeset -n x='-[1]' +> +>typeset -un x=- +>569X +>typeset -n x=_ +>x +>typeset -n x='_[1]' +>x +>typeset -un x=_ +>x +?edgeupper: invalid name reference: argv +?edgeupper: invalid name reference: ARGC +?edgelocal: invalid name reference: @ +?edgelocal: invalid name reference: @[1] +?edgeupper: invalid name reference: @ +?edgelocal: invalid name reference: * +?edgelocal: invalid name reference: *[1] +?edgeupper: invalid name reference: * +?edgelocal: invalid name reference: # +?edgelocal: invalid name reference: #[1] +?edgeupper: invalid name reference: # +?edgeupper: invalid name reference: 0 +?edgeupper: invalid name reference: 1 +?edgeupper: invalid name reference: 01 + + edgelocal \$ + edgelocal '$[1]' + edgeupper \$ + unfunction edgelocal edgeupper +0qf:references to $$ +F:$$[1] reference should print the first digit of $$ but prints nothing +>typeset -n x='$' +>$$ +>typeset -n x='\$[1]' +>$$[1] +>$$ + +# # The following tests are run in interactive mode, using PS1 as an # assignable special with side-effects. This crashed at one time. # |
