From patchwork Tue Sep 1 20:37:03 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: 40350 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 51F8C395C877; Tue, 1 Sep 2020 20:37:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 51F8C395C877 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1598992647; bh=pwb/gUUE4q3lT1ZTCe9QinSFe8V+5OBmjk4xSzIS/Yw=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=EYPx/l1L5/8DnOZPV9FiRACU6kOGcNc7HkwVtppjov5WIIjF/GO47BkIl/aOEbN99 qx6rYqHj+rynw3HbwvKF3a6knfL1hKq4VerMQOKsIA/YIvtrG/wCtOg/sT5wel6ByQ Af7MXcPZHPiFYvK9w34/l7/u/j5cu/udvd/BzfrM= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf42.google.com (mail-qv1-xf42.google.com [IPv6:2607:f8b0:4864:20::f42]) by sourceware.org (Postfix) with ESMTPS id 61A663959E47 for ; Tue, 1 Sep 2020 20:37:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 61A663959E47 Received: by mail-qv1-xf42.google.com with SMTP id db4so1042188qvb.4 for ; Tue, 01 Sep 2020 13:37:24 -0700 (PDT) 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:mime-version:content-transfer-encoding; bh=pwb/gUUE4q3lT1ZTCe9QinSFe8V+5OBmjk4xSzIS/Yw=; b=ra7B6cWc+0bd1jd5CaBHQXHONzNVJShDS6llxSfzOtfatF1nYmKa8GCoV1Y0MdMgLE xeG4Vi8v9nA0nDqtG9X3cFQjHDdQUNd41SB+zVTsLMnmFUGsKlQpgK+piTq/dJGFWpLy TaI2nhyKCJnmFFOf/L7/M3hCle5d+qI7oPdz0Ew/Y6F4cbQkirYScV9p0sfN2UtL9v3K sVV/AEBn9qwdcsdAFbg3lcs9kA484SHetYbdGHVCe7vV57JamPwr4FyKfZgH0r+kZDyB TgRUrYrDN2yHSSCSHA1B59yzXmeYelhmtFQPCp+Yj1Ju30fLaCbVU60nC9ZQcogwn0db 96Gw== X-Gm-Message-State: AOAM530to7fcwXF7RqGHnmAmdAIAfTviDsx38ScH/x2qUs6Ufus+hmr9 JALoNqz93kRqLQfFOpkFbBKcL90Urn0cDA== X-Google-Smtp-Source: ABdhPJwks8+iYz4Lu8LHMLJB15KffAhqBTTzifz3Xc01JAcPWLI8nf6beQGKjY5r0so/mTRA9iGkMA== X-Received: by 2002:a05:6214:5cf:: with SMTP id t15mr3859513qvz.119.1598992643590; Tue, 01 Sep 2020 13:37:23 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id z29sm2940176qtj.79.2020.09.01.13.37.22 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2020 13:37:23 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 4/5] linux: Simplify getcwd implementation Date: Tue, 1 Sep 2020 17:37:03 -0300 Message-Id: <20200901203704.172996-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200901203704.172996-1-adhemerval.zanella@linaro.org> References: <20200901203704.172996-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.6 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 Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" Changes from previous version: - Move the linux and loader changes to its own patch. --- Instead of allocating and reallocate/free the buffer, a temporary buffer of PATH_MAX size is used and output buffer is allocated only the syscall returns a valid buffer. The NO_ALLOCATION is removed and instead the buffer allocation path is also used on loader (and the stretegy of using the temporary stack buffer should play nice with the loader bump allocator). The fallback generic algorithm is not built for rtld, since it would eventually fail to open paths larger than PATH_MAX. Checked on x86_64-linux-gnu and i686-linux-gnu. --- elf/dl-object.c | 30 +++------ sysdeps/unix/sysv/linux/getcwd.c | 112 +++++++++---------------------- 2 files changed, 42 insertions(+), 100 deletions(-) diff --git a/elf/dl-object.c b/elf/dl-object.c index d2cdf135cc..717fb253bb 100644 --- a/elf/dl-object.c +++ b/elf/dl-object.c @@ -202,38 +202,30 @@ _dl_new_object (char *realname, const char *libname, int type, } else { - size_t len = realname_len; - char *result = NULL; - - /* Get the current directory name. */ - origin = NULL; - do + /* The rtld __getcwd implementation does not handle paths larger + than PATH_MAX (which would be invalid to be used on subsequent + open calls). */ + origin = __getcwd (NULL, 0); + if (origin == NULL) { - char *new_origin; - - len += 128; - new_origin = (char *) realloc (origin, len); - if (new_origin == NULL) - /* We exit the loop. Note that result == NULL. */ - break; - origin = new_origin; + origin = (char *) -1; + goto out; } - while ((result = __getcwd (origin, len - realname_len)) == NULL - && errno == ERANGE); + size_t len = strlen (origin); + char *result = realloc (origin, len + realname_len); if (result == NULL) { - /* We were not able to determine the current directory. - Note that free(origin) is OK if origin == NULL. */ free (origin); origin = (char *) -1; goto out; } + origin = result; + cp = origin + len; /* Find the end of the path and see whether we have to add a slash. We could use rawmemchr but this need not be fast. */ - cp = (strchr) (origin, '\0'); if (cp[-1] != '/') *cp++ = '/'; } diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c index c5886f5283..5ef0b092ec 100644 --- a/sysdeps/unix/sysv/linux/getcwd.c +++ b/sysdeps/unix/sysv/linux/getcwd.c @@ -17,115 +17,65 @@ License along with the GNU C Library; if not, see . */ -#include #include #include #include +#include #include -#include #include #include - -/* If we compile the file for use in ld.so we don't need the feature - that getcwd() allocates the buffers itself. */ -#if IS_IN (rtld) -# define NO_ALLOCATION 1 -#endif - - -/* The "proc" filesystem provides an easy method to retrieve the value. - For each process, the corresponding directory contains a symbolic link - named `cwd'. Reading the content of this link immediate gives us the - information. But we have to take care for systems which do not have - the proc filesystem mounted. Use the POSIX implementation in this case. */ - -/* Get the code for the generic version. */ +#if !IS_IN (rtld) +/* The generic implementation is used for valid paths larger than + PATH_MAX (where the syscall returns a positive value with errno + set to ENAMETOOLONG). */ #define GETCWD_RETURN_TYPE static char * #include +#endif char * __getcwd (char *buf, size_t size) { - char *path; - char *result; + char *r = NULL; + int len; -#ifndef NO_ALLOCATION - size_t alloc_size = size; - if (size == 0) + if (buf != NULL) { - if (buf != NULL) + if (size == 0) { __set_errno (EINVAL); return NULL; - } - alloc_size = MAX (PATH_MAX, __getpagesize ()); - } - - if (buf == NULL) - { - path = malloc (alloc_size); - if (path == NULL) - return NULL; + } + len = INLINE_SYSCALL_CALL (getcwd, buf, size); + if (len > 0) + r = buf; } else -#else -# define alloc_size size -#endif - path = buf; - - int retval; - - retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size); - if (retval > 0 && path[0] == '/') - { -#ifndef NO_ALLOCATION - if (buf == NULL && size == 0) - /* Ensure that the buffer is only as large as necessary. */ - buf = realloc (path, (size_t) retval); - - if (buf == NULL) - /* Either buf was NULL all along, or `realloc' failed but - we still have the original string. */ - buf = path; -#endif - - return buf; - } - - /* The system call either cannot handle paths longer than a page - or can succeed without returning an absolute path. Just use the - generic implementation right away. */ - if (retval >= 0 || errno == ENAMETOOLONG) { -#ifndef NO_ALLOCATION - if (buf == NULL && size == 0) + char tmp[PATH_MAX]; + size_t tmps = size == 0 || size > PATH_MAX + ? PATH_MAX : size; + len = INLINE_SYSCALL_CALL (getcwd, tmp, tmps); + if (len > 0) { - free (path); - path = NULL; - } -#endif - - result = __getcwd_generic (path, size); + /* Allocates a buffer with at least SIZE bytes, even it is larger + than required buffer. */ + r = malloc (size > len ? size : len); + if (r == NULL) + return NULL; -#ifndef NO_ALLOCATION - if (result == NULL && buf == NULL && size != 0) - free (path); -#endif - - return result; + memcpy (r, tmp, len); + } } - /* It should never happen that the `getcwd' syscall failed because - the buffer is too small if we allocated the buffer ourselves - large enough. */ - assert (errno != ERANGE || buf != NULL || size != 0); + if (len > 0 && r[0] == '/') + return r; -#ifndef NO_ALLOCATION - if (buf == NULL) - free (path); +#if !IS_IN (rtld) + if (len >=0 || errno == ENAMETOOLONG) + return __getcwd_generic (buf, size); #endif return NULL;