svn commit: r303142 - head/lib/libc/gen

Andrey A. Chernov ache at FreeBSD.org
Thu Jul 21 12:53:38 UTC 2016


Author: ache
Date: Thu Jul 21 12:53:36 2016
New Revision: 303142
URL: https://svnweb.freebsd.org/changeset/base/303142

Log:
  1) GLOB_BRACE was somewhat broken. First it repeatedly calls glob0() in
  globexp1() recursive calls, but glob0() was not supposed to be called
  repeatedly in the original code. It finalize results by possible adding
  original pattern for no match case, may return GLOB_NOMATCH error and
  by sorting all things. Original pattern adding or GLOB_NOMATCH error
  can happens each time glob0() called repeatedly, and sorting happens
  for one item only, all things are never sorted. Second, f.e. "a{a"
  pattern does not match "a{a" file but match "a" file instead
  (just one example, there are many). Third, some errors (f.e. for limits
  or overflow) can be ignored by GLOB_BRACE code because it forces return (0).
  Add non-finalizing flag to glob0() and make globexp0() wrapper around
  recursively called globexp1() to finalize things like glob0() does.
  Reorganize braces code to work correctly.
  
  2) Don't allow MB_CUR_MAX * strlen overallocation hits GLOB_LIMIT_STRING
  (ARG_MAX) limit, use final string length, not malloced space for it.
  
  3) Revive DEBUG-ifdefed section.

Modified:
  head/lib/libc/gen/glob.c

Modified: head/lib/libc/gen/glob.c
==============================================================================
--- head/lib/libc/gen/glob.c	Thu Jul 21 12:50:23 2016	(r303141)
+++ head/lib/libc/gen/glob.c	Thu Jul 21 12:53:36 2016	(r303142)
@@ -128,8 +128,6 @@ struct glob_limit {
 #define	RBRACE		L'}'
 #define	COMMA		L','
 
-#ifndef DEBUG
-
 #define	M_QUOTE		0x8000000000ULL
 #define	M_PROTECT	0x4000000000ULL
 #define	M_MASK		0xffffffffffULL
@@ -137,18 +135,6 @@ struct glob_limit {
 
 typedef uint_fast64_t Char;
 
-#else
-
-#define	M_QUOTE		0x80
-#define	M_PROTECT	0x40
-#define	M_MASK		0xff
-#define	M_CHAR		0x7f
-
-typedef char Char;
-
-#endif
-
-
 #define	CHAR(c)		((Char)((c)&M_CHAR))
 #define	META(c)		((Char)((c)|M_QUOTE))
 #define	UNPROT(c)	((c) & ~M_PROTECT)
@@ -171,7 +157,7 @@ static const Char *g_strchr(const Char *
 static Char	*g_strcat(Char *, const Char *);
 #endif
 static int	 g_stat(Char *, struct stat *, glob_t *);
-static int	 glob0(const Char *, glob_t *, struct glob_limit *);
+static int	 glob0(const Char *, glob_t *, struct glob_limit *, int);
 static int	 glob1(Char *, glob_t *, struct glob_limit *);
 static int	 glob2(Char *, Char *, Char *, Char *, glob_t *,
     struct glob_limit *);
@@ -180,8 +166,9 @@ static int	 glob3(Char *, Char *, Char *
 static int	 globextend(const Char *, glob_t *, struct glob_limit *, int);
 static const Char *
 		 globtilde(const Char *, Char *, size_t, glob_t *);
+static int	 globexp0(const Char *, glob_t *, struct glob_limit *);
 static int	 globexp1(const Char *, glob_t *, struct glob_limit *);
-static int	 globexp2(const Char *, const Char *, glob_t *, int *,
+static int	 globexp2(const Char *, const Char *, glob_t *,
     struct glob_limit *);
 static int	 match(Char *, Char *, Char *);
 #ifdef DEBUG
@@ -260,9 +247,49 @@ glob(const char * __restrict pattern, in
 	*bufnext = EOS;
 
 	if (flags & GLOB_BRACE)
-	    return (globexp1(patbuf, pglob, &limit));
+	    return (globexp0(patbuf, pglob, &limit));
 	else
-	    return (glob0(patbuf, pglob, &limit));
+	    return (glob0(patbuf, pglob, &limit, 1));
+}
+
+static int
+globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
+{
+	int rv;
+	size_t oldpathc;
+
+	/* Protect a single {}, for find(1), like csh */
+	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+			errno = 0;
+			return (GLOB_NOSPACE);
+		}
+		return (glob0(pattern, pglob, limit, 1));
+	}
+
+	oldpathc = pglob->gl_pathc;
+
+	if ((rv = globexp1(pattern, pglob, limit)) != 0)
+		return rv;
+	/*
+	 * If there was no match we are going to append the pattern
+	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+	 * and the pattern did not contain any magic characters
+	 * GLOB_NOMAGIC is there just for compatibility with csh.
+	 */
+	if (pglob->gl_pathc == oldpathc) {
+		if (((pglob->gl_flags & GLOB_NOCHECK) ||
+		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
+			!(pglob->gl_flags & GLOB_MAGCHAR))))
+			return (globextend(pattern, pglob, limit, 1));
+		else
+			return (GLOB_NOMATCH);
+	}
+	if (!(pglob->gl_flags & GLOB_NOSORT))
+		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+	return (0);
 }
 
 /*
@@ -273,24 +300,18 @@ glob(const char * __restrict pattern, in
 static int
 globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
 {
-	const Char* ptr = pattern;
-	int rv;
+	const Char* ptr;
 
-	if ((pglob->gl_flags & GLOB_LIMIT) &&
-	    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
-		errno = 0;
-		return (GLOB_NOSPACE);
+	if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+			errno = 0;
+			return (GLOB_NOSPACE);
+		}
+		return (globexp2(ptr, pattern, pglob, limit));
 	}
 
-	/* Protect a single {}, for find(1), like csh */
-	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
-		return glob0(pattern, pglob, limit);
-
-	while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
-		if (!globexp2(ptr, pattern, pglob, &rv, limit))
-			return rv;
-
-	return glob0(pattern, pglob, limit);
+	return (glob0(pattern, pglob, limit, 0));
 }
 
 
@@ -300,10 +321,10 @@ globexp1(const Char *pattern, glob_t *pg
  * If it fails then it tries to glob the rest of the pattern and returns.
  */
 static int
-globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
     struct glob_limit *limit)
 {
-	int     i;
+	int     i, rv;
 	Char   *lm, *ls;
 	const Char *pe, *pm, *pm1, *pl;
 	Char    patbuf[MAXPATHLEN];
@@ -315,7 +336,7 @@ globexp2(const Char *ptr, const Char *pa
 	ls = lm;
 
 	/* Find the balanced brace */
-	for (i = 0, pe = ++ptr; *pe; pe++)
+	for (i = 0, pe = ++ptr; *pe != EOS; pe++)
 		if (*pe == LBRACKET) {
 			/* Ignore everything between [] */
 			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
@@ -337,10 +358,8 @@ globexp2(const Char *ptr, const Char *pa
 		}
 
 	/* Non matching braces; just glob the pattern */
-	if (i != 0 || *pe == EOS) {
-		*rv = glob0(patbuf, pglob, limit);
-		return (0);
-	}
+	if (i != 0 || *pe == EOS)
+		return (glob0(pattern, pglob, limit, 0));
 
 	for (i = 0, pl = pm = ptr; pm <= pe; pm++)
 		switch (*pm) {
@@ -385,7 +404,9 @@ globexp2(const Char *ptr, const Char *pa
 #ifdef DEBUG
 				qprintf("globexp2:", patbuf);
 #endif
-				*rv = globexp1(patbuf, pglob, limit);
+				rv = globexp1(patbuf, pglob, limit);
+				if (rv)
+					return (rv);
 
 				/* move after the comma, to the next string */
 				pl = pm + 1;
@@ -395,7 +416,6 @@ globexp2(const Char *ptr, const Char *pa
 		default:
 			break;
 		}
-	*rv = 0;
 	return (0);
 }
 
@@ -517,7 +537,8 @@ globtilde(const Char *pattern, Char *pat
  * if things went well, nonzero if errors occurred.
  */
 static int
-glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
+glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+    int final)
 {
 	const Char *qpatnext;
 	int err;
@@ -587,23 +608,25 @@ glob0(const Char *pattern, glob_t *pglob
 	if ((err = glob1(patbuf, pglob, limit)) != 0)
 		return(err);
 
-	/*
-	 * If there was no match we are going to append the pattern
-	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
-	 * and the pattern did not contain any magic characters
-	 * GLOB_NOMAGIC is there just for compatibility with csh.
-	 */
-	if (pglob->gl_pathc == oldpathc) {
-		if (((pglob->gl_flags & GLOB_NOCHECK) ||
-		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
-			!(pglob->gl_flags & GLOB_MAGCHAR))))
-			return (globextend(pattern, pglob, limit, 1));
-		else
-			return (GLOB_NOMATCH);
+	if (final) {
+		/*
+		 * If there was no match we are going to append the pattern
+		 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+		 * and the pattern did not contain any magic characters
+		 * GLOB_NOMAGIC is there just for compatibility with csh.
+		 */
+		if (pglob->gl_pathc == oldpathc) {
+			if (((pglob->gl_flags & GLOB_NOCHECK) ||
+			    ((pglob->gl_flags & GLOB_NOMAGIC) &&
+				!(pglob->gl_flags & GLOB_MAGCHAR))))
+				return (globextend(pattern, pglob, limit, 1));
+			else
+				return (GLOB_NOMATCH);
+		}
+		if (!(pglob->gl_flags & GLOB_NOSORT))
+			qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+			    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
 	}
-	if (!(pglob->gl_flags & GLOB_NOSORT))
-		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
-		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
 	return (0);
 }
 
@@ -856,18 +879,19 @@ globextend(const Char *path, glob_t *pgl
 	len = MB_CUR_MAX * (size_t)(p - path);	/* XXX overallocation */
 	if (prot)
 		len += (size_t)(p - path) - 1;
-	limit->l_string_cnt += len;
-	if ((pglob->gl_flags & GLOB_LIMIT) &&
-	    limit->l_string_cnt >= GLOB_LIMIT_STRING) {
-		errno = 0;
-		return (GLOB_NOSPACE);
-	}
 	if ((copy = malloc(len)) != NULL) {
 		if (g_Ctoc(path, copy, len, prot)) {
 			free(copy);
 			errno = 0;
 			return (GLOB_NOSPACE);
 		}
+		limit->l_string_cnt += strlen(copy) + 1;
+		if ((pglob->gl_flags & GLOB_LIMIT) &&
+		    limit->l_string_cnt >= GLOB_LIMIT_STRING) {
+			free(copy);
+			errno = 0;
+			return (GLOB_NOSPACE);
+		}
 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
 	}
 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
@@ -1046,15 +1070,17 @@ qprintf(const char *str, Char *s)
 {
 	Char *p;
 
-	(void)printf("%s:\n", str);
-	for (p = s; *p; p++)
-		(void)printf("%c", CHAR(*p));
-	(void)printf("\n");
-	for (p = s; *p; p++)
-		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
-	(void)printf("\n");
-	for (p = s; *p; p++)
-		(void)printf("%c", ismeta(*p) ? '_' : ' ');
-	(void)printf("\n");
+	(void)printf("%s\n", str);
+	if (s != NULL) {
+		for (p = s; *p != EOS; p++)
+			(void)printf("%c", (char)CHAR(*p));
+		(void)printf("\n");
+		for (p = s; *p != EOS; p++)
+			(void)printf("%c", (isprot(*p) ? '\\' : ' '));
+		(void)printf("\n");
+		for (p = s; *p != EOS; p++)
+			(void)printf("%c", (ismeta(*p) ? '_' : ' '));
+		(void)printf("\n");
+	}
 }
 #endif


More information about the svn-src-all mailing list