From patchwork Thu Dec 24 15:16:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41548 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 35F85383509B; Thu, 24 Dec 2020 15:17:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 35F85383509B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1608823034; bh=/K7wsxpwZS7bnrIOeM2TzARc+mP/c/dVbncSy9CUxzE=; 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=Lo6RIcs9VJI35yU8R+ULphSMX0mpyY3MPMXzxgmQfr9smUChNKgT6F4Z8Kg2LPayi AWW/iSHul4ElJr17mprsH8TaSn0K4/iw0hpgvWFNQqG430Hyl+3gjjgUp4y/xOhT2s BNBloDJ0EmV5kv7/QYyZcI4qX2YrXMkuR3PP4tJY= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x829.google.com (mail-qt1-x829.google.com [IPv6:2607:f8b0:4864:20::829]) by sourceware.org (Postfix) with ESMTPS id 055983851C0D for ; Thu, 24 Dec 2020 15:17:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 055983851C0D Received: by mail-qt1-x829.google.com with SMTP id y15so1632681qtv.5 for ; Thu, 24 Dec 2020 07:17: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:in-reply-to :references:mime-version:content-transfer-encoding; bh=/K7wsxpwZS7bnrIOeM2TzARc+mP/c/dVbncSy9CUxzE=; b=kmdhhVBBSWfWJquny1Md/8zyXcn5J4XIKr2qAxko7Ix37MRBlzng/U++Kgwi3DSfSR Db3fnZwITSG+DDn1cNTa2iyG/oGNJVDWW/G9ga5MkgsAvPG9j1fj6f0P/8x1hMHWBa8m qjmO+W5vxmPrZoL29fIoBSmeWMnkl3VyL2vYT8TzWNDrNrUGmLMNIMrnHhzSEDHDE5ch gnPldZo0XbytSNf/6/Hgp/iXJcNCqalD24qnSHzMnaaXzUELmpwzTSRHDkamSNb7U4sW TUFffEtEYW9ZeYbmnChi+eL3ulCIjU1ma8Ig4bIyBC2Zcb7kFT8+14suNmbZXeCMs8fl rWFw== X-Gm-Message-State: AOAM530yU3XkCAGxNcBBKrMuyJYPQVrWv9B2mvRQWw/+cYDamvupEca9 8kT3KJAU1V4SKUH0rsk7PILxMrnLfEOddQ== X-Google-Smtp-Source: ABdhPJx+7HoryiU8NE8mkYLdRmeudXkH5xbIPCIQIgKnoGm/AF2bJJ2lsoYKyvTJfuRFFW4o9gZNDw== X-Received: by 2002:a05:622a:28b:: with SMTP id z11mr30797829qtw.94.1608823029027; Thu, 24 Dec 2020 07:17:09 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id h21sm17039460qkk.5.2020.12.24.07.17.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Dec 2020 07:17:08 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 1/5] stdlib: Sync canonicalize with gnulib [BZ #10635] [BZ #26592] [BZ #26241] Date: Thu, 24 Dec 2020 12:16:57 -0300 Message-Id: <20201224151701.1751008-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> References: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, 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" It sync with gnulib version d9c121346 with the following difference require fix a glibc build: --- ../../gnulib/gnulib-lib/lib/canonicalize-lgpl.c +++ stdlib/canonicalize.c @@ -46,7 +46,7 @@ # define FILE_SYSTEM_PREFIX_LEN(name) 0 # define IS_ABSOLUTE_FILE_NAME(name) ISSLASH(*(name)) # define ISSLASH(c) ((c) == '/') -# define freea(p) ((void) (p)) +# define FUNC_REALPATH_WORKS 1 #else # define __canonicalize_file_name canonicalize_file_name # define __realpath realpath @@ -270,7 +270,7 @@ buf[n] = '\0'; char *extra_buf = extra_buffer.data; - idx_t end_idx; + idx_t end_idx = 0; if (end_in_extra_buffer) end_idx = end - extra_buf; idx_t len = strlen (end); It shows the following testcase failures: FAIL: stdlib/test-canon azanella@birita:~/Projects/glibc/build/x86_64-linux-gnu$ cat stdlib/test-canon.out stdlib/test-canon: flunked test 30 (expected resolved `./doesExist/someFile', got `[builddir]/stdlib/doesExist/someFile/') stdlib/test-canon: flunked test 31 (expected `NULL', got `[builddir]/stdlib/doesExist') 2 errors. (the [builddir] the build directory I used) This regression will be fixed in the last commit of this set. The sync also fixes BZ#26592 and BZ#26241. --- stdlib/canonicalize.c | 456 +++++++++++++++++++++++++++--------------- 1 file changed, 297 insertions(+), 159 deletions(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 3fcb399a5d..66685f4526 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -16,43 +16,126 @@ License along with the GNU C Library; if not, see . */ -#include +#ifndef _LIBC +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the name == NULL test below. */ +# define _GL_ARG_NONNULL(params) + +# define _GL_USE_STDLIB_ALLOC 1 +# include +#endif + +/* Specification. */ #include -#include -#include -#include -#include + #include +#include +#include #include +#include +#include +#include + +#include + +#ifdef _LIBC +# include +# include +typedef ptrdiff_t idx_t; +# define IDX_MAX PTRDIFF_MAX +# define FILE_SYSTEM_PREFIX_LEN(name) 0 +# define IS_ABSOLUTE_FILE_NAME(name) ISSLASH(*(name)) +# define ISSLASH(c) ((c) == '/') +# define FUNC_REALPATH_WORKS 1 +#else +# define __canonicalize_file_name canonicalize_file_name +# define __realpath realpath +# include "idx.h" +# include "pathmax.h" +# include "filename.h" +# if defined _WIN32 && !defined __CYGWIN__ +# define __getcwd _getcwd +# elif HAVE_GETCWD +# if IN_RELOCWRAPPER + /* When building the relocatable program wrapper, use the system's getcwd + function, not the gnulib override, otherwise we would get a link error. + */ +# undef getcwd +# endif +# if defined VMS && !defined getcwd + /* We want the directory in Unix syntax, not in VMS syntax. + The gnulib override of 'getcwd' takes 2 arguments; the original VMS + 'getcwd' takes 3 arguments. */ +# define __getcwd(buf, max) getcwd (buf, max, 0) +# else +# define __getcwd getcwd +# endif +# else +# define __getcwd(buf, max) getwd (buf) +# endif +# define __mempcpy mempcpy +# define __pathconf pathconf +# define __rawmemchr rawmemchr +# define __readlink readlink +# ifndef MAXSYMLINKS +# ifdef SYMLOOP_MAX +# define MAXSYMLINKS SYMLOOP_MAX +# else +# define MAXSYMLINKS 20 +# endif +# endif +# define __eloop_threshold() MAXSYMLINKS +#endif + +#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +#endif + +#if !FUNC_REALPATH_WORKS || defined _LIBC -#include -#include +static idx_t +get_path_max (void) +{ +# ifdef PATH_MAX + long int path_max = PATH_MAX; +# else + /* The caller invoked realpath with a null RESOLVED, even though + PATH_MAX is not defined as a constant. The glibc manual says + programs should not do this, and POSIX says the behavior is undefined. + Historically, glibc here used the result of pathconf, or 1024 if that + failed; stay consistent with this (dubious) historical practice. */ + int err = errno; + long int path_max = __pathconf ("/", _PC_PATH_MAX); + __set_errno (err); +# endif + return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX; +} /* Return the canonical absolute name of file NAME. A canonical name - does not contain any `.', `..' components nor any repeated path - separators ('/') or symlinks. All path components must exist. If + does not contain any ".", ".." components nor any repeated file name + separators ('/') or symlinks. All file name components must exist. If RESOLVED is null, the result is malloc'd; otherwise, if the - canonical name is PATH_MAX chars or more, returns null with `errno' + canonical name is PATH_MAX chars or more, returns null with 'errno' set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the name in RESOLVED. If the name cannot be resolved and - RESOLVED is non-NULL, it contains the path of the first component - that cannot be resolved. If the path can be resolved, RESOLVED + RESOLVED is non-NULL, it contains the name of the first component + that cannot be resolved. If the name can be resolved, RESOLVED holds the same value as the value returned. */ char * __realpath (const char *name, char *resolved) { - char *rpath, *dest, *extra_buf = NULL; - const char *start, *end, *rpath_limit; - long int path_max; + char *dest; + char const *start; + char const *end; int num_links = 0; if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if - either parameter is a null pointer. We extend this to allow - the RESOLVED parameter to be NULL in case the we are expected to - allocate the room for the return value. */ + either parameter is a null pointer. We extend this to allow + the RESOLVED parameter to be NULL in case the we are expected to + allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } @@ -60,166 +143,221 @@ __realpath (const char *name, char *resolved) if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if - the name argument points to an empty string. */ + the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } -#ifdef PATH_MAX - path_max = PATH_MAX; -#else - path_max = __pathconf (name, _PC_PATH_MAX); - if (path_max <= 0) - path_max = 1024; -#endif - - if (resolved == NULL) - { - rpath = malloc (path_max); - if (rpath == NULL) - return NULL; - } - else - rpath = resolved; - rpath_limit = rpath + path_max; - - if (name[0] != '/') + struct scratch_buffer extra_buffer, link_buffer; + struct scratch_buffer rname_buffer; + struct scratch_buffer *rname_buf = &rname_buffer; + scratch_buffer_init (&extra_buffer); + scratch_buffer_init (&link_buffer); + scratch_buffer_init (rname_buf); + char *rname_on_stack = rname_buf->data; + char *rname = rname_on_stack; + bool end_in_extra_buffer = false; + bool failed = true; + + /* This is always zero for Posix hosts, but can be 2 for MS-Windows + and MS-DOS X:/foo/bar file names. */ + idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name); + + if (!IS_ABSOLUTE_FILE_NAME (name)) { - if (!__getcwd (rpath, path_max)) - { - rpath[0] = '\0'; - goto error; - } - dest = __rawmemchr (rpath, '\0'); + while (!__getcwd (rname, rname_buf->length)) + { + if (errno != ERANGE) + { + dest = rname; + goto error; + } + if (!scratch_buffer_grow (rname_buf)) + goto error_nomem; + rname = rname_buf->data; + } + dest = __rawmemchr (rname, '\0'); + start = name; + prefix_len = FILE_SYSTEM_PREFIX_LEN (rname); } else { - rpath[0] = '/'; - dest = rpath + 1; + dest = __mempcpy (rname, name, prefix_len); + *dest++ = '/'; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT) + { + if (prefix_len == 0 /* implies ISSLASH (name[0]) */ + && ISSLASH (name[1]) && !ISSLASH (name[2])) + *dest++ = '/'; + *dest = '\0'; + } + start = name + prefix_len; } - for (start = end = name; *start; start = end) + for ( ; *start; start = end) { - struct stat64 st; - int n; - - /* Skip sequence of multiple path-separators. */ - while (*start == '/') - ++start; - - /* Find end of path component. */ - for (end = start; *end && *end != '/'; ++end) - /* Nothing. */; - - if (end - start == 0) - break; - else if (end - start == 1 && start[0] == '.') - /* nothing */; - else if (end - start == 2 && start[0] == '.' && start[1] == '.') - { - /* Back up to previous component, ignore if at root already. */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - } + /* Skip sequence of multiple file name separators. */ + while (ISSLASH (*start)) + ++start; + + /* Find end of component. */ + for (end = start; *end && !ISSLASH (*end); ++end) + /* Nothing. */; + + /* Length of this file name component; it can be zero if a file + name ends in '/'. */ + idx_t startlen = end - start; + + if (startlen == 1 && start[0] == '.') + /* nothing */; + else if (startlen == 2 && start[0] == '.' && start[1] == '.') + { + /* Back up to previous component, ignore if at root already. */ + if (dest > rname + prefix_len + 1) + for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest) + continue; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT + && dest == rname + 1 && !prefix_len + && ISSLASH (*dest) && !ISSLASH (dest[1])) + dest++; + } else - { - size_t new_size; - - if (dest[-1] != '/') - *dest++ = '/'; - - if (dest + (end - start) >= rpath_limit) - { - ptrdiff_t dest_offset = dest - rpath; - char *new_rpath; - - if (resolved) - { - __set_errno (ENAMETOOLONG); - if (dest > rpath + 1) - dest--; - *dest = '\0'; - goto error; - } - new_size = rpath_limit - rpath; - if (end - start + 1 > path_max) - new_size += end - start + 1; - else - new_size += path_max; - new_rpath = (char *) realloc (rpath, new_size); - if (new_rpath == NULL) - goto error; - rpath = new_rpath; - rpath_limit = rpath + new_size; - - dest = rpath + dest_offset; - } - - dest = __mempcpy (dest, start, end - start); - *dest = '\0'; - - if (__lstat64 (rpath, &st) < 0) - goto error; - - if (S_ISLNK (st.st_mode)) - { - char *buf = __alloca (path_max); - size_t len; - - if (++num_links > __eloop_threshold ()) - { - __set_errno (ELOOP); - goto error; - } - - n = __readlink (rpath, buf, path_max - 1); - if (n < 0) - goto error; - buf[n] = '\0'; - - if (!extra_buf) - extra_buf = __alloca (path_max); - - len = strlen (end); - if (path_max - n <= len) - { - __set_errno (ENAMETOOLONG); - goto error; - } - - /* Careful here, end may be a pointer into extra_buf... */ - memmove (&extra_buf[n], end, len + 1); - name = end = memcpy (extra_buf, buf, n); - - if (buf[0] == '/') - dest = rpath + 1; /* It's an absolute symlink */ - else - /* Back up to previous component, ignore if at root already: */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - } - else if (!S_ISDIR (st.st_mode) && *end != '\0') - { - __set_errno (ENOTDIR); - goto error; - } - } + { + if (!ISSLASH (dest[-1])) + *dest++ = '/'; + + while (rname + rname_buf->length - dest <= startlen) + { + idx_t dest_offset = dest - rname; + if (!scratch_buffer_grow_preserve (rname_buf)) + goto error_nomem; + rname = rname_buf->data; + dest = rname + dest_offset; + } + + dest = __mempcpy (dest, start, startlen); + *dest = '\0'; + + /* If STARTLEN == 0, RNAME ends in '/'; use stat rather than + readlink, because readlink might fail with EINVAL without + checking whether RNAME sans '/' is valid. */ + struct stat st; + char *buf = NULL; + ssize_t n; + if (startlen != 0) + { + while (true) + { + buf = link_buffer.data; + idx_t bufsize = link_buffer.length; + n = __readlink (rname, buf, bufsize - 1); + if (n < bufsize - 1) + break; + if (!scratch_buffer_grow (&link_buffer)) + goto error_nomem; + } + if (n < 0) + buf = NULL; + } + if (buf) + { + if (++num_links > __eloop_threshold ()) + { + __set_errno (ELOOP); + goto error; + } + + buf[n] = '\0'; + + char *extra_buf = extra_buffer.data; + idx_t end_idx = 0; + if (end_in_extra_buffer) + end_idx = end - extra_buf; + idx_t len = strlen (end); + while (extra_buffer.length <= len + n) + { + if (!scratch_buffer_grow_preserve (&extra_buffer)) + goto error_nomem; + extra_buf = extra_buffer.data; + } + if (end_in_extra_buffer) + end = extra_buf + end_idx; + + /* Careful here, end may be a pointer into extra_buf... */ + memmove (&extra_buf[n], end, len + 1); + name = end = memcpy (extra_buf, buf, n); + end_in_extra_buffer = true; + + if (IS_ABSOLUTE_FILE_NAME (buf)) + { + idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); + + dest = __mempcpy (rname, buf, pfxlen); + *dest++ = '/'; /* It's an absolute symlink */ + if (DOUBLE_SLASH_IS_DISTINCT_ROOT) + { + if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen) + *dest++ = '/'; + *dest = '\0'; + } + /* Install the new prefix to be in effect hereafter. */ + prefix_len = pfxlen; + } + else + { + /* Back up to previous component, ignore if at root + already: */ + if (dest > rname + prefix_len + 1) + for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest) + continue; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 + && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) + dest++; + } + } + else if (! (startlen == 0 + ? stat (rname, &st) == 0 || errno == EOVERFLOW + : errno == EINVAL)) + goto error; + } } - if (dest > rpath + 1 && dest[-1] == '/') + if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1])) --dest; - *dest = '\0'; - - assert (resolved == NULL || resolved == rpath); - return rpath; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len + && ISSLASH (*dest) && !ISSLASH (dest[1])) + dest++; + failed = false; error: - assert (resolved == NULL || resolved == rpath); - if (resolved == NULL) - free (rpath); - return NULL; + *dest++ = '\0'; + if (resolved != NULL && dest - rname <= get_path_max ()) + rname = strcpy (resolved, rname); + +error_nomem: + scratch_buffer_free (&extra_buffer); + scratch_buffer_free (&link_buffer); + if (failed || rname == resolved) + scratch_buffer_free (rname_buf); + + if (failed) + return NULL; + + if (rname == resolved) + return rname; + idx_t rname_size = dest - rname; + if (rname == rname_on_stack) + { + rname = malloc (rname_size); + if (rname == NULL) + return NULL; + return memcpy (rname, rname_on_stack, rname_size); + } + char *result = realloc (rname, rname_size); + return result != NULL ? result : rname; } libc_hidden_def (__realpath) versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); +#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */ #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3) From patchwork Thu Dec 24 15:16:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41550 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 261973887021; Thu, 24 Dec 2020 15:17:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 261973887021 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1608823036; bh=KJjTB7EeNzubWpToFUrRr5MRnklVRU0WZB1RiZRlwWs=; 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=OHm4XOO6CsfDHH+EA4msWZOR+bC/xH7DyJVBgmp0LIUOkebVkRwAS0NVF9uIBuSR4 tjqVWB/m5MgJesvYXmq0Mx3U0eSsV1XRuz7siWTAtwxfUvK77mUfrPCf+d6+qFWAln VS02gOPaO0rYLuznuj3O9S3ljJrOXJu1PWPmOKTM= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf2e.google.com (mail-qv1-xf2e.google.com [IPv6:2607:f8b0:4864:20::f2e]) by sourceware.org (Postfix) with ESMTPS id F174E3851C0D for ; Thu, 24 Dec 2020 15:17:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org F174E3851C0D Received: by mail-qv1-xf2e.google.com with SMTP id et9so1281378qvb.10 for ; Thu, 24 Dec 2020 07:17: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=KJjTB7EeNzubWpToFUrRr5MRnklVRU0WZB1RiZRlwWs=; b=RVTDB5de2YG9W1Aq2W2POaed7Fxtf46KVPvcriIip4HOoMtyFICv+nOqVo0sf+uLsW tLuHoNi2OTOauTlCflzMXFVbU5qpHuyXT1fDX/41lKe9GLa/ZhHAY6jg76NtLq4LLmak /3UQmjOBkxKfxtmGjxqaZXdngLx+eKQh+I8nMTf4yyqvDSYh15PAcxFiCCGsYhH0GaU+ 44/nxwUPlTwuV26PaYuEvBnD0YREmwbyJjlKZWKNcJHiRrpIK4nEGYcFjSeYTYFkwuB8 N1Y5/0khCkVbUHEqtAZiSapTbX8R7b4mjVQ2SbqVIZZpPWG1PSPWTMEhS1GlHshIqLRB OQYw== X-Gm-Message-State: AOAM531n2HHVr9TyTsfkhjGHr4Uzzrq58Uth7P8AZ9/bpqxgejEtR/sq W8X/NktsPyDUbKeLvuVPLQ2S11MCuluOCQ== X-Google-Smtp-Source: ABdhPJxnu9z9j0bLth8nBD3PAAu3Rm8Ca5UKYoNajWFYiZy2GMQy3iWzf7lN/dBCAJFWhaQYNXQZCg== X-Received: by 2002:ad4:4426:: with SMTP id e6mr32435334qvt.51.1608823032369; Thu, 24 Dec 2020 07:17:12 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id h21sm17039460qkk.5.2020.12.24.07.17.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Dec 2020 07:17:11 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 3/5] Import filename.h from gnulib Date: Thu, 24 Dec 2020 12:16:59 -0300 Message-Id: <20201224151701.1751008-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> References: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, 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" And use to simplify stdlib/canonicalize.c implementation. --- include/filename.h | 110 ++++++++++++++++++++++++++++++++++++++++++ stdlib/canonicalize.c | 5 +- 2 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 include/filename.h diff --git a/include/filename.h b/include/filename.h new file mode 100644 index 0000000000..4598fb1d63 --- /dev/null +++ b/include/filename.h @@ -0,0 +1,110 @@ +/* Basic filename support macros. + Copyright (C) 2001-2004, 2007-2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* From Paul Eggert and Jim Meyering. */ + +#ifndef _FILENAME_H +#define _FILENAME_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Filename support. + ISSLASH(C) tests whether C is a directory separator + character. + HAS_DEVICE(Filename) tests whether Filename contains a device + specification. + FILE_SYSTEM_PREFIX_LEN(Filename) length of the device specification + at the beginning of Filename, + index of the part consisting of + alternating components and slashes. + FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE + 1 when a non-empty device specification + can be followed by an empty or relative + part, + 0 when a non-empty device specification + must be followed by a slash, + 0 when device specification don't exist. + IS_ABSOLUTE_FILE_NAME(Filename) + tests whether Filename is independent of + any notion of "current directory". + IS_RELATIVE_FILE_NAME(Filename) + tests whether Filename may be concatenated + to a directory filename. + Note: On native Windows, OS/2, DOS, "c:" is neither an absolute nor a + relative file name! + IS_FILE_NAME_WITH_DIR(Filename) tests whether Filename contains a device + or directory specification. + */ +#if defined _WIN32 || defined __CYGWIN__ \ + || defined __EMX__ || defined __MSDOS__ || defined __DJGPP__ + /* Native Windows, Cygwin, OS/2, DOS */ +# define ISSLASH(C) ((C) == '/' || (C) == '\\') + /* Internal macro: Tests whether a character is a drive letter. */ +# define _IS_DRIVE_LETTER(C) \ + (((C) >= 'A' && (C) <= 'Z') || ((C) >= 'a' && (C) <= 'z')) + /* Help the compiler optimizing it. This assumes ASCII. */ +# undef _IS_DRIVE_LETTER +# define _IS_DRIVE_LETTER(C) \ + (((unsigned int) (C) | ('a' - 'A')) - 'a' <= 'z' - 'a') +# define HAS_DEVICE(Filename) \ + (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':') +# define FILE_SYSTEM_PREFIX_LEN(Filename) (HAS_DEVICE (Filename) ? 2 : 0) +# ifdef __CYGWIN__ +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 +# else + /* On native Windows, OS/2, DOS, the system has the notion of a + "current directory" on each drive. */ +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 1 +# endif +# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE +# define IS_ABSOLUTE_FILE_NAME(Filename) \ + ISSLASH ((Filename)[FILE_SYSTEM_PREFIX_LEN (Filename)]) +# else +# define IS_ABSOLUTE_FILE_NAME(Filename) \ + (ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename)) +# endif +# define IS_RELATIVE_FILE_NAME(Filename) \ + (! (ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename))) +# define IS_FILE_NAME_WITH_DIR(Filename) \ + (strchr ((Filename), '/') != NULL || strchr ((Filename), '\\') != NULL \ + || HAS_DEVICE (Filename)) +#else + /* Unix */ +# define ISSLASH(C) ((C) == '/') +# define HAS_DEVICE(Filename) ((void) (Filename), 0) +# define FILE_SYSTEM_PREFIX_LEN(Filename) ((void) (Filename), 0) +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 +# define IS_ABSOLUTE_FILE_NAME(Filename) ISSLASH ((Filename)[0]) +# define IS_RELATIVE_FILE_NAME(Filename) (! ISSLASH ((Filename)[0])) +# define IS_FILE_NAME_WITH_DIR(Filename) (strchr ((Filename), '/') != NULL) +#endif + +/* Deprecated macros. For backward compatibility with old users of the + 'filename' module. */ +#define IS_ABSOLUTE_PATH IS_ABSOLUTE_FILE_NAME +#define IS_PATH_WITH_DIR IS_FILE_NAME_WITH_DIR + + +#ifdef __cplusplus +} +#endif + +#endif /* _FILENAME_H */ diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 4b3bd10a9d..9111d92a4c 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -36,21 +36,18 @@ #include #include #include +#include #include #ifdef _LIBC # include # include -# define FILE_SYSTEM_PREFIX_LEN(name) 0 -# define IS_ABSOLUTE_FILE_NAME(name) ISSLASH(*(name)) -# define ISSLASH(c) ((c) == '/') # define FUNC_REALPATH_WORKS 1 #else # define __canonicalize_file_name canonicalize_file_name # define __realpath realpath # include "pathmax.h" -# include "filename.h" # if defined _WIN32 && !defined __CYGWIN__ # define __getcwd _getcwd # elif HAVE_GETCWD From patchwork Thu Dec 24 15:17:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41551 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 DCE143851C0D; Thu, 24 Dec 2020 15:17:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DCE143851C0D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1608823037; bh=qkluXh06hEQ984NxkhiZkwr9Xql3f9pwCNZbv7tx/dQ=; 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=CsOPz+ywXZ5lBjJUJgHynau3i3c7rfvACL/2LgoLUc876YS/YU+qKMmhATPxC7s9V Gaykavcs6v+4HUjBRjYlIbdkNoZDZ1/1N1v5O87VHtth+hEQv1Ny6RM6adp5Gfzfyo 17jto9SxP1X2xWkrqpJ9Y0PuNuhOOu7bg7bLuIck= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x731.google.com (mail-qk1-x731.google.com [IPv6:2607:f8b0:4864:20::731]) by sourceware.org (Postfix) with ESMTPS id B72363851C0D for ; Thu, 24 Dec 2020 15:17:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org B72363851C0D Received: by mail-qk1-x731.google.com with SMTP id v126so2239412qkd.11 for ; Thu, 24 Dec 2020 07:17:14 -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=qkluXh06hEQ984NxkhiZkwr9Xql3f9pwCNZbv7tx/dQ=; b=HWZcjbrchjZJ0l/QB8Gv3HWG2968pzdVeAO7NqaI3uPGgp0q0n5Rh73WG0TP3ZlXe/ Snz92YX0/a+Hiok3zuYm2MxtIz5lWODb8Wh0Ay6zQk3vdF0ob+LEYCWX9oz3pYxo9i9A U1ORnvIiFNjDwDHKGr7LEvDa61gLbp+EdY2jGZu1nvQ6D3J7KvfjMOb8pxGQheruu41p nYHjeHqf0w90+RCy6jvo5kOxMQYr6/eB/iGCODJY+hNCRUyGUwUyGo0z9JSMP+uq/w86 lMhEHVxSpZQQYc4Z2X9Nx2gFbOptP+5x1lf6F2EK9cc3MymUT1IQ5yiNRbJHSFC0kFjE b5Eg== X-Gm-Message-State: AOAM533h2vPC2A2noMy65bmmHei3l6AnGQ+yp+n2/6kVhkBkseE6KO7C TV/QQbqRiQsMKhu1KS29Tf1nnzT2nFluAA== X-Google-Smtp-Source: ABdhPJy5aeEk67WrZf+2PpgeomVhaU40xs+Kc88DxpuKHiPEUbfXjxb+Gox8y9UJKTTbQ37uPnUu1A== X-Received: by 2002:a37:ccf:: with SMTP id 198mr30401386qkm.223.1608823034031; Thu, 24 Dec 2020 07:17:14 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id h21sm17039460qkk.5.2020.12.24.07.17.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Dec 2020 07:17:13 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 4/5] stdlib: Add testcase fro BZ #26241 Date: Thu, 24 Dec 2020 12:17:00 -0300 Message-Id: <20201224151701.1751008-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> References: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, KAM_SHORT, 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" Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/Makefile | 3 +- stdlib/tst-canon-bz26341.c | 108 ++++++++++++++++++ support/support_set_small_thread_stack_size.c | 12 +- support/xthread.h | 2 + 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 stdlib/tst-canon-bz26341.c diff --git a/stdlib/Makefile b/stdlib/Makefile index 29b7cd7071..6518d8993b 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -86,7 +86,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-makecontext-align test-bz22786 tst-strtod-nan-sign \ tst-swapcontext1 tst-setcontext4 tst-setcontext5 \ tst-setcontext6 tst-setcontext7 tst-setcontext8 \ - tst-setcontext9 tst-bz20544 + tst-setcontext9 tst-bz20544 tst-canon-bz26341 tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ tst-tls-atexit tst-tls-atexit-nodelete @@ -101,6 +101,7 @@ LDLIBS-test-atexit-race = $(shared-thread-library) LDLIBS-test-at_quick_exit-race = $(shared-thread-library) LDLIBS-test-cxa_atexit-race = $(shared-thread-library) LDLIBS-test-on_exit-race = $(shared-thread-library) +LDLIBS-tst-canon-bz26341 = $(shared-thread-library) LDLIBS-test-dlclose-exit-race = $(shared-thread-library) $(libdl) LDFLAGS-test-dlclose-exit-race = $(LDFLAGS-rdynamic) diff --git a/stdlib/tst-canon-bz26341.c b/stdlib/tst-canon-bz26341.c new file mode 100644 index 0000000000..63474bddaa --- /dev/null +++ b/stdlib/tst-canon-bz26341.c @@ -0,0 +1,108 @@ +/* Check if realpath does not consume extra stack space based on symlink + existance in the path (BZ #26341) + Copyright (C) 2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +static char *filename; +static size_t filenamelen; +static char *linkname; + +static int +maxsymlinks (void) +{ +#ifdef MAXSYMLINKS + return MAXSYMLINKS; +#else + long int sysconf_symloop_max = sysconf (_SC_SYMLOOP_MAX); + return sysconf_symloop_max <= 0 + ? _POSIX_SYMLOOP_MAX + : sysconf_symloop_max; +#endif +} + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +static void +create_link (void) +{ + int fd = create_temp_file ("tst-canon-bz26341", &filename); + TEST_VERIFY_EXIT (fd != -1); + xclose (fd); + + char *prevlink = filename; + int maxlinks = maxsymlinks (); + for (int i = 0; i < maxlinks; i++) + { + linkname = xasprintf ("%s%d", filename, i); + xsymlink (prevlink, linkname); + add_temp_file (linkname); + prevlink = linkname; + } + + filenamelen = strlen (filename); +} + +static void * +do_realpath (void *arg) +{ + /* Old implementation of realpath allocates a PATH_MAX using alloca + for each symlink in the path, leading to MAXSYMLINKS times PATH_MAX + maximum stack usage. + This stack allocations tries fill the thread allocated stack minus + both the thread (plus some slack) and the realpath (plus some slack). + If realpath uses more than 2 * PATH_MAX plus some slack it will trigger + a stackoverflow. */ + + const size_t realpath_usage = 2 * PATH_MAX + 1024; + const size_t thread_usage = 1 * PATH_MAX + 1024; + size_t stack_size = support_small_thread_stack_size () + - realpath_usage - thread_usage; + char stack[stack_size]; + char *resolved = stack + stack_size - thread_usage + 1024; + + char *p = realpath (linkname, resolved); + TEST_VERIFY (p != NULL); + TEST_COMPARE_BLOB (resolved, filenamelen, filename, filenamelen); + + return NULL; +} + +static int +do_test (void) +{ + create_link (); + + pthread_t th = xpthread_create (support_small_stack_thread_attribute (), + do_realpath, NULL); + xpthread_join (th); + + return 0; +} + +#include diff --git a/support/support_set_small_thread_stack_size.c b/support/support_set_small_thread_stack_size.c index 69d66e97db..74a0e38a72 100644 --- a/support/support_set_small_thread_stack_size.c +++ b/support/support_set_small_thread_stack_size.c @@ -20,8 +20,8 @@ #include #include -void -support_set_small_thread_stack_size (pthread_attr_t *attr) +size_t +support_small_thread_stack_size (void) { /* Some architectures have too small values for PTHREAD_STACK_MIN which cannot be used for creating threads. Ensure that the stack @@ -31,5 +31,11 @@ support_set_small_thread_stack_size (pthread_attr_t *attr) if (stack_size < PTHREAD_STACK_MIN) stack_size = PTHREAD_STACK_MIN; #endif - xpthread_attr_setstacksize (attr, stack_size); + return stack_size; +} + +void +support_set_small_thread_stack_size (pthread_attr_t *attr) +{ + xpthread_attr_setstacksize (attr, support_small_thread_stack_size ()); } diff --git a/support/xthread.h b/support/xthread.h index 05f8d4a7d9..6ba2f5a18b 100644 --- a/support/xthread.h +++ b/support/xthread.h @@ -78,6 +78,8 @@ void xpthread_attr_setguardsize (pthread_attr_t *attr, /* Set the stack size in ATTR to a small value, but still large enough to cover most internal glibc stack usage. */ void support_set_small_thread_stack_size (pthread_attr_t *attr); +/* Return the stack size used on support_set_small_thread_stack_size. */ +size_t support_small_thread_stack_size (void); /* Return a pointer to a thread attribute which requests a small stack. The caller must not free this pointer. */ From patchwork Thu Dec 24 15:17:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 41552 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 7541A3898509; Thu, 24 Dec 2020 15:17:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7541A3898509 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1608823039; bh=Ht1dTKRROJmZQkqkZu30EBoWAfJB8EQoCdZ1WFhpD4Y=; 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=ZlMC5AklIdIKGYbHtGCdwy7rWalObMnpK9y8aozvxcMvRdK/fnBn7tTj7bXSlzq8u SNoq5Y9+lnL3sB+8DHjkqn9Ty0AUp27XghypW2pMqT8g0W0TI6GsQPlDO5Ka6B1Ntc Nu699VZJQ6XPArvi9Xdcy2sYMH9t3NTwpqglGOVI= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf29.google.com (mail-qv1-xf29.google.com [IPv6:2607:f8b0:4864:20::f29]) by sourceware.org (Postfix) with ESMTPS id 9351D388703E for ; Thu, 24 Dec 2020 15:17:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 9351D388703E Received: by mail-qv1-xf29.google.com with SMTP id p12so1271156qvj.13 for ; Thu, 24 Dec 2020 07:17:16 -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=Ht1dTKRROJmZQkqkZu30EBoWAfJB8EQoCdZ1WFhpD4Y=; b=HDowM0estlVoWViXS2OWCJdGTPwLFIKB7Q6tXTkisC4W7qa4RSOBHFYY1WQQZZizTg 1MYKFGOrNM4+aJl0hWxcVaL7Uyg6gyIPXYrYzzp12PpgiOjgBVUPnPPKuVRAYjLbnGYm Ot800sk+gsijGnzLZh/2etYOL1R9FBG3zW6e5aJvs0OffsGyMyz3PeNIfyJk8IQ4/nv2 Gyu33S592MWcuN+pOmusp5uO2UpzoLi2Z9pq04K033DxAMz4SQbh/UgZSORQRWEOLP2O RGIpCVvT0l25q80wqVIXde3x2MdgLNmvVB1C9kIkbCeQD4SPsktKYeWA0PS9YIrs057N GzVQ== X-Gm-Message-State: AOAM53386Wnfzcj5Xh2bljTEuRpCu1NTe4oCMH9FiC0Rnxg79kyarD5r mt3T6I7Cp6YOPa/LlYEYaVBK1sFCPIudTA== X-Google-Smtp-Source: ABdhPJySPcQX2W0YhTJS+URXUgdyUm15Q1lsuo6z0gq3M9u3Ge0nuj7Ob5Vm1nL5MhW8qdP6CIdHPQ== X-Received: by 2002:ad4:5762:: with SMTP id r2mr32241593qvx.45.1608823035860; Thu, 24 Dec 2020 07:17:15 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id h21sm17039460qkk.5.2020.12.24.07.17.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Dec 2020 07:17:15 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 5/5] stdlib: Remove lstat usage from realpath [BZ #24970] Date: Thu, 24 Dec 2020 12:17:01 -0300 Message-Id: <20201224151701.1751008-6-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> References: <20201224151701.1751008-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 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" The readlink already tells whether the file is a symlink, so there is no need to call lstat to check it. However for '..' it requires an extra readlink check if the previous component can be really accessed, otherwise the next iteration will check a possible valid path and end early. It should performance-wise acceptable and a gain over lstat, afaik symlink should not update any inode information. It also fixes the stdlib/test-canon issued from the gnulib sync. Checked on x86_64-linux-gnu. --- include/scratch_buffer.h | 21 ++++++ stdlib/canonicalize.c | 139 +++++++++++++++++++++++---------------- 2 files changed, 102 insertions(+), 58 deletions(-) diff --git a/include/scratch_buffer.h b/include/scratch_buffer.h index c39da78629..7ae77e5160 100644 --- a/include/scratch_buffer.h +++ b/include/scratch_buffer.h @@ -132,4 +132,25 @@ scratch_buffer_set_array_size (struct scratch_buffer *buffer, (buffer, nelem, size)); } +/* Check if BUFFER is using the internal buffer. */ +static __always_inline bool +scratch_buffer_using_internal (struct scratch_buffer *buffer) +{ + return buffer->data == buffer->__space.__c; +} + +/* Return the internal buffer from BUFFER if it is dynamic allocated, + otherwise returns NULL. Initializes the BUFFER if the internal + dynamic buffer is returned. */ +static __always_inline void * +scratch_buffer_take_buffer (struct scratch_buffer *buffer) +{ + if (scratch_buffer_using_internal (buffer)) + return NULL; + + void *r = buffer->data; + scratch_buffer_init (buffer); + return r; +} + #endif /* _SCRATCH_BUFFER_H */ diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 9111d92a4c..78a06227d2 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -88,6 +88,21 @@ #if !FUNC_REALPATH_WORKS || defined _LIBC static idx_t +readlink_scratch_buffer (const char *path, struct scratch_buffer *buf) +{ + ssize_t r; + while (true) + { + ptrdiff_t bufsize = buf->length; + r = __readlink (path, buf->data, bufsize - 1); + if (r < bufsize - 1) + break; + if (!scratch_buffer_grow (buf)) + return -1; + } + return r; +} +static idx_t get_path_max (void) { # ifdef PATH_MAX @@ -144,12 +159,10 @@ __realpath (const char *name, char *resolved) struct scratch_buffer extra_buffer, link_buffer; struct scratch_buffer rname_buffer; - struct scratch_buffer *rname_buf = &rname_buffer; scratch_buffer_init (&extra_buffer); scratch_buffer_init (&link_buffer); - scratch_buffer_init (rname_buf); - char *rname_on_stack = rname_buf->data; - char *rname = rname_on_stack; + scratch_buffer_init (&rname_buffer); + char *rname = rname_buffer.data; bool end_in_extra_buffer = false; bool failed = true; @@ -159,16 +172,16 @@ __realpath (const char *name, char *resolved) if (!IS_ABSOLUTE_FILE_NAME (name)) { - while (!__getcwd (rname, rname_buf->length)) + while (!__getcwd (rname, rname_buffer.length)) { if (errno != ERANGE) { dest = rname; goto error; } - if (!scratch_buffer_grow (rname_buf)) + if (!scratch_buffer_grow (&rname_buffer)) goto error_nomem; - rname = rname_buf->data; + rname = rname_buffer.data; } dest = __rawmemchr (rname, '\0'); start = name; @@ -188,7 +201,7 @@ __realpath (const char *name, char *resolved) start = name + prefix_len; } - for ( ; *start; start = end) + for (end = start ; *start; start = end) { /* Skip sequence of multiple file name separators. */ while (ISSLASH (*start)) @@ -206,6 +219,20 @@ __realpath (const char *name, char *resolved) /* nothing */; else if (startlen == 2 && start[0] == '.' && start[1] == '.') { + if (!ISSLASH (dest[-1])) + *dest++ = '/'; + *dest = '\0'; + + ssize_t n = readlink_scratch_buffer (rname, &link_buffer); + if (n < 0) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno == ENOMEM) + goto error_nomem; + if (errno != EINVAL) + goto error; + } /* Back up to previous component, ignore if at root already. */ if (dest > rname + prefix_len + 1) for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest) @@ -220,46 +247,36 @@ __realpath (const char *name, char *resolved) if (!ISSLASH (dest[-1])) *dest++ = '/'; - while (rname + rname_buf->length - dest <= startlen) + while (rname + rname_buffer.length - dest <= startlen) { idx_t dest_offset = dest - rname; - if (!scratch_buffer_grow_preserve (rname_buf)) + if (!scratch_buffer_grow_preserve (&rname_buffer)) goto error_nomem; - rname = rname_buf->data; + rname = rname_buffer.data; dest = rname + dest_offset; } dest = __mempcpy (dest, start, startlen); *dest = '\0'; - /* If STARTLEN == 0, RNAME ends in '/'; use stat rather than - readlink, because readlink might fail with EINVAL without - checking whether RNAME sans '/' is valid. */ - struct stat st; - char *buf = NULL; - ssize_t n; - if (startlen != 0) + ssize_t n = readlink_scratch_buffer (rname, &link_buffer); + if (n < 0) { - while (true) - { - buf = link_buffer.data; - idx_t bufsize = link_buffer.length; - n = __readlink (rname, buf, bufsize - 1); - if (n < bufsize - 1) - break; - if (!scratch_buffer_grow (&link_buffer)) - goto error_nomem; - } - if (n < 0) - buf = NULL; + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno == ENOMEM) + goto error_nomem; + if (errno != EINVAL) + goto error; } - if (buf) + else { if (++num_links > __eloop_threshold ()) { __set_errno (ELOOP); goto error; } + char *buf = (char*) link_buffer.data; buf[n] = '\0'; @@ -279,7 +296,7 @@ __realpath (const char *name, char *resolved) /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); - name = end = memcpy (extra_buf, buf, n); + name = end = memcpy (extra_buf, link_buffer.data, n); end_in_extra_buffer = true; if (IS_ABSOLUTE_FILE_NAME (buf)) @@ -309,10 +326,6 @@ __realpath (const char *name, char *resolved) dest++; } } - else if (! (startlen == 0 - ? stat (rname, &st) == 0 || errno == EOVERFLOW - : errno == EINVAL)) - goto error; } } if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1])) @@ -320,34 +333,44 @@ __realpath (const char *name, char *resolved) if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; + *dest = '\0'; failed = false; error: - *dest++ = '\0'; - if (resolved != NULL && dest - rname <= get_path_max ()) - rname = strcpy (resolved, rname); + if (resolved != NULL) + { + if (dest - rname <= get_path_max ()) + rname = strcpy (resolved, rname); + } + else + { + if (rname == resolved) + return rname; + + idx_t rname_size = dest - rname; + if (scratch_buffer_using_internal (&rname_buffer)) + { + rname = malloc (rname_size + 1); + if (rname != NULL) + { + memcpy (rname, rname_buffer.data, rname_size); + rname[rname_size] = '\0'; + } + } + else + { + rname = scratch_buffer_take_buffer (&rname_buffer); + char *result = realloc (rname, rname_size); + if (result != NULL) + rname = result; + } + } error_nomem: - scratch_buffer_free (&extra_buffer); scratch_buffer_free (&link_buffer); - if (failed || rname == resolved) - scratch_buffer_free (rname_buf); - - if (failed) - return NULL; - - if (rname == resolved) - return rname; - idx_t rname_size = dest - rname; - if (rname == rname_on_stack) - { - rname = malloc (rname_size); - if (rname == NULL) - return NULL; - return memcpy (rname, rname_on_stack, rname_size); - } - char *result = realloc (rname, rname_size); - return result != NULL ? result : rname; + scratch_buffer_free (&extra_buffer); + scratch_buffer_free (&rname_buffer); + return failed ? NULL : rname; } libc_hidden_def (__realpath) versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);