[PATCH v2] nptl: pthread_getattr_np: Read /proc/self/maps in BUFSIZ chunks, avoid fstat
Josh Triplett
josh@joshtriplett.org
Thu Jul 23 04:57:47 GMT 2026
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 <josh@joshtriplett.org>
---
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
More information about the Libc-alpha
mailing list