]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - nptl/pthread_getattr_np.c
alloc_buffer: Return unqualified pointer type in alloc_buffer_next
[thirdparty/glibc.git] / nptl / pthread_getattr_np.c
index 87cf56482f3f5f36c80e4fcdbae5ec28db699534..9b752e606a19d18fb6004983b029e9ecf0f63c5d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 2002-2019 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -13,9 +13,8 @@
    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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <assert.h>
 #include <errno.h>
 
 
 int
-pthread_getattr_np (thread_id, attr)
-     pthread_t thread_id;
-     pthread_attr_t *attr;
+pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
 {
   struct pthread *thread = (struct pthread *) thread_id;
   struct pthread_attr *iattr = (struct pthread_attr *) attr;
   int ret = 0;
 
-  lll_lock (thread->lock);
+  lll_lock (thread->lock, LLL_PRIVATE);
 
   /* The thread library is responsible for keeping the values in the
      thread desriptor up-to-date in case the user changes them.  */
@@ -58,16 +55,22 @@ pthread_getattr_np (thread_id, attr)
   iattr->guardsize = thread->reported_guardsize;
 
   /* The sizes are subject to alignment.  */
-  if (__builtin_expect (thread->stackblock != NULL, 1))
+  if (__glibc_likely (thread->stackblock != NULL))
     {
-      iattr->stacksize = thread->stackblock_size;
-      iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+      /* The stack size reported to the user should not include the
+        guard size.  */
+      iattr->stacksize = thread->stackblock_size - thread->guardsize;
+#if _STACK_GROWS_DOWN
+      iattr->stackaddr = (char *) thread->stackblock
+                        + thread->stackblock_size;
+#else
+      iattr->stackaddr = (char *) thread->stackblock;
+#endif
     }
   else
     {
       /* No stack information available.  This must be for the initial
         thread.  Get the info in some magical way.  */
-      assert (abs (thread->pid) == thread->tid);
 
       /* Stack size limit.  */
       struct rlimit rl;
@@ -75,7 +78,7 @@ pthread_getattr_np (thread_id, attr)
       /* 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", "rc");
+      FILE *fp = fopen ("/proc/self/maps", "rce");
       if (fp == NULL)
        ret = errno;
       /* We need the limit of the stack in any case.  */
@@ -85,6 +88,18 @@ pthread_getattr_np (thread_id, attr)
            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);
 
@@ -94,7 +109,9 @@ pthread_getattr_np (thread_id, attr)
 
              char *line = NULL;
              size_t linelen = 0;
+#if _STACK_GROWS_DOWN
              uintptr_t last_to = 0;
+#endif
 
              while (! feof_unlocked (fp))
                {
@@ -109,19 +126,33 @@ pthread_getattr_np (thread_id, attr)
                      && (uintptr_t) __libc_stack_end < to)
                    {
                      /* Found the entry.  Now we have the info we need.  */
-                     iattr->stacksize = rl.rlim_cur;
-                     iattr->stackaddr = (void *) to;
-
+                     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 high.  */
+                     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);
@@ -164,7 +195,7 @@ pthread_getattr_np (thread_id, attr)
        {
          free (cpuset);
          if (ret == ENOSYS)
-           {     
+           {
              /* There is no such functionality.  */
              ret = 0;
              iattr->cpuset = NULL;
@@ -173,7 +204,7 @@ pthread_getattr_np (thread_id, attr)
        }
     }
 
-  lll_unlock (thread->lock);
+  lll_unlock (thread->lock, LLL_PRIVATE);
 
   return ret;
 }