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

Josh Triplett josh@joshtriplett.org
Wed Jul 22 23:04:41 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`.

This is part of the stack setup at startup for almost every Rust program.

Signed-off-by: Josh Triplett <josh@joshtriplett.org>
---

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 | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
index b0d2343a59..c1ed453f30 100644
--- a/nptl/pthread_getattr_np.c
+++ b/nptl/pthread_getattr_np.c
@@ -88,10 +88,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 && 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 +176,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