From patchwork Tue Feb 2 13:08:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41894 X-Patchwork-Delegate: azanella@linux.vnet.ibm.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EDB7E3987C11; Tue, 2 Feb 2021 13:08:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org EDB7E3987C11 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1612271293; bh=aSH7KU9NurB3ny6Oq7RRks+FEPeUlZxtEgvPAbXSXII=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=F6zffjuxs8q2yFDnCJdeBGpHepVYXbPDoRIdUQrzyuExEA3sZHhES3CBQIUpEirxo zVQfZUmm2o3sZUa33JrOKTdlpv+JpZymzTV7cyahZhS7fc8Z+Y1w9TqQH5U9mC4lUA uGgFTyqI7dCSz23VAs7NNrQS0BXkfCRPwFdFfJBY= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf34.google.com (mail-qv1-xf34.google.com [IPv6:2607:f8b0:4864:20::f34]) by sourceware.org (Postfix) with ESMTPS id 2DA92385801A for ; Tue, 2 Feb 2021 13:08:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 2DA92385801A Received: by mail-qv1-xf34.google.com with SMTP id r13so5400071qvm.11 for ; Tue, 02 Feb 2021 05:08:10 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=aSH7KU9NurB3ny6Oq7RRks+FEPeUlZxtEgvPAbXSXII=; b=m7gb4ZlYWriR06z1338RaY388agAj1PLuW0T5vr6BSGVUG914AqBWJoZdZH18gnE+K 4ALd8JvOP/ZG8iRSLrBjFlaSsuYqfzNlHKrOEe0z18pKwRzd/u6lLtZWoXsST4xxM3Ln P2U56yVb1tNMO7cPmutbgVLJk6LmSboOalWco/5dOKe2s8v3t8zJjhADVXa0Bt3lOM7I ZKiZIBRE2M2WyXiLaTkDip3MMFSYKAez2dOcu2lPza9dZogh7gF6538ZwIlfcHJTX/1v QGGhFXq4DnVTc5JK6M0GZVxEnrdY4YGwy5rMmkSPTuODVnAdOt0yVh2wVhVyuT/uE6SL CGMA== X-Gm-Message-State: AOAM531iGEcoFrnGSm6vmqnmLGYyVvcUHCV7MnAdkXzbioP3ncij3ySx h0v54aYNO4/4E+sQ/QrVldGsCjznmPHacg== X-Google-Smtp-Source: ABdhPJwqGaOFivYQj5Phf3pKf/iCuDgnheRIm3A25ohekOuPJkMBGa4k9Jpv6O7z4aiywl8KVG0TvA== X-Received: by 2002:a05:6214:14e2:: with SMTP id k2mr19946893qvw.24.1612271289435; Tue, 02 Feb 2021 05:08:09 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id h63sm15305510qtd.14.2021.02.02.05.08.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Feb 2021 05:08:08 -0800 (PST) To: libc-alpha@sourceware.org Subject: [PATCH 1/2] posix: Falling back to non wide mode in case of encoding error [BZ #14185] Date: Tue, 2 Feb 2021 10:08:03 -0300 Message-Id: <20210202130804.1920933-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Gnulib has added the proposed fix with aed23714d60 (done in 2005), but recently with a glibc merge with 67306f6 (done in 2020 with sync back) it has fallback to old semantic to return -1 on in case of failure. From gnulib developer feedback it was an oversight. Although the full fix for BZ #14185 would require to rewrite fnmatch implementation to use mbrtowc instead of mbsrtowcs on the full input, this mitigate the issue and it has been used by gnulib for a long time. This patch also removes the alloca usage on the string convertion to wide characters before calling the internal function. Checked on x86_64-linux-gnu. --- posix/fnmatch.c | 160 ++++++++++++++-------------------------- posix/tst-fnmatch.input | 2 + 2 files changed, 58 insertions(+), 104 deletions(-) diff --git a/posix/fnmatch.c b/posix/fnmatch.c index b8a71f164d..a66c9196c7 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -75,6 +75,7 @@ extern int fnmatch (const char *pattern, const char *string, int flags); #include #include +#include #ifdef _LIBC typedef ptrdiff_t idx_t; @@ -231,121 +232,72 @@ is_char_class (const wchar_t *wcs) #include "fnmatch_loop.c" +static int +fnmatch_convert_to_wide (const char *str, struct scratch_buffer *buf, + size_t *n) +{ + mbstate_t ps; + memset (&ps, '\0', sizeof (ps)); + + size_t nw = buf->length / sizeof (wchar_t); + *n = strnlen (str, nw - 1); + if (__glibc_likely (*n < nw)) + { + const char *p = str; + *n = mbsrtowcs (buf->data, &p, *n + 1, &ps); + if (__glibc_unlikely (*n == (size_t) -1)) + /* Something wrong. + XXX Do we have to set 'errno' to something which mbsrtows hasn't + already done? */ + return -1; + if (p == NULL) + return 0; + memset (&ps, '\0', sizeof (ps)); + } + + *n = mbsrtowcs (NULL, &str, 0, &ps); + if (__glibc_unlikely (*n == (size_t) -1)) + return -1; + if (!scratch_buffer_set_array_size (buf, *n + 1, sizeof (wchar_t))) + { + __set_errno (ENOMEM); + return -2; + } + assert (mbsinit (&ps)); + mbsrtowcs (buf->data, &str, *n + 1, &ps); + return 0; +} int fnmatch (const char *pattern, const char *string, int flags) { if (__glibc_unlikely (MB_CUR_MAX != 1)) { - mbstate_t ps; size_t n; - const char *p; - wchar_t *wpattern_malloc = NULL; - wchar_t *wpattern; - wchar_t *wstring_malloc = NULL; - wchar_t *wstring; - size_t alloca_used = 0; - - /* Convert the strings into wide characters. */ - memset (&ps, '\0', sizeof (ps)); - p = pattern; - n = strnlen (pattern, 1024); - if (__glibc_likely (n < 1024)) + struct scratch_buffer wpattern; + scratch_buffer_init (&wpattern); + struct scratch_buffer wstring; + scratch_buffer_init (&wstring); + int r; + + /* Convert the strings into wide characters. Any conversion issue + fallback to the ascii version. */ + r = fnmatch_convert_to_wide (pattern, &wpattern, &n); + if (r == 0) { - wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), - alloca_used); - n = mbsrtowcs (wpattern, &p, n + 1, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - /* Something wrong. - XXX Do we have to set 'errno' to something which mbsrtows hasn't - already done? */ - return -1; - if (p) - { - memset (&ps, '\0', sizeof (ps)); - goto prepare_wpattern; - } - } - else - { - prepare_wpattern: - n = mbsrtowcs (NULL, &pattern, 0, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - /* Something wrong. - XXX Do we have to set 'errno' to something which mbsrtows hasn't - already done? */ - return -1; - if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) - { - __set_errno (ENOMEM); - return -2; - } - wpattern_malloc = wpattern - = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); - assert (mbsinit (&ps)); - if (wpattern == NULL) - return -2; - (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); - } - - assert (mbsinit (&ps)); - n = strnlen (string, 1024); - p = string; - if (__glibc_likely (n < 1024)) - { - wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), - alloca_used); - n = mbsrtowcs (wstring, &p, n + 1, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - { - /* Something wrong. - XXX Do we have to set 'errno' to something which - mbsrtows hasn't already done? */ - free_return: - free (wpattern_malloc); - return -1; - } - if (p) - { - memset (&ps, '\0', sizeof (ps)); - goto prepare_wstring; - } - } - else - { - prepare_wstring: - n = mbsrtowcs (NULL, &string, 0, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - /* Something wrong. - XXX Do we have to set 'errno' to something which mbsrtows hasn't - already done? */ - goto free_return; - if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) - { - free (wpattern_malloc); - __set_errno (ENOMEM); - return -2; - } - - wstring_malloc = wstring - = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); - if (wstring == NULL) - { - free (wpattern_malloc); - return -2; - } - assert (mbsinit (&ps)); - (void) mbsrtowcs (wstring, &string, n + 1, &ps); - } - - int res = internal_fnwmatch (wpattern, wstring, wstring + n, + r = fnmatch_convert_to_wide (string, &wstring, &n); + if (r == 0) + r = internal_fnwmatch (wpattern.data, wstring.data, + (wchar_t *) wstring.data + n, flags & FNM_PERIOD, flags, NULL, - alloca_used); + false); + } - free (wstring_malloc); - free (wpattern_malloc); + scratch_buffer_free (&wstring); + scratch_buffer_free (&wpattern); - return res; + if (r == -2 || r == 0) + return r; } return internal_fnmatch (pattern, string, string + strlen (string), diff --git a/posix/tst-fnmatch.input b/posix/tst-fnmatch.input index 4fef4ee829..67aac5aada 100644 --- a/posix/tst-fnmatch.input +++ b/posix/tst-fnmatch.input @@ -676,6 +676,8 @@ C "x" "*" 0 PATHNAME|LEADING_DIR C "x/y" "*" 0 PATHNAME|LEADING_DIR C "x/y/z" "*" 0 PATHNAME|LEADING_DIR C "x" "*x" 0 PATHNAME|LEADING_DIR + +en_US.UTF-8 "\366.csv" "*.csv" 0 C "x/y" "*x" 0 PATHNAME|LEADING_DIR C "x/y/z" "*x" 0 PATHNAME|LEADING_DIR C "x" "x*" 0 PATHNAME|LEADING_DIR From patchwork Tue Feb 2 13:08:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41895 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7DBA83987C0F; Tue, 2 Feb 2021 13:08:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7DBA83987C0F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1612271295; bh=BSYQjdUuOs1GyXD5uGkuNF6YjtG+idMWbyNHOVNxzoo=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=tJjejunA99R1jN3qsDdtMzkmPcvf4htpyS13Sop3HP9YckJ54rHxHkNwkEbYiOb/R KEeO2Lgsg5HoZuFMTsT2EwpjGBgnsjGf2JDWq5qjhRWx/9RwQhYA6qmLKN170mBNet EwzLbxGoH6BTm5qRRfcxLb3089ngjzIgko6wDReY= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x72a.google.com (mail-qk1-x72a.google.com [IPv6:2607:f8b0:4864:20::72a]) by sourceware.org (Postfix) with ESMTPS id 26BB5385801A for ; Tue, 2 Feb 2021 13:08:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 26BB5385801A Received: by mail-qk1-x72a.google.com with SMTP id x81so19661330qkb.0 for ; Tue, 02 Feb 2021 05:08:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BSYQjdUuOs1GyXD5uGkuNF6YjtG+idMWbyNHOVNxzoo=; b=S2J24u5dBQhumxfdutY/t4Sqf7JU9uMwGwAIJ9CrU+Bzb+Li0Z1CfeX0HLgEU1vTqR +IWGk+1nSqiXpgJJ472nifM03eCGW4fSrKS4S03d3f6uQM7yYcqIoxo68VJOwMmNMs8J 5q7ZOpBRX5nR9rCdEjZG//UBXJVqkU/pgMU0otL0EjaCKyXoRXaHDnY2zb+XL4Feee6N OgQYSJJrvKVuSArnI3huEQ/B3DjG/305yLbUIg6erzqNv5C/ck4wSGpS2ZJ8kAOW7JzW R+KMbNxUDSLOlOrzlfkZ4wZxjGj6Xz/1IKFtccsYC0e2RJA1TrjZn0KYW2Q1Wcuck5D2 EBXQ== X-Gm-Message-State: AOAM533Myp5wo+18JviSVXE3Ay3DFkKWljOOwlQqaCPgZdAG1YE+c8/X np7b3b/Qkc2VplQ1viMylqPKh+CoubIErQ== X-Google-Smtp-Source: ABdhPJyZu/C1b9ANsKvYRdhHfefO472axdQRtJ9BOu6yI9BIXQJIOqtXQ48TY5K25UVno+EPpyRKeA== X-Received: by 2002:a05:620a:1241:: with SMTP id a1mr21071158qkl.405.1612271291239; Tue, 02 Feb 2021 05:08:11 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id h63sm15305510qtd.14.2021.02.02.05.08.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Feb 2021 05:08:10 -0800 (PST) To: libc-alpha@sourceware.org Subject: [PATCH 2/2] posix: Remove alloca usage for internal fnmatch implementation Date: Tue, 2 Feb 2021 10:08:04 -0300 Message-Id: <20210202130804.1920933-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210202130804.1920933-1-adhemerval.zanella@linaro.org> References: <20210202130804.1920933-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" This patch replaces the internal fnmatch pattern list generation to use a dynamic array. Checked on x86_64-linux-gnu. --- posix/fnmatch.c | 24 +----- posix/fnmatch_loop.c | 190 +++++++++++++++++++------------------------ 2 files changed, 87 insertions(+), 127 deletions(-) diff --git a/posix/fnmatch.c b/posix/fnmatch.c index a66c9196c7..51080ab833 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -31,9 +31,6 @@ #include #include #include -#if defined _LIBC || HAVE_ALLOCA -# include -#endif #include #include #include @@ -87,22 +84,6 @@ typedef ptrdiff_t idx_t; #define NO_LEADING_PERIOD(flags) \ ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD)) -#ifndef _LIBC -# if HAVE_ALLOCA -/* The OS usually guarantees only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - allocate anything larger than 4096 bytes. Also care for the possibility - of a few compiler-allocated temporary stack slots. */ -# define __libc_use_alloca(n) ((n) < 4032) -# else -/* Just use malloc. */ -# define __libc_use_alloca(n) false -# undef alloca -# define alloca(n) malloc (n) -# endif -# define alloca_account(size, avar) ((avar) += (size), alloca (size)) -#endif - /* Provide support for user-defined character classes, based on the functions from ISO C 90 amendment 1. */ #ifdef CHARCLASS_NAME_MAX @@ -289,8 +270,7 @@ fnmatch (const char *pattern, const char *string, int flags) if (r == 0) r = internal_fnwmatch (wpattern.data, wstring.data, (wchar_t *) wstring.data + n, - flags & FNM_PERIOD, flags, NULL, - false); + flags & FNM_PERIOD, flags, NULL); } scratch_buffer_free (&wstring); @@ -301,7 +281,7 @@ fnmatch (const char *pattern, const char *string, int flags) } return internal_fnmatch (pattern, string, string + strlen (string), - flags & FNM_PERIOD, flags, NULL, 0); + flags & FNM_PERIOD, flags, NULL); } #undef fnmatch diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c index 7f938af590..69f78f0fd8 100644 --- a/posix/fnmatch_loop.c +++ b/posix/fnmatch_loop.c @@ -30,15 +30,14 @@ struct STRUCT it matches, nonzero if not. */ static int FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, bool no_leading_period, int flags, - struct STRUCT *ends, size_t alloca_used); + struct STRUCT *ends); static int EXT (INT opt, const CHAR *pattern, const CHAR *string, - const CHAR *string_end, bool no_leading_period, int flags, - size_t alloca_used); + const CHAR *string_end, bool no_leading_period, int flags); static const CHAR *END (const CHAR *patternp); static int FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, - bool no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used) + bool no_leading_period, int flags, struct STRUCT *ends) { const CHAR *p = pattern, *n = string; UCHAR c; @@ -62,8 +61,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, case L_('?'): if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') { - int res = EXT (c, p, n, string_end, no_leading_period, - flags, alloca_used); + int res = EXT (c, p, n, string_end, no_leading_period, flags); if (res != -1) return res; } @@ -92,8 +90,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, case L_('*'): if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') { - int res = EXT (c, p, n, string_end, no_leading_period, - flags, alloca_used); + int res = EXT (c, p, n, string_end, no_leading_period, flags); if (res != -1) return res; } @@ -182,7 +179,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, for (--p; n < endp; ++n, no_leading_period = false) if (FCT (p, n, string_end, no_leading_period, flags2, - &end, alloca_used) == 0) + &end) == 0) goto found; } else if (c == L_('/') && (flags & FNM_FILE_NAME)) @@ -191,7 +188,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, ++n; if (n < string_end && *n == L_('/') && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags, - NULL, alloca_used) == 0)) + NULL) == 0)) return 0; } else @@ -205,7 +202,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, for (--p; n < endp; ++n, no_leading_period = false) if (FOLD ((UCHAR) *n) == c && (FCT (p, n, string_end, no_leading_period, flags2, - &end, alloca_used) == 0)) + &end) == 0)) { found: if (end.pattern == NULL) @@ -892,8 +889,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, case L_('!'): if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') { - int res = EXT (c, p, n, string_end, no_leading_period, flags, - alloca_used); + int res = EXT (c, p, n, string_end, no_leading_period, flags); if (res != -1) return res; } @@ -972,26 +968,37 @@ END (const CHAR *pattern) return p + 1; } +#if WIDE_CHAR_VERSION +# define PATTERN_PREFIX pattern_list +#else +# define PATTERN_PREFIX wpattern_list +#endif + +#define PASTE(a,b) PASTE1(a,b) +#define PASTE1(a,b) a##b + +#define DYNARRAY_STRUCT PATTERN_PREFIX +#define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr) +#define DYNARRAY_ELEMENT CHAR * +#define DYNARRAY_PREFIX PASTE(PATTERN_PREFIX,_) +#define DYNARRAY_INITIAL_SIZE 8 +#include static int EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, - bool no_leading_period, int flags, size_t alloca_used) + bool no_leading_period, int flags) { const CHAR *startp; ptrdiff_t level; - struct patternlist - { - struct patternlist *next; - CHAR malloced; - CHAR str __flexarr; - } *list = NULL; - struct patternlist **lastp = &list; + struct PATTERN_PREFIX list; size_t pattern_len = STRLEN (pattern); - bool any_malloced = false; + size_t pattern_i = 0; const CHAR *p; const CHAR *rs; int retval = 0; + PASTE (PATTERN_PREFIX, _init) (&list); + /* Parse the pattern. Store the individual parts in the list. */ level = 0; for (startp = p = pattern + 1; level >= 0; ++p) @@ -1027,74 +1034,48 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, || *p == L_('!')) && p[1] == L_('(')) /* Remember the nesting level. */ ++level; - else if (*p == L_(')')) - { - if (level-- == 0) - { - /* This means we found the end of the pattern. */ -#define NEW_PATTERN \ - struct patternlist *newp; \ - size_t plen = (opt == L_('?') || opt == L_('@') \ - ? pattern_len : (p - startp + 1UL)); \ - idx_t slen = FLEXSIZEOF (struct patternlist, str, 0); \ - idx_t new_used = alloca_used + slen; \ - idx_t plensize; \ - if (INT_MULTIPLY_WRAPV (plen, sizeof (CHAR), &plensize) \ - || INT_ADD_WRAPV (new_used, plensize, &new_used)) \ - { \ - retval = -2; \ - goto out; \ - } \ - slen += plensize; \ - bool malloced = ! __libc_use_alloca (new_used); \ - if (__glibc_unlikely (malloced)) \ - { \ - newp = malloc (slen); \ - if (newp == NULL) \ - { \ - retval = -2; \ - goto out; \ - } \ - any_malloced = true; \ - } \ - else \ - newp = alloca_account (slen, alloca_used); \ - newp->next = NULL; \ - newp->malloced = malloced; \ - *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \ - *lastp = newp; \ - lastp = &newp->next - NEW_PATTERN; - } - } - else if (*p == L_('|')) + else if (*p == L_(')') || *p == L_('|')) { if (level == 0) { - NEW_PATTERN; - startp = p + 1; + size_t slen = opt == L_('?') || opt == L_('@') + ? pattern_len : p - startp + 1; + CHAR *newp = malloc (slen * sizeof (CHAR)); + if (newp != NULL) + { + *((CHAR *) MEMPCPY (newp, startp, p - startp)) = L_('\0'); + PASTE (PATTERN_PREFIX,_add) (&list, newp); + } + if (newp == NULL || PASTE (PATTERN_PREFIX, _has_failed) (&list)) + { + retval = -2; + goto out; + } + + if (*p == L_('|')) + startp = p + 1; } + if (*p == L_(')')) + level--; } - assert (list != NULL); assert (p[-1] == L_(')')); -#undef NEW_PATTERN switch (opt) { case L_('*'): - if (FCT (p, string, string_end, no_leading_period, flags, NULL, - alloca_used) == 0) + if (FCT (p, string, string_end, no_leading_period, flags, NULL) == 0) goto success; FALLTHROUGH; case L_('+'): - do + for (; pattern_i < PASTE (PATTERN_PREFIX, _size)(&list); pattern_i++) { for (rs = string; rs <= string_end; ++rs) /* First match the prefix with the current pattern with the current pattern. */ - if (FCT (list->str, string, rs, no_leading_period, + if (FCT (*PASTE (PATTERN_PREFIX, _at) (&list, pattern_i), string, + rs, no_leading_period, flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0 + NULL) == 0 /* This was successful. Now match the rest with the rest of the pattern. */ && (FCT (p, rs, string_end, @@ -1102,7 +1083,7 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, ? no_leading_period : rs[-1] == '/' && NO_LEADING_PERIOD (flags), flags & FNM_FILE_NAME - ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0 + ? flags : flags & ~FNM_PERIOD, NULL) == 0 /* This didn't work. Try the whole pattern. */ || (rs != string && FCT (pattern - 1, rs, string_end, @@ -1110,35 +1091,33 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, ? no_leading_period : rs[-1] == '/' && NO_LEADING_PERIOD (flags), flags & FNM_FILE_NAME - ? flags : flags & ~FNM_PERIOD, NULL, - alloca_used) == 0))) + ? flags : flags & ~FNM_PERIOD, NULL) == 0))) /* It worked. Signal success. */ goto success; } - while ((list = list->next) != NULL); /* None of the patterns lead to a match. */ retval = FNM_NOMATCH; break; case L_('?'): - if (FCT (p, string, string_end, no_leading_period, flags, NULL, - alloca_used) == 0) + if (FCT (p, string, string_end, no_leading_period, flags, NULL) == 0) goto success; FALLTHROUGH; case L_('@'): - do - /* I cannot believe it but 'strcat' is actually acceptable - here. Match the entire string with the prefix from the - pattern list and the rest of the pattern following the - pattern list. */ - if (FCT (STRCAT (list->str, p), string, string_end, - no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0) - /* It worked. Signal success. */ - goto success; - while ((list = list->next) != NULL); + for (; pattern_i < PASTE (PATTERN_PREFIX, _size) (&list); pattern_i++) + { + /* I cannot believe it but `strcat' is actually acceptable + here. Match the entire string with the prefix from the + pattern list and the rest of the pattern following the + pattern list. */ + if (FCT (STRCAT (*PASTE (PATTERN_PREFIX, _at) (&list, pattern_i), p), + string, string_end, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, + NULL) == 0) + /* It worked. Signal success. */ + goto success; + } /* None of the patterns lead to a match. */ retval = FNM_NOMATCH; @@ -1147,22 +1126,27 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, case L_('!'): for (rs = string; rs <= string_end; ++rs) { - struct patternlist *runp; + size_t runp_i; - for (runp = list; runp != NULL; runp = runp->next) - if (FCT (runp->str, string, rs, no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0) + for (runp_i = pattern_i; + runp_i != PASTE (PATTERN_PREFIX, _size) (&list); + runp_i++) + { + if (FCT (*PASTE (PATTERN_PREFIX, _at) (&list, runp_i), string, rs, + no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, + NULL) == 0) break; + } /* If none of the patterns matched see whether the rest does. */ - if (runp == NULL + if (runp_i == PASTE (PATTERN_PREFIX, _size) (&list) && (FCT (p, rs, string_end, rs == string ? no_leading_period : rs[-1] == '/' && NO_LEADING_PERIOD (flags), flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0)) + NULL) == 0)) /* This is successful. */ goto success; } @@ -1180,18 +1164,14 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, success: out: - if (any_malloced) - while (list != NULL) - { - struct patternlist *old = list; - list = list->next; - if (old->malloced) - free (old); - } + PASTE (PATTERN_PREFIX, _free) (&list); return retval; } +#undef PATTERN_PREFIX +#undef PASTE +#undef PASTE1 #undef FOLD #undef CHAR