Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: D04parameter.ztst crashes if USE_MMAP is not defined



On Fri, Mar 1, 2024 at 1:57 AM Jun T <takimoto-j@xxxxxxxxxxxxxxxxx> wrote:
>
> Why (PM_TYPE(v->pm->node.flags) == PM_ARRAY) is true here?
> I believe the parameter here is 'string'. But didn't we unset it?

Thanks, this was the needed clue.

In stdunsetfn:

3903        if ((pm->node.flags & (PM_SPECIAL|PM_TIED)) == PM_TIED) {
3904        if (pm->ename) {
3905            zsfree(pm->ename);
3906            pm->ename = NULL;
3907        }
3908        pm->node.flags &= ~PM_TIED;
3909        }
3910        pm->node.flags |= PM_UNSET;

> So even with mmap, the parameter 'string' is not removed from paramtab...?

No, it isn't.  It's just marked PM_UNSET.  Then back in unsetparam_pm:

3811            if (oldpm && !altpm->level) {
3812            oldpm->old = NULL;
3813            /* fudge things so removenode isn't called */
3814            altpm->level = 1;
3815            }
3816            unsetparam_pm(altpm, 1, exp);

Calling unsetparam_pm() on the scalar altpm ends up calling the setfn
of the array name again, which clears the PM_UNSET flag that was
applied at line 3910.

3819        zsfree(altremove);
3820        if (!(pm->node.flags & PM_SPECIAL))
3821            pm->gsu.s = &stdscalar_gsu;

We change the gsu pointer but not the parameter flags.  Then:

3825         * If this was a local variable, we need to keep the old
3826         * struct so that it is resurrected at the right level.
3827         * This is partly because when an array/scalar value is set
3828         * and the parameter used to be the other sort, unsetparam()
3829         * is called.  Beyond that, there is an ambiguity:  should
3830         * foo() { local bar; unset bar; } make the global bar
3831         * available or not?  The following makes the answer "no".

3836        if ((pm->level && locallevel >= pm->level) ||
3837        (pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
3838        return 0;

This should fix it:

diff --git a/Src/params.c b/Src/params.c
index 064dbd2bc..e83e4aa5e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -3813,12 +3813,15 @@ unsetparam_pm(Param pm, int altflag, int exp)
                /* fudge things so removenode isn't called */
                altpm->level = 1;
            }
-           unsetparam_pm(altpm, 1, exp);
+           unsetparam_pm(altpm, 1, exp); /* This resets pm to empty */
+           pm->node.flags |= PM_UNSET;   /* so we must repeat this */
        }

        zsfree(altremove);
-       if (!(pm->node.flags & PM_SPECIAL))
+       if (!(pm->node.flags & PM_SPECIAL)) {
            pm->gsu.s = &stdscalar_gsu;
+           pm->node.flags &= ~PM_ARRAY;
+       }
     }

     /*
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 69a4fd3ec..0e2a04eb5 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1222,6 +1222,7 @@
   typeset -T STRING string
   print $STRING $string
   unset string
+  typeset -p string
   STRING=x:y:z
   print $STRING $string
   STRING=a:b




Messages sorted by: Reverse Date, Date, Thread, Author