Merge branch 'pw/wildmatch-fixes'

The wildmatch library code unlearns exponential behaviour it
acquired some time ago since it was borrowed from rsync.

* pw/wildmatch-fixes:
  t3070: make chain lint tester happy
  wildmatch: hide internal return values
  wildmatch: avoid undefined behavior
  wildmatch: fix exponential behavior
This commit is contained in:
Junio C Hamano 2023-04-04 14:28:27 -07:00
commit f834089925
3 changed files with 27 additions and 9 deletions

View File

@ -431,4 +431,15 @@ match 1 1 1 1 'a' '[B-a]'
match 0 1 0 1 'z' '[Z-y]' match 0 1 0 1 'z' '[Z-y]'
match 1 1 1 1 'Z' '[Z-y]' match 1 1 1 1 'Z' '[Z-y]'
test_expect_success 'matching does not exhibit exponential behavior' '
{
test-tool wildmatch wildmatch \
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab \
"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a" &
pid=$!
} &&
sleep 2 &&
! kill $!
'
test_done test_done

View File

@ -14,6 +14,10 @@
typedef unsigned char uchar; typedef unsigned char uchar;
/* Internal return values */
#define WM_ABORT_ALL -1
#define WM_ABORT_TO_STARSTAR -2
/* What character marks an inverted character class? */ /* What character marks an inverted character class? */
#define NEGATE_CLASS '!' #define NEGATE_CLASS '!'
#define NEGATE_CLASS2 '^' #define NEGATE_CLASS2 '^'
@ -83,12 +87,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
continue; continue;
case '*': case '*':
if (*++p == '*') { if (*++p == '*') {
const uchar *prev_p = p - 2; const uchar *prev_p = p;
while (*++p == '*') {} while (*++p == '*') {}
if (!(flags & WM_PATHNAME)) if (!(flags & WM_PATHNAME))
/* without WM_PATHNAME, '*' == '**' */ /* without WM_PATHNAME, '*' == '**' */
match_slash = 1; match_slash = 1;
else if ((prev_p < pattern || *prev_p == '/') && else if ((prev_p - pattern < 2 || *(prev_p - 2) == '/') &&
(*p == '\0' || *p == '/' || (*p == '\0' || *p == '/' ||
(p[0] == '\\' && p[1] == '/'))) { (p[0] == '\\' && p[1] == '/'))) {
/* /*
@ -114,7 +118,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
* only if there are no more slash characters. */ * only if there are no more slash characters. */
if (!match_slash) { if (!match_slash) {
if (strchr((char *)text, '/')) if (strchr((char *)text, '/'))
return WM_NOMATCH; return WM_ABORT_TO_STARSTAR;
} }
return WM_MATCH; return WM_MATCH;
} else if (!match_slash && *p == '/') { } else if (!match_slash && *p == '/') {
@ -125,7 +129,7 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
*/ */
const char *slash = strchr((char*)text, '/'); const char *slash = strchr((char*)text, '/');
if (!slash) if (!slash)
return WM_NOMATCH; return WM_ABORT_ALL;
text = (const uchar*)slash; text = (const uchar*)slash;
/* the slash is consumed by the top-level for loop */ /* the slash is consumed by the top-level for loop */
break; break;
@ -153,8 +157,12 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
break; break;
text++; text++;
} }
if (t_ch != p_ch) if (t_ch != p_ch) {
return WM_NOMATCH; if (match_slash)
return WM_ABORT_ALL;
else
return WM_ABORT_TO_STARSTAR;
}
} }
if ((matched = dowild(p, text, flags)) != WM_NOMATCH) { if ((matched = dowild(p, text, flags)) != WM_NOMATCH) {
if (!match_slash || matched != WM_ABORT_TO_STARSTAR) if (!match_slash || matched != WM_ABORT_TO_STARSTAR)
@ -274,5 +282,6 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
/* Match the "pattern" against the "text" string. */ /* Match the "pattern" against the "text" string. */
int wildmatch(const char *pattern, const char *text, unsigned int flags) int wildmatch(const char *pattern, const char *text, unsigned int flags)
{ {
return dowild((const uchar*)pattern, (const uchar*)text, flags); int res = dowild((const uchar*)pattern, (const uchar*)text, flags);
return res == WM_MATCH ? WM_MATCH : WM_NOMATCH;
} }

View File

@ -6,8 +6,6 @@
#define WM_NOMATCH 1 #define WM_NOMATCH 1
#define WM_MATCH 0 #define WM_MATCH 0
#define WM_ABORT_ALL -1
#define WM_ABORT_TO_STARSTAR -2
int wildmatch(const char *pattern, const char *text, unsigned int flags); int wildmatch(const char *pattern, const char *text, unsigned int flags);
#endif #endif