From 6af6f846709403e80ef848a282f03150e54cd113 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 28 Apr 2017 12:12:00 -0600 Subject: [PATCH] Fix exponential behavior in glob() with respect to multiple '*'. See https://research.swtch.com/glob Adapted from https://perl5.git.perl.org/perl.git/commit/33252c318625f3c6c89b816ee88481940e3e6f95 --- lib/util/glob.c | 52 ++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/util/glob.c b/lib/util/glob.c index ee59642d4..ac19f86d7 100644 --- a/lib/util/glob.c +++ b/lib/util/glob.c @@ -135,9 +135,6 @@ typedef char Char; #define GLOB_LIMIT_STAT 2048 #define GLOB_LIMIT_READDIR 16384 -/* Limit of recursion during matching attempts. */ -#define GLOB_LIMIT_RECUR 64 - struct glob_lim { size_t glim_malloc; size_t glim_stat; @@ -164,7 +161,7 @@ static const Char * static int globexp1(const Char *, glob_t *, struct glob_lim *); static int globexp2(const Char *, const Char *, glob_t *, struct glob_lim *); -static int match(Char *, Char *, Char *, int); +static int match(Char *, Char *, Char *); #ifdef DEBUG static void qprintf(const char *, Char *); #endif @@ -699,7 +696,7 @@ glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, break; } - if (!match(pathend, pattern, restpattern, GLOB_LIMIT_RECUR)) { + if (!match(pathend, pattern, restpattern)) { *pathend = EOS; continue; } @@ -790,17 +787,24 @@ globextend(const Char *path, glob_t *pglob, struct glob_lim *limitp, /* * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. + * pattern causes an iteration. + * + * Note, this function differs from the original as per the discussion + * here: https://research.swtch.com/glob + * + * Basically we removed the recursion and made it use the algorithm + * from Russ Cox to not go quadratic on cases like a file called + * ("a" x 100) . "x" matched against a pattern like "a*a*a*a*a*a*a*y". */ static int -match(Char *name, Char *pat, Char *patend, int recur) +match(Char *name, Char *pat, Char *patend) { int ok, negate_range; Char c, k; + Char *nextp = NULL; + Char *nextn = NULL; - if (recur-- == 0) - return GLOB_NOSPACE; - +loop: while (pat < patend) { c = *pat++; switch (c & M_MASK) { @@ -809,19 +813,19 @@ match(Char *name, Char *pat, Char *patend, int recur) pat++; /* eat consecutive '*' */ if (pat == patend) return 1; - do { - if (match(name, pat, patend, recur)) - return 1; - } while (*name++ != EOS); - return 0; + if (*name == EOS) + return 0; + nextn = name + 1; + nextp = pat - 1; + break; case M_ONE: if (*name++ == EOS) - return 0; + goto fail; break; case M_SET: ok = 0; if ((k = *name++) == EOS) - return 0; + goto fail; if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) ++pat; while (((c = *pat++) & M_MASK) != M_END) { @@ -840,15 +844,23 @@ match(Char *name, Char *pat, Char *patend, int recur) ok = 1; } if (ok == negate_range) - return 0; + goto fail; break; default: if (*name++ != c) - return 0; + goto fail; break; } } - return *name == EOS; + if (*name == EOS) + return 1; +fail: + if (nextn) { + pat = nextp; + name = nextn; + goto loop; + } + return 0; } /* Free allocated data belonging to a glob_t structure. */ -- 2.40.0