[v2] nptl: pthread_getattr_np: Read /proc/self/maps in BUFSIZ chunks, avoid fstat
Checks
| Context |
Check |
Description |
| redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
| linaro-tcwg-bot/tcwg_glibc_build--master-arm |
success
|
Build passed
|
| redhat-pt-bot/TryBot-32bit |
success
|
Build for i686
|
| linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_glibc_check--master-arm |
success
|
Test passed
|
Commit Message
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(+)
Comments
Am Donnerstag, 23. Juli 2026, 13:57:47 Japanische Normalzeit schrieb Josh Triplett:
> 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.
After the release please. TIA
>
> 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);
> }
> }
>
>
@@ -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);
}
}