From edc04bd94656a152e17f06188bcef172d62a3ad4 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 13 Jan 2020 00:27:24 +0000 Subject: 45291: A glob with a trailing slash will now match unreadable/unexecutable directories. --- Src/glob.c | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) (limited to 'Src/glob.c') diff --git a/Src/glob.c b/Src/glob.c index f67a376b9..bee890caf 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -279,11 +279,11 @@ addpath(char *s, int l) * foo/ can be used to reference a non-directory foo. Returns nonzero if * * the file does not exists. */ -/**/ static int statfullpath(const char *s, struct stat *st, int l) { char buf[PATH_MAX+1]; + int check_for_being_a_directory = 0; DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX, "BUG: statfullpath(): pathname too long"); @@ -294,16 +294,44 @@ statfullpath(const char *s, struct stat *st, int l) * Don't add the '.' if the path so far is empty, since * then we get bogus empty strings inserted as files. */ - buf[pathpos - pathbufcwd] = '.'; - buf[pathpos - pathbufcwd + 1] = '\0'; - l = 0; + if (st) { + buf[pathpos - pathbufcwd] = '.'; + buf[pathpos - pathbufcwd + 1] = '\0'; + l = 0; + } + else { + check_for_being_a_directory = 1; + } } unmetafy(buf, NULL); - if (!st) { + if (st) { + return l ? lstat(buf, st) : stat(buf, st); + } + else if (check_for_being_a_directory) { + struct stat tmp; + if (stat(buf, &tmp)) + return -1; + + return S_ISDIR(tmp.st_mode) ? 0 : -1; + } + else { char lbuf[1]; - return access(buf, F_OK) && (!l || readlink(buf, lbuf, 1) < 0); + + /* If it exists, signal success. */ + if (access(buf, F_OK) == 0) + return 0; + + /* Would a dangling symlink be good enough? */ + if (l == 0) + return -1; + + /* Is it a dangling symlink? */ + if (readlink(buf, lbuf, 1) >= 0) + return 0; + + /* Guess it doesn't exist, then. */ + return -1; } - return l ? lstat(buf, st) : stat(buf, st); } /* This may be set by qualifier functions to an array of strings to insert @@ -327,11 +355,13 @@ insert(char *s, int checked) if (gf_listtypes || gf_markdirs) { /* Add the type marker to the end of the filename */ mode_t mode; - checked = statted = 1; if (statfullpath(s, &buf, 1)) { unqueue_signals(); return; } + else { + checked = statted = 1; + } mode = buf.st_mode; if (gf_follow) { if (!S_ISLNK(mode) || statfullpath(s, &buf2, 0)) @@ -387,11 +417,10 @@ insert(char *s, int checked) qn = qn->next; } } else if (!checked) { - if (statfullpath(s, &buf, 1)) { + if (statfullpath(s, NULL, 1)) { unqueue_signals(); return; } - statted = 1; news = dyncat(pathbuf, news); } else news = dyncat(pathbuf, news); -- cgit v1.2.3 From 7f240e6aa9f5596a129474ba6294875dfe7ae264 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 21 Dec 2021 10:31:26 +0000 Subject: 49658: Fix NULL reference in match code. A test when acquiring the replacement pattern match in the globbing code erroneously allowed the use of a NULL pointer. This appears to be an unnecessary test case added alongside other surgery back in 2008. --- ChangeLog | 5 +++++ Src/glob.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Src/glob.c') diff --git a/ChangeLog b/ChangeLog index 17d6cbc96..270cf39ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2021-12-21 Peter Stephenson + + * 49658: Src/glob.c: Remove erroneous use of NULL pointer for + replacement pattern match. + 2021-12-21 Oliver Kiddle * 49655 based on 34928 (Daniel Hahler): diff --git a/Src/glob.c b/Src/glob.c index bee890caf..375671cea 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2549,7 +2549,7 @@ get_match_ret(Imatchdata imd, int b, int e) e += add; /* Everything now refers to metafied lengths. */ - if (replstr || (fl & SUB_LIST)) { + if (replstr) { if (fl & SUB_DOSUBST) { replstr = dupstring(replstr); singsub(&replstr); -- cgit v1.2.3 From 3bf95b91f0cd378c1a4e9c611a51cb9fe0e2ffcd Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sat, 19 Mar 2022 01:20:57 +0100 Subject: 49870: Fix NULL reference in match code more This reverts "49658: Fix NULL reference in match code." and adds a check inside the block, as well as a failsafe check at the end. The above commit (49658) causes a crash due to ll being calculated as 0 which leads to rr being an invalid pointer. Only adding a check for when ll is 0 just leads to bck-i-search pattern not working at all (the final hunk). Restoring the condition and adding an explicit NULL check for replstr seems to make matters work as intended. --- ChangeLog | 2 ++ Src/glob.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'Src/glob.c') diff --git a/ChangeLog b/ChangeLog index 4b02f3bc8..3b7cc4921 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,8 @@ * 49915: Src/Zle/comp.h, Src/Zle/compcore.c: Efficient dedup for unsorted completions + * 49870: Src/glob.c: Fix NULL reference in match code more + 2022-03-29 Bart Schaefer * 49918: NEWS, README: Update for 49917 and 49911. diff --git a/Src/glob.c b/Src/glob.c index 375671cea..349862531 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2549,7 +2549,7 @@ get_match_ret(Imatchdata imd, int b, int e) e += add; /* Everything now refers to metafied lengths. */ - if (replstr) { + if (replstr || (fl & SUB_LIST)) { if (fl & SUB_DOSUBST) { replstr = dupstring(replstr); singsub(&replstr); @@ -2568,7 +2568,8 @@ get_match_ret(Imatchdata imd, int b, int e) addlinknode(imd->repllist, rd); return imd->mstr; } - ll += strlen(replstr); + if (replstr) + ll += strlen(replstr); } if (fl & SUB_MATCH) /* matched portion */ ll += 1 + (e - b); @@ -2594,6 +2595,9 @@ get_match_ret(Imatchdata imd, int b, int e) if (bl) buf[bl - 1] = '\0'; + if (ll == 0) + return NULL; + rr = r = (char *) hcalloc(ll); if (fl & SUB_MATCH) { -- cgit v1.2.3 From c77cdb27db1c85b1842922a0b2cc4344478dd56b Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Mon, 4 Apr 2022 09:14:59 -0700 Subject: 49955: Src/glob.c: fix bad free in incremental-pattern-search matching --- ChangeLog | 6 ++++++ Src/Zle/zle_refresh.c | 2 ++ Src/glob.c | 13 ++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'Src/glob.c') diff --git a/ChangeLog b/ChangeLog index cde6bfc2d..11ebb7d66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2022-04-03 Bart Schaefer + + * 49955 (with thanks to Madhu ): Src/glob.c: + fix bad free in incremental-pattern-search matching (observed + only when compiled without MULTIBYTE support) + 2022-04-03 Mikael Magnusson * 49959: Completion/Zsh/Context/_brace_parameter: diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index d9d9503e2..c8c6f78c6 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -255,7 +255,9 @@ int cost; #endif static const REFRESH_ELEMENT zr_cr = { ZWC('\r'), 0 }; +#ifdef MULTIBYTE_support static const REFRESH_ELEMENT zr_dt = { ZWC('.'), 0 }; +#endif static const REFRESH_ELEMENT zr_nl = { ZWC('\n'), 0 }; static const REFRESH_ELEMENT zr_sp = { ZWC(' '), 0 }; static const REFRESH_ELEMENT zr_zr = { ZWC('\0'), 0 }; diff --git a/Src/glob.c b/Src/glob.c index 349862531..d4ffc2274 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -3286,6 +3286,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, return 1; } if (matched) { + /* Default is to match at the start; see comment in MULTIBYTE above */ switch (fl & (SUB_END|SUB_LONG|SUB_SUBSTR)) { case 0: case SUB_LONG: @@ -3355,7 +3356,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, /* longest or smallest at start with substrings */ t = s; if (fl & SUB_GLOBAL) { - imd.repllist = newlinklist(); + imd.repllist = (fl & SUB_LIST) ? znewlinklist() : newlinklist(); if (repllistp) *repllistp = imd.repllist; } @@ -3405,6 +3406,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * which is already marked for replacement. */ matched = 1; + if (t == send) + break; while (t < mpos) { ioff++; umlen--; @@ -3412,8 +3415,10 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, } break; } + if (t == send) + break; } - } while (matched); + } while (matched && t < send); /* * check if we can match a blank string, if so do it * at the start. Goodness knows if this is a good idea @@ -3485,6 +3490,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, * Results from get_match_ret in repllist are all metafied. */ s = *sp; + if (fl & SUB_LIST) + return 1; i = 0; /* start of last chunk we got from *sp */ for (nd = firstnode(imd.repllist); nd; incnode(nd)) { rd = (Repldata) getdata(nd); @@ -3514,7 +3521,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, imd.replstr = NULL; imd.repllist = NULL; *sp = get_match_ret(&imd, 0, 0); - return 1; + return (fl & SUB_RETFAIL) ? 0 : 1; } /**/ -- cgit v1.2.3 From b80d1600395c46b24ebe8d34e40fb4e660692de1 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Mon, 4 Apr 2022 14:21:50 -0700 Subject: 49991: single-byte brace expansion handles $'\0' and control character output aligns with multibyte --- ChangeLog | 3 +++ Src/glob.c | 15 ++++++--------- Src/utils.c | 11 ++++++++--- 3 files changed, 17 insertions(+), 12 deletions(-) (limited to 'Src/glob.c') diff --git a/ChangeLog b/ChangeLog index 92e5b6716..d2ffce95e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2022-04-04 Bart Schaefer + * 49991: Src/glob.c, Src/utils.c: single-byte brace expansion + handles $'\0' and control character output aligns with multibyte + * 49990: Src/hist.c: in single-byte, like multibyte, casemodify() avoids metafying characters that it otherwise did not touch diff --git a/Src/glob.c b/Src/glob.c index d4ffc2274..ca28f20e8 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -2220,7 +2220,7 @@ bracechardots(char *str, convchar_t *c1p, convchar_t *c2p) #ifdef MULTIBYTE_SUPPORT cstart == WEOF || #else - !cstart || + !*pconv || #endif pnext[0] != '.' || pnext[1] != '.') return 0; @@ -2241,7 +2241,7 @@ bracechardots(char *str, convchar_t *c1p, convchar_t *c2p) #ifdef MULTIBYTE_SUPPORT cend == WEOF || #else - !cend || + !*pconv || #endif *pnext != Outbrace) return 0; @@ -2305,22 +2305,19 @@ xpandbraces(LinkList list, LinkNode *np) strp = str - str3; lenalloc = strp + strlen(str2+1) + 1; do { -#ifdef MULTIBYTE_SUPPORT char *ncptr; int nclen; +#ifdef MULTIBYTE_SUPPORT mb_charinit(); ncptr = wcs_nicechar(cend, NULL, NULL); +#else + ncptr = nicechar(cend); +#endif nclen = strlen(ncptr); p = zhalloc(lenalloc + nclen); memcpy(p, str3, strp); memcpy(p + strp, ncptr, nclen); strcpy(p + strp + nclen, str2 + 1); -#else - p = zhalloc(lenalloc + 1); - memcpy(p, str3, strp); - sprintf(p + strp, "%c", cend); - strcat(p + strp, str2 + 1); -#endif insertlinknode(list, last, p); if (rev) /* decreasing: add in reverse order. */ last = nextnode(last); diff --git a/Src/utils.c b/Src/utils.c index f9127c70c..66cb2a63a 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -557,9 +557,14 @@ nicechar(int c) *s++ = '\\'; c = 't'; } else if (c < 0x20) { - *s++ = '\\'; - *s++ = 'C'; - *s++ = '-'; + /* + if (quotable) { + *s++ = '\\'; + *s++ = 'C'; + *s++ = '-'; + } else + */ + *s++ = '^'; c += 0x40; } done: -- cgit v1.2.3 From ebad5f8164335ccc6547b1508561726aa6420258 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Tue, 5 Apr 2022 09:10:45 -0700 Subject: 49994: Single-byte equivalence of users/22601 and workers/40891 --- ChangeLog | 5 +++++ Src/glob.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Src/glob.c') diff --git a/ChangeLog b/ChangeLog index b412b883d..d72395705 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2022-04-05 Bart Schaefer + + * 49994: Src/glob.c: Single-byte equivalence of users/22601 and + workers/40891 for matching against zero-length strings + 2022-04-05 Peter Stephenson * 49989: Src/Zle/compresult.c, Src/utils.c, Src/zsh.h: Align diff --git a/Src/glob.c b/Src/glob.c index ca28f20e8..400be12d5 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -3331,7 +3331,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, /* Largest possible match at tail of string: * * move forward along string until we get a match. * * Again there's no optimisation. */ - for (ioff = 0, t = s, umlen = uml; t < send; + for (ioff = 0, t = s, umlen = uml; t <= send; ioff++, t++, umlen--) { set_pat_start(p, t-s); if (pattrylen(p, t, send - t, umlen, &patstralloc, ioff)) { @@ -3362,7 +3362,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr, do { /* loop over all matches for global substitution */ matched = 0; - for (; t < send; t++, ioff++, umlen--) { + for (; t <= send; t++, ioff++, umlen--) { /* Find the longest match from this position. */ set_pat_start(p, t-s); if (pattrylen(p, t, send - t, umlen, &patstralloc, ioff)) { -- cgit v1.2.3