From 4b9cd6b8bd5f67500e716f8485aebd31a9f7cf47 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Fri, 23 Feb 2024 09:51:06 -0800 Subject: 52583: extra check for proper scope and existence of readonly specials --- ChangeLog | 6 ++++++ Src/params.c | 25 +++++++++++++++++++++++-- Test/V10private.ztst | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 91503f01d..d520ec8c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2024-02-23 Bart Schaefer + + * 52583: Src/params.c, Test/V10private.ztst: do an extra check + for proper scope and parameter existence when assigning to a + non-local name that resolves to a readonly special. + 2024-02-22 Oliver Kiddle * 52552: Completion/Unix/Command/_java: newer Java supports diff --git a/Src/params.c b/Src/params.c index b329d2079..225acb8a1 100644 --- a/Src/params.c +++ b/Src/params.c @@ -1004,8 +1004,29 @@ createparam(char *name, int flags) gethashnode2(paramtab, name) : paramtab->getnode(paramtab, name)); - if (oldpm && (oldpm->node.flags & PM_NAMEREF) && - !(flags & PM_NAMEREF) && (oldpm = upscope(oldpm, oldpm->base))) { + if (oldpm && (oldpm->node.flags & PM_RO_BY_DESIGN)) { + if (!(flags & PM_LOCAL)) { + /* Must call the API for namerefs and specials to work */ + pm = (Param) paramtab->getnode2(paramtab, oldpm->node.nam); + if (!pm || ((pm->node.flags & PM_NAMEREF) && + pm->level != locallevel)) { + zerr("%s: can't modify read-only parameter", name); + return NULL; + } + } + /** + * Implementation note: In the case of a readonly nameref, + * the right thing might be to insert a new global into + * the paramtab and point the local pm->old at it, rather + * than error. That is why gethashnode2() is called + * first, to avoid skipping up the stack prematurely. + **/ + } + + if (oldpm && !(flags & PM_NAMEREF) && + (!(oldpm->node.flags & PM_RO_BY_DESIGN) || !(flags & PM_LOCAL)) && + (oldpm->node.flags & PM_NAMEREF) && + (oldpm = upscope(oldpm, oldpm->base))) { Param lastpm; struct asgment stop; stop.flags = PM_NAMEREF | (flags & PM_LOCAL); diff --git a/Test/V10private.ztst b/Test/V10private.ztst index 4140d4e96..efa346002 100644 --- a/Test/V10private.ztst +++ b/Test/V10private.ztst @@ -311,6 +311,47 @@ F:future revision will create a global with this assignment >TOP >UP: + () { + typeset -a ary + local -P -n ref=ary + { + (){ + ref=XX # Should be an error + typeset -p ary ref + } + } always { + TRY_BLOCK_ERROR=0 + typeset -p ary ref + } + } + typeset -p ary +1:assignment to private nameref in wrong scope, part 1 +>typeset -a ary +>typeset -hn ref=ary +*?*ref: can't modify read-only parameter +*?*no such variable: ary + + () { + typeset -a ary + local -P -n ref=ary + { + (){ + typeset ref=XX # Should create a local + typeset -p ary ref + } + } always { + TRY_BLOCK_ERROR=0 + typeset -p ary ref + } + } + typeset -p ary +1:assignment to private nameref in wrong scope, part 2 +>typeset -g -a ary +>typeset ref=XX +>typeset -a ary +>typeset -hn ref=ary +*?*no such variable: ary + () { typeset -n ptr1=ptr2 private -n ptr2 # TYPESET_TO_UNSET makes this not a "placeholder" -- cgit 1.4.1