Running `zsh -fc ': ${${(PAA)p[foo]}::=x}'` in current zsh versions causes: > "segmentation fault (core dumped) zsh -fc ': ${${(PAA)p[foo]}::=x}' Also happens when testing with machabot: > 19:42 > : ${${(PAA)p[foo]}::=x} > 19:42 jp: zsh[248]: segfault at 0 ip b7dfcda3 sp bfeb9ebc > error 4 in libc-2.13.so[b7d84000+149000] Add a simple `dupstring(s2)` fallback instead of pointlessly trying to concatenate `s2` to NULL and segfaulting. Also added indication of empty string using `(nil)`; the empty string case should still provide a somewhat useful error message of > zsh:1: not an identifier: (nil) rather than > zsh:1: not an identifier: which is fairly confusing. Signed-off-by: Joey Pabalinas Requested-by: Bart Schaefer 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Src/params.c b/Src/params.c index de7730ae735a44963c..44a942296f23ddf88f 100644 --- a/Src/params.c +++ b/Src/params.c @@ -3004,6 +3004,8 @@ assignsparam(char *s, char *val, int flags) int sstart, created = 0; if (!isident(s)) { + if (!strcmp(s, "")) + s = "(nil)"; zerr("not an identifier: %s", s); zsfree(val); errflag |= ERRFLAG_ERROR; diff --git a/Src/string.c b/Src/string.c index 9e14ef94919c3e8ec5..7c24ab3c45777f31e9 100644 --- a/Src/string.c +++ b/Src/string.c @@ -126,9 +126,17 @@ mod_export char * zhtricat(char const *s1, char const *s2, char const *s3) { char *ptr; - size_t l1 = strlen(s1); - size_t l2 = strlen(s2); + size_t l1; + size_t l2; + /* String duplicate fallback to prevent NULL derefs */ + if (!s1 && !s2) + return dupstring(s3); + if (!s1) + l1 = 0, s1 = s2; + else + l1 = strlen(s1); + l2 = strlen(s2); ptr = (char *)zhalloc(l1 + l2 + strlen(s3) + 1); strcpy(ptr, s1); strcpy(ptr + l1, s2); @@ -144,8 +152,12 @@ dyncat(const char *s1, const char *s2) { /* This version always uses space from the current heap. */ char *ptr; - size_t l1 = strlen(s1); + size_t l1; + /* String duplicate fallback to prevent NULL derefs */ + if (!s1) + return dupstring(s2); + l1 = strlen(s1); ptr = (char *)zhalloc(l1 + strlen(s2) + 1); strcpy(ptr, s1); strcpy(ptr + l1, s2); @@ -158,8 +170,12 @@ bicat(const char *s1, const char *s2) { /* This version always uses permanently-allocated space. */ char *ptr; - size_t l1 = strlen(s1); + size_t l1; + /* String duplicate fallback to prevent NULL derefs */ + if (!s1) + return dupstring(s2); + l1 = strlen(s1); ptr = (char *)zalloc(l1 + strlen(s2) + 1); strcpy(ptr, s1); strcpy(ptr + l1, s2); diff --git a/Src/subst.c b/Src/subst.c index d027e3d83cadc631a7..9a8c635e313687d046 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -3150,6 +3150,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, } if (*itype_end(s, IIDENT, 0)) { untokenize(s); + if (!strcmp(s, " ")) + s = "(nil)"; zerr("not an identifier: %s", s); return NULL; } @@ -3210,6 +3212,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags, ++s; if (*itype_end(s, IIDENT, 0)) { untokenize(s); + if (!strcmp(s, "")) + s = "(nil)"; zerr("not an identifier: %s", s); return NULL; } -- 2.15.1