about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/builtin.c9
-rw-r--r--Src/mem.c15
-rw-r--r--Src/params.c29
3 files changed, 36 insertions, 17 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index ce3aec0a2..1345b3006 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1924,10 +1924,13 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	    Param apm;
 	    char **x;
 	    if (PM_TYPE(pm->flags) == PM_ARRAY) {
-		x = zarrdup((*pm->gsu.a->getfn)(pm));
+		x = (*pm->gsu.a->getfn)(pm);
 		uniqarray(x);
-		pm->gsu.a->setfn(pm, x);
-		if (pm->ename && x)
+		if (pm->flags & PM_SPECIAL) {
+		    if (zheapptr(x))
+			x = zarrdup(x);
+		    (*pm->gsu.a->setfn)(pm, x);
+		} else if (pm->ename && x)
 		    arrfixenv(pm->ename, x);
 	    } else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename &&
 		       (apm =
diff --git a/Src/mem.c b/Src/mem.c
index 499f7d7e4..bcdd1efe9 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -329,6 +329,21 @@ mmap_heap_alloc(size_t *n)
 }
 #endif
 
+/* check whether a pointer is within a memory pool */
+
+/**/
+mod_export void *
+zheapptr(void *p)
+{
+    Heap h;
+    queue_signals();
+    for (h = heaps; h; h = h->next)
+	if ((char *)p >= arena(h) &&
+	    (char *)p + H_ISIZE < arena(h) + ARENA_SIZEOF(h))
+	    break;
+    unqueue_signals();
+    return (h ? p : 0);
+}
 
 /* allocate memory from the current memory pool */
 
diff --git a/Src/params.c b/Src/params.c
index efdb42aca..135c40f1d 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2820,11 +2820,11 @@ tiedarrsetfn(Param pm, char *x)
 	*dptr->arrptr = sepsplit(x, sepbuf, 0, 0);
 	if (pm->flags & PM_UNIQUE)
 	    uniqarray(*dptr->arrptr);
+	zsfree(x);
     } else
 	*dptr->arrptr = NULL;
     if (pm->ename)
 	arrfixenv(pm->nam, *dptr->arrptr);
-    zsfree(x);
 }
 
 /**/
@@ -2847,17 +2847,16 @@ tiedarrunsetfn(Param pm, UNUSED(int exp))
 }
 
 /**/
-void
-uniqarray(char **x)
+static void
+arrayuniq(char **x, int freeok)
 {
     char **t, **p = x;
 
-    if (!x || !*x)
-	return;
     while (*++p)
 	for (t = x; t < p; t++)
 	    if (!strcmp(*p, *t)) {
-		zsfree(*p);
+		if (freeok)
+		    zsfree(*p);
 		for (t = p--; (*t = t[1]) != NULL; t++);
 		break;
 	    }
@@ -2865,18 +2864,20 @@ uniqarray(char **x)
 
 /**/
 void
-zhuniqarray(char **x)
+uniqarray(char **x)
 {
-    char **t, **p = x;
+    if (!x || !*x)
+	return;
+    arrayuniq(x, !zheapptr(*x));
+}
 
+/**/
+void
+zhuniqarray(char **x)
+{
     if (!x || !*x)
 	return;
-    while (*++p)
-	for (t = x; t < p; t++)
-	    if (!strcmp(*p, *t)) {
-		for (t = p--; (*t = t[1]) != NULL; t++);
-		break;
-	    }
+    arrayuniq(x, 0);
 }
 
 /* Function to get value of special parameter `#' and `ARGC' */