summaryrefslogtreecommitdiffstats
path: root/Src
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2025-11-10 15:13:36 -0800
committerBart Schaefer <schaefer@zsh.org>2025-11-10 15:13:36 -0800
commit8eec2c793cf782b0b067a94cf3442d6e118e8d77 (patch)
tree6ea2faa47e9e80106cf7d575a2686a12ac77f497 /Src
parent53402, 54042: make timeout for terminal queries configurable via a .term.quer... (diff)
downloadzsh-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).
Diffstat (limited to 'Src')
-rw-r--r--Src/params.c67
1 files changed, 42 insertions, 25 deletions
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;