[PATCH 4/6] nptl: Use __libc_procmaps_iterate on pthread_getattr_np

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue Sep 15 18:34:48 GMT 2026


Instead of stdio and __getline, which removes the malloc usage and the
fstat that stdio issues to size the stream buffer, and shares the
/proc/self/maps parsing with __readonly_area_fallback.

Checked on x86_64-linux-gnu.
---
 nptl/pthread_getattr_np.c | 186 ++++++++++++++++++--------------------
 1 file changed, 89 insertions(+), 97 deletions(-)

diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
index b0d2343a59a..698954f405a 100644
--- a/nptl/pthread_getattr_np.c
+++ b/nptl/pthread_getattr_np.c
@@ -17,15 +17,98 @@
 
 #include <assert.h>
 #include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdio_ext.h>
+#include <ldsodefs.h>
+#include <procmaps.h>
+#include <shlib-compat.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/resource.h>
 #include "pthreadP.h"
 #include <lowlevellock.h>
-#include <ldsodefs.h>
+
+
+struct find_stack_args
+{
+  uintptr_t stack_end;
+  uintptr_t to;
+#if _STACK_GROWS_DOWN
+  uintptr_t last_to;
+#endif
+  bool found;
+};
+
+/* Check whether the mapping address range contains ARGS->stack_end.  */
+static bool
+find_stack_vma (uintptr_t start, uintptr_t end, const char *perm, void *arg)
+{
+  struct find_stack_args *args = arg;
+
+  if (start <= args->stack_end && args->stack_end < end)
+    {
+      args->to = end;
+      args->found = true;
+      return true;
+    }
+#if _STACK_GROWS_DOWN
+  args->last_to = end;
+#endif
+  return false;
+}
+
+static int
+pthread_main_stack (void **stackaddr, size_t *stacksize)
+{
+  /* Stack size limit.  */
+  struct rlimit rl;
+
+  /* We need the limit of the stack in any case.  */
+  if (__getrlimit (RLIMIT_STACK, &rl) != 0)
+    return errno;
+
+  /* We consider the main process stack to have ended with the page
+     containing __libc_stack_end.  There is stuff below it in the stack too,
+     like the program arguments, environment variables and auxv info, but we
+     ignore those pages when returning size so that the output is consistent
+     when the stack is marked executable due to a loaded DSO requiring it.  */
+  void *stack_end = (void *) ((uintptr_t) __libc_stack_end
+			      & -(uintptr_t) GLRO(dl_pagesize));
+#if _STACK_GROWS_DOWN
+  stack_end += GLRO(dl_pagesize);
+#endif
+  /* The safest way to get the top of the stack is to read
+     /proc/self/maps and locate the line into which __libc_stack_end
+     falls.  */
+  struct find_stack_args args =
+    {
+      .stack_end = (uintptr_t) __libc_stack_end,
+    };
+
+  if (__libc_procmaps_iterate (find_stack_vma, &args) == procutils_read_error)
+    return errno;
+  if (!args.found)
+    /* No entry was found (there should always be one).  */
+    return ENOENT;
+
+  size_t size = rl.rlim_cur - (size_t) (args.to - (uintptr_t) stack_end);
+
+  /* Cut it down to align it to page size since otherwise we risk going beyond
+     rlimit when the kernel rounds up the stack extension request.  */
+  size &= -(uintptr_t) GLRO(dl_pagesize);
+#if _STACK_GROWS_DOWN
+  /* The limit might be too high.  */
+  if (size > (uintptr_t) stack_end - args.last_to)
+    size = (uintptr_t) stack_end - args.last_to;
+#else
+  /* The limit might be too low.  */
+  if (size < args.to - (uintptr_t) stack_end)
+    size = args.to - (uintptr_t) stack_end;
+#endif
+
+  *stackaddr = stack_end;
+  *stacksize = size;
+  return 0;
+}
 
 
 int
@@ -72,99 +155,8 @@ __pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
 #endif
     }
   else
-    {
-      /* No stack information available.  This must be for the initial
-	 thread.  Get the info in some magical way.  */
-
-      /* Stack size limit.  */
-      struct rlimit rl;
-
-      /* The safest way to get the top of the stack is to read
-	 /proc/self/maps and locate the line into which
-	 __libc_stack_end falls.  */
-      FILE *fp = fopen ("/proc/self/maps", "rce");
-      if (fp == NULL)
-	ret = errno;
-      /* We need the limit of the stack in any case.  */
-      else
-	{
-	  if (__getrlimit (RLIMIT_STACK, &rl) != 0)
-	    ret = errno;
-	  else
-	    {
-	      /* We consider the main process stack to have ended with
-	         the page containing __libc_stack_end.  There is stuff below
-		 it in the stack too, like the program arguments, environment
-		 variables and auxv info, but we ignore those pages when
-		 returning size so that the output is consistent when the
-		 stack is marked executable due to a loaded DSO requiring
-		 it.  */
-	      void *stack_end = (void *) ((uintptr_t) __libc_stack_end
-					  & -(uintptr_t) GLRO(dl_pagesize));
-#if _STACK_GROWS_DOWN
-	      stack_end += GLRO(dl_pagesize);
-#endif
-	      /* We need no locking.  */
-	      __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
-	      /* Until we found an entry (which should always be the case)
-		 mark the result as a failure.  */
-	      ret = ENOENT;
-
-	      char *line = NULL;
-	      size_t linelen = 0;
-#if _STACK_GROWS_DOWN
-	      uintptr_t last_to = 0;
-#endif
-
-	      while (! feof_unlocked (fp))
-		{
-		  if (__getline (&line, &linelen, fp) <= 0)
-		    break;
-
-		  uintptr_t from;
-		  uintptr_t to;
-		  if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
-		    continue;
-		  if (from <= (uintptr_t) __libc_stack_end
-		      && (uintptr_t) __libc_stack_end < to)
-		    {
-		      /* Found the entry.  Now we have the info we need.  */
-		      iattr->stackaddr = stack_end;
-		      iattr->stacksize =
-		        rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end);
-
-		      /* Cut it down to align it to page size since otherwise we
-		         risk going beyond rlimit when the kernel rounds up the
-		         stack extension request.  */
-		      iattr->stacksize = (iattr->stacksize
-					  & -(intptr_t) GLRO(dl_pagesize));
-#if _STACK_GROWS_DOWN
-		      /* The limit might be too high.  */
-		      if ((size_t) iattr->stacksize
-			  > (size_t) iattr->stackaddr - last_to)
-			iattr->stacksize = (size_t) iattr->stackaddr - last_to;
-#else
-		      /* The limit might be too low.  */
-		      if ((size_t) iattr->stacksize
-			  < to - (size_t) iattr->stackaddr)
-			iattr->stacksize = to - (size_t) iattr->stackaddr;
-#endif
-		      /* We succeed and no need to look further.  */
-		      ret = 0;
-		      break;
-		    }
-#if _STACK_GROWS_DOWN
-		  last_to = to;
-#endif
-		}
-
-	      free (line);
-	    }
-
-	  fclose (fp);
-	}
-    }
+    /* No stack information available.  This must be for the initial thread.  */
+    ret = pthread_main_stack (&iattr->stackaddr, &iattr->stacksize);
 
   iattr->flags |= ATTR_FLAG_STACKADDR;
 
-- 
2.53.0



More information about the Libc-alpha mailing list