From patchwork Fri Aug 11 14:50:35 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 22094 Received: (qmail 89563 invoked by alias); 11 Aug 2017 14:51:32 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 79491 invoked by uid 89); 11 Aug 2017 14:51:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-27.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=3326, 31615 X-HELO: mail-qt0-f180.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=KEILaRst6FvMIZfq2t8TH75MbcYo7+5jHWHTggsesyA=; b=UHdCyf7iuT6rB9u71zP7hTuwcR/5U53LqWxFzIUpMWL8c79km1nPwz6spV8F5ONWaW gkWkMStdTEAzm1fKLbEy8JJKTV9vNdFNJ6xjtvqn0ITapmoS8vcfc1qVbj2qDKMRKyWk btG6FzHD4FfgDbyBLqVoxMOdyPiJINl03qVtc3OKb9j/PibgIvEgsEJoWWCtBhTE8txs pJIcA59FZ1VGkq4lYYBTnA+EKheNrmedBBBUdDJrfx8Pd8tOLjudY4Smj2l3JpZH1fV4 viQ0rZ2viWQxTEMyYdilk+Kardqm7IR8hCHZtBeyl0bsiVKIuk4q4tJhUTQ3OyDQwUS6 9Upw== X-Gm-Message-State: AHYfb5j4Iisf/B9Bk4tenD7NLt95vNaSE27LXzGftuRPr+4H3YDG1HQ2 wThgJH1vpolsHflx5Zj+jg== X-Received: by 10.237.58.38 with SMTP id n35mr21856776qte.61.1502463062660; Fri, 11 Aug 2017 07:51:02 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 09/18] posix: Use char_array for internal glob dirname Date: Fri, 11 Aug 2017 11:50:35 -0300 Message-Id: <1502463044-4042-10-git-send-email-adhemerval.zanella@linaro.org> In-Reply-To: <1502463044-4042-1-git-send-email-adhemerval.zanella@linaro.org> References: <1502463044-4042-1-git-send-email-adhemerval.zanella@linaro.org> This is the first patch of the set to remove alloca usage on glob implementation. Internal path to search for file might expand to a non static directory derived from pattern for some difference cases (GLOB_NOESCAPE, GNU GLOB_TILDE) and to allow a non-static dirname path glob uses a lot of boilerplate code to manage the buffer (which is either allocated using alloca or malloc depending both to size requested and the total alloca_used). The patch changes to use the char_array struct with the default size (256 bytes). It simplifies all the allocation code by using char_array one and every internal buffer access is done using char_array provided functions. No functional changes are expected. Checked on x86_64-linux-gnu. * posix/globc.c (glob): Use char_array for dirname. --- posix/glob.c | 269 +++++++++++++++++++++++++---------------------------------- 1 file changed, 112 insertions(+), 157 deletions(-) diff --git a/posix/glob.c b/posix/glob.c index 554d558..858b709 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -91,6 +91,7 @@ #include #include +#include #ifndef LOGIN_NAME_MAX # define LOGIN_NAME_MAX 256 @@ -315,16 +316,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), glob_t *pglob) { const char *filename; - char *dirname = NULL; size_t dirlen; int status; size_t oldcount; int meta; - int dirname_modified; - int malloc_dirname = 0; + bool dirname_modified; glob_t dirs; int retval = 0; size_t alloca_used = 0; + struct char_array dirname; if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) { @@ -332,6 +332,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), return -1; } + if (!char_array_init_empty (&dirname)) + return GLOB_NOSPACE; + /* POSIX requires all slashes to be matched. This means that with a trailing slash we must match only directories. */ if (pattern[0] && pattern[strlen (pattern) - 1] == '/') @@ -352,12 +355,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t i; if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) - return GLOB_NOSPACE; + goto err_nospace; pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) * sizeof (char *)); if (pglob->gl_pathv == NULL) - return GLOB_NOSPACE; + goto err_nospace; for (i = 0; i <= pglob->gl_offs; ++i) pglob->gl_pathv[i] = NULL; @@ -415,7 +418,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), pglob->gl_pathc = 0; pglob->gl_pathv = NULL; } - return GLOB_NOSPACE; + goto err_nospace; } } @@ -431,6 +434,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), illegal_brace: if (__glibc_unlikely (!alloca_onealt)) free (onealt); + char_array_free (&dirname); return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); } @@ -476,7 +480,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (pglob); pglob->gl_pathc = 0; } - return result; + retval = result; + goto out; } if (*next == '}') @@ -493,9 +498,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (pglob->gl_pathc != firstc) /* We found some entries. */ - return 0; + retval = 0; else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) - return GLOB_NOMATCH; + retval = GLOB_NOMATCH; + goto out; } } @@ -511,14 +517,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (filename == NULL) filename = strchr (pattern, ':'); #endif /* __MSDOS__ || WINDOWS32 */ - dirname_modified = 0; + dirname_modified = false; if (filename == NULL) { /* This can mean two things: a simple name or "~name". The latter case is nothing but a notation for a directory. */ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') { - dirname = (char *) pattern; + if (!char_array_set_str (&dirname, pattern)) + goto err_nospace; dirlen = strlen (pattern); /* Set FILENAME to NULL as a special flag. This is ugly but @@ -536,10 +543,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), filename = pattern; #ifdef _AMIGA - dirname = (char *) ""; +# define CURRENT_FILENAME "" #else - dirname = (char *) "."; +# define CURRENT_FILENAME "." #endif + if (!char_array_set_str (&dirname, CURRENT_FILENAME)) + goto err_nospace; dirlen = 0; } } @@ -548,13 +557,13 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), && (flags & GLOB_NOESCAPE) == 0)) { /* "/pattern" or "\\/pattern". */ - dirname = (char *) "/"; + if (!char_array_set_str (&dirname, "/")) + goto err_nospace; dirlen = 1; ++filename; } else { - char *newp; dirlen = filename - pattern; #if defined __MSDOS__ || defined WINDOWS32 if (*filename == ':' @@ -568,50 +577,48 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* For now, disallow wildcards in the drive spec, to prevent infinite recursion in glob. */ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) - return GLOB_NOMATCH; + { + retval = GLOB_NOMATCH; + goto out; + } /* If this is "d:pattern", we need to copy ':' to DIRNAME as well. If it's "d:/pattern", don't remove the slash from "d:/", since "d:" and "d:/" are not the same.*/ } #endif - if (glob_use_alloca (alloca_used, dirlen + 1)) - newp = alloca_account (dirlen + 1, alloca_used); - else - { - newp = malloc (dirlen + 1); - if (newp == NULL) - return GLOB_NOSPACE; - malloc_dirname = 1; - } - *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; - dirname = newp; + if (!char_array_set_str_size (&dirname, pattern, dirlen)) + goto err_nospace; ++filename; if (filename[0] == '\0' #if defined __MSDOS__ || defined WINDOWS32 - && dirname[dirlen - 1] != ':' - && (dirlen < 3 || dirname[dirlen - 2] != ':' - || dirname[dirlen - 1] != '/') + && char_array_pos (&dirname, dirlen - 1) != ':' + && (dirlen < 3 || char_array_pos (&dirname, dirlen - 2) != ':' + || char_array_pos (&dirname, dirlen - 1) != '/') #endif && dirlen > 1) /* "pattern/". Expand "pattern", appending slashes. */ { int orig_flags = flags; int val; - if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') + if (!(flags & GLOB_NOESCAPE) + && char_array_pos (&dirname, dirlen - 1) == '\\') { /* "pattern\\/". Remove the final backslash if it hasn't been quoted. */ - char *p = (char *) &dirname[dirlen - 1]; - - while (p > dirname && p[-1] == '\\') --p; - if ((&dirname[dirlen] - p) & 1) + size_t p = dirlen - 1; + while (p > 0 && char_array_pos (&dirname, p - 1) == '\\') --p; + if ((dirlen - p) & 1) { - *(char *) &dirname[--dirlen] = '\0'; + /* Since we are shrinking the array, there is no need to + check the function return. */ + dirlen -= 1; + char_array_crop (&dirname, dirlen); flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); } } - val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + val = glob (char_array_str (&dirname), flags | GLOB_MARK, errfunc, + pglob); if (val == 0) pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK)); @@ -628,11 +635,14 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } } - if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) + && char_array_pos (&dirname, 0) == '~') { - if (dirname[1] == '\0' || dirname[1] == '/' - || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' - && (dirname[2] == '\0' || dirname[2] == '/'))) + if (char_array_pos (&dirname, 1) == '\0' + || char_array_pos (&dirname, 1) == '/' + || (!(flags & GLOB_NOESCAPE) && char_array_pos (&dirname, 1) == '\\' + && (char_array_pos (&dirname, 2) == '\0' + || char_array_pos (&dirname, 2) == '/'))) { /* Look up home directory. */ char *home_dir = getenv ("HOME"); @@ -688,10 +698,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), break; } if (!scratch_buffer_grow (&pwtmpbuf)) - { - retval = GLOB_NOSPACE; - goto out; - } + goto err_nospace; __set_errno (save); } # else @@ -704,8 +711,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (home_dir == NULL) { scratch_buffer_free (&pwtmpbuf); - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } } scratch_buffer_free (&pwtmpbuf); @@ -729,53 +735,26 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), # endif /* WINDOWS32 */ # endif /* Now construct the full directory. */ - if (dirname[1] == '\0') + if (char_array_pos (&dirname, 1) == '\0') { - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - - dirname = home_dir; - dirlen = strlen (dirname); - malloc_dirname = malloc_home_dir; + if (!char_array_set_str (&dirname, home_dir)) + goto err_nospace; + dirlen = char_array_size (&dirname) - 1; } else { - char *newp; - size_t home_len = strlen (home_dir); - int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); - if (use_alloca) - newp = alloca_account (home_len + dirlen, alloca_used); - else - { - newp = malloc (home_len + dirlen); - if (newp == NULL) - { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - retval = GLOB_NOSPACE; - goto out; - } - } - - mempcpy (mempcpy (newp, home_dir, home_len), - &dirname[1], dirlen); - - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - - dirname = newp; - dirlen += home_len - 1; - malloc_dirname = !use_alloca; - - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); + /* Replaces '~' by the obtained HOME dir. */ + char_array_erase (&dirname, 0); + if (!char_array_prepend_str (&dirname, home_dir)) + goto err_nospace; } - dirname_modified = 1; + dirname_modified = true; } # if !defined _AMIGA && !defined WINDOWS32 else { - char *end_name = strchr (dirname, '/'); + char *dirnamestr = char_array_at (&dirname, 0); + char *end_name = strchr (dirnamestr, '/'); char user_name[LOGIN_NAME_MAX]; char *unescape = NULL; @@ -783,22 +762,22 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { if (end_name == NULL) { - unescape = strchr (dirname, '\\'); + unescape = strchr (dirnamestr, '\\'); if (unescape) end_name = strchr (unescape, '\0'); } else - unescape = memchr (dirname, '\\', end_name - dirname); + unescape = memchr (dirnamestr, '\\', end_name - dirnamestr); } if (end_name == NULL) - strncpy (user_name, dirname + 1, LOGIN_NAME_MAX - 1); + strncpy (user_name, dirnamestr + 1, LOGIN_NAME_MAX - 1); else { if (unescape != NULL) { - ptrdiff_t name_len = unescape - dirname - 1; + ptrdiff_t name_len = unescape - dirnamestr - 1; name_len = MIN (name_len, LOGIN_NAME_MAX - 1); - char *p = mempcpy (user_name, dirname + 1, name_len); + char *p = mempcpy (user_name, dirnamestr + 1, name_len); char *q = unescape; while (*q != '\0') { @@ -821,9 +800,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } else { - ptrdiff_t name_len = end_name - dirname; + ptrdiff_t name_len = end_name - dirnamestr; name_len = MIN (name_len, LOGIN_NAME_MAX - 1); - *((char *) mempcpy (user_name, dirname + 1, name_len)) + *((char *) mempcpy (user_name, dirnamestr + 1, name_len)) = '\0'; } } @@ -860,32 +839,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* If we found a home directory use this. */ if (p != NULL) { - size_t home_len = strlen (p->pw_dir); - size_t rest_len = end_name == NULL ? 0 : strlen (end_name); - - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - malloc_dirname = 0; - - if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) - dirname = alloca_account (home_len + rest_len + 1, - alloca_used); - else + if (!char_array_set_str (&dirname, p->pw_dir)) { - dirname = malloc (home_len + rest_len + 1); - if (dirname == NULL) - { - scratch_buffer_free (&pwtmpbuf); - retval = GLOB_NOSPACE; - goto out; - } - malloc_dirname = 1; + scratch_buffer_free (&pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; } - *((char *) mempcpy (mempcpy (dirname, p->pw_dir, home_len), - end_name, rest_len)) = '\0'; - dirlen = home_len + rest_len; - dirname_modified = 1; + dirlen = strlen (p->pw_dir); + dirname_modified = true; } else { @@ -913,9 +875,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Return the directory if we don't check for error or if it exists. */ if ((flags & GLOB_NOCHECK) || (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) - ? ((*pglob->gl_lstat) (dirname, &st) == 0 + ? ((*pglob->gl_lstat) (char_array_str (&dirname), &st) == 0 && S_ISDIR (st.st_mode)) - : (__lstat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode))))) + : (__lstat64 (char_array_str (&dirname), &st64) == 0 + && S_ISDIR (st64.st_mode))))) { size_t newcount = pglob->gl_pathc + pglob->gl_offs; char **new_gl_pathv; @@ -926,8 +889,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), free (pglob->gl_pathv); pglob->gl_pathv = NULL; pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } new_gl_pathv = realloc (pglob->gl_pathv, @@ -942,28 +904,23 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), pglob->gl_pathv[newcount] = malloc (dirlen + 2); if (pglob->gl_pathv[newcount] == NULL) goto nospace; - p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); + p = mempcpy (pglob->gl_pathv[newcount], + char_array_str (&dirname), dirlen); p[0] = '/'; p[1] = '\0'; - if (__glibc_unlikely (malloc_dirname)) - free (dirname); } else { - if (__glibc_unlikely (malloc_dirname)) - pglob->gl_pathv[newcount] = dirname; - else - { - pglob->gl_pathv[newcount] = strdup (dirname); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; - } + pglob->gl_pathv[newcount] = strdup (char_array_str (&dirname)); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; } pglob->gl_pathv[++newcount] = NULL; ++pglob->gl_pathc; pglob->gl_flags = flags; - return 0; + retval = 0; + goto out; } /* Not found. */ @@ -971,7 +928,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), goto out; } - meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); + meta = __glob_pattern_type (char_array_str (&dirname), + !(flags & GLOB_NOESCAPE)); /* meta is 1 if correct glob pattern containing metacharacters. If meta has bit (1 << 2) set, it means there was an unterminated [ which we handle the same, using fnmatch. Broken unterminated @@ -984,15 +942,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), the pattern in each directory found. */ size_t i; - if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\') + if (!(flags & GLOB_NOESCAPE) && dirlen > 0 + && char_array_pos (&dirname, dirlen - 1) == '\\') { /* "foo\\/bar". Remove the final backslash from dirname if it has not been quoted. */ - char *p = (char *) &dirname[dirlen - 1]; - - while (p > dirname && p[-1] == '\\') --p; - if ((&dirname[dirlen] - p) & 1) - *(char *) &dirname[--dirlen] = '\0'; + size_t p = dirlen - 1; + while (p > 0 && char_array_pos (&dirname, p - 1) == '\\') --p; + if ((dirlen - p) & 1) + char_array_crop (&dirname, --dirlen); } if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0)) @@ -1006,7 +964,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirs.gl_lstat = pglob->gl_lstat; } - status = glob (dirname, + status = glob (char_array_str (&dirname), ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) | GLOB_NOSORT | GLOB_ONLYDIR), @@ -1068,8 +1026,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } } @@ -1091,8 +1048,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { nospace2: globfree (&dirs); - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } new_gl_pathv = realloc (pglob->gl_pathv, @@ -1107,8 +1063,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } ++pglob->gl_pathc; @@ -1134,7 +1089,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (meta & 2) { - char *p = strchr (dirname, '\\'), *q; + char *p = strchr (char_array_str (&dirname), '\\'), *q; /* We need to unescape the dirname string. It is certainly allocated by alloca, as otherwise filename would be NULL or dirname wouldn't contain backslashes. */ @@ -1151,12 +1106,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), ++q; } while (*p++ != '\0'); - dirname_modified = 1; + dirname_modified = true; } if (dirname_modified) flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); - status = glob_in_dir (filename, dirname, flags, errfunc, pglob, - alloca_used); + status = glob_in_dir (filename, char_array_str (&dirname), flags, + errfunc, pglob, alloca_used); if (status != 0) { if (status == GLOB_NOMATCH && flags != orig_flags @@ -1174,14 +1129,13 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (dirlen > 0) { /* Stick the directory on the front of each name. */ - if (prefix_array (dirname, + if (prefix_array (char_array_str (&dirname), &pglob->gl_pathv[old_pathc + pglob->gl_offs], pglob->gl_pathc - old_pathc)) { globfree (pglob); pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } } } @@ -1206,8 +1160,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { globfree (pglob); pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; + goto err_nospace; } strcpy (&new[len - 2], "/"); pglob->gl_pathv[i] = new; @@ -1223,10 +1176,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } out: - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - + char_array_free (&dirname); return retval; + + err_nospace: + char_array_free (&dirname); + return GLOB_NOSPACE; } #if defined _LIBC && !defined glob libc_hidden_def (glob)