summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Src/params.c25
-rw-r--r--Test/V10private.ztst41
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 <schaefer@zsh.org>
+
+ * 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 <opk@zsh.org>
* 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
@@ -312,6 +312,47 @@ F:future revision will create a global with this assignment
>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"
typeset -p ptr1 ptr2