public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org
Subject: [PATCH v2 4/5] linux: Simplify getcwd implementation
Date: Tue,  1 Sep 2020 17:37:03 -0300	[thread overview]
Message-ID: <20200901203704.172996-4-adhemerval.zanella@linaro.org> (raw)
In-Reply-To: <20200901203704.172996-1-adhemerval.zanella@linaro.org>

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
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
-#include <sys/param.h>
 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
-
-/* 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 <sysdeps/posix/getcwd.c>
+#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;
-- 
2.25.1


  parent reply	other threads:[~2020-09-01 20:37 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-01 20:37 [PATCH v2 1/5] Sync getcwd with gnulib Adhemerval Zanella
2020-09-01 20:37 ` [PATCH v2 2/5] linux: Remove __ASSUME_ATFCTS Adhemerval Zanella
2020-09-01 20:37 ` [PATCH v2 3/5] Use LFS readdir in generic POSIX getcwd [BZ# 22899] Adhemerval Zanella
2020-09-01 20:37 ` Adhemerval Zanella [this message]
2020-09-01 20:37 ` [PATCH v2 5/5] io: Reorganize the getcwd implementation Adhemerval Zanella
2020-09-01 21:24 ` [PATCH v2 1/5] Sync getcwd with gnulib Paul Eggert
2020-09-02 11:50   ` Adhemerval Zanella

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200901203704.172996-4-adhemerval.zanella@linaro.org \
    --to=adhemerval.zanella@linaro.org \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).