[PATCH v2] nptl: pthread_getattr_np: Read /proc/self/maps in BUFSIZ chunks, avoid fstat

Josh Triplett <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <46d13770b118b68b936bcd25420edf84bf5ba91c.1784782269.git.josh@joshtriplett.org>
pthread_getattr_np gets stack information by reading /proc/self/maps.
This file, like all proc inodes, reports a size of 1024, regardless of
its actual content. In practice, it tends to be several times that size.
So, use our BUFSIZ instead.

This also avoids an unnecessary `fstat`.

This requires us to allocate a buffer ourselves, since otherwise the
default logic in `setvbuf` will ignore our requested size in favor of
the stat-based heuristics.

strace before:
```
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "558bccc5a000-558bccc6e000 r--p 0"..., 1024) = 1024
read(3, "                  /usr/lib/x86_6"..., 1024) = 1024
read(3, "             /usr/lib/x86_64-lin"..., 1024) = 670
close(3)                                = 0
```

strace after:
```
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
read(3, "55556b7ab000-55556b7cc000 rw-p 0"..., 8192) = 2753
close(3)                                = 0
```

Note the single `read` call and the absent `fstat`.

Signed-off-by: Josh Triplett <[email protected]>
---
v2: Use `_IO_setvbuf` rather than `setvbuf` to avoid the PLT.

I don't have commit access yet, so I'd appreciate it if a reviewer could
commit this for me once accepted.

 nptl/pthread_getattr_np.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
index b0d2343a59..659323fc9c 100644
--- a/nptl/pthread_getattr_np.c
+++ b/nptl/pthread_getattr_np.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/resource.h>
+#include "iolibio.h"
 #include "pthreadP.h"
 #include <lowlevellock.h>
 #include <ldsodefs.h>
@@ -88,10 +89,23 @@ __pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
       /* We need the limit of the stack in any case.  */
       else
 	{
+	  char *fp_buf = NULL;
 	  if (__getrlimit (RLIMIT_STACK, &rl) != 0)
 	    ret = errno;
 	  else
 	    {
+	      /* /proc/self/maps reports a size of 1024, like all proc inodes.
+		 However, in practice it tends to be larger than that. Use our
+		 default BUFSIZ instead. We have to allocate the buffer
+		 ourselves, because if we don't, setvbuf ignores the requested
+		 size and uses the file size. */
+	      fp_buf = malloc(BUFSIZ);
+	      if (fp_buf && _IO_setvbuf (fp, fp_buf, _IOFBF, BUFSIZ) != 0)
+		{
+		  free(fp_buf);
+		  fp_buf = NULL;
+		}
+
 	      /* 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
@@ -163,6 +177,7 @@ __pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr)
 	    }
 
 	  fclose (fp);
+	  free (fp_buf);
 	}
     }
 
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.