diff --git a/NEWS b/NEWS index 56c6b581df..1964ebdf81 100644 --- a/NEWS +++ b/NEWS @@ -9,7 +9,9 @@ Version 2.45 Major new features: - [Add new features here] +* The function pthread_getstack_np has been added. It returns the stack + bounds of a thread, like pthread_attr_getstack applied to the result of + pthread_getattr_np, in a async-signal-safe manner. Deprecated and removed features, and other changes affecting compatibility: diff --git a/manual/threads.texi b/manual/threads.texi index 0331599bc0..6b04ff3755 100644 --- a/manual/threads.texi +++ b/manual/threads.texi @@ -1148,6 +1148,7 @@ the standard. * Thread CPU Affinity:: Limiting which CPUs can run a thread. * Joining Threads:: Wait for a thread to terminate. * Thread Names:: Changing the name of a thread. +* Thread Stack Bounds:: Determining the stack of a thread. * Single-Threaded:: Detecting single-threaded execution. * Restartable Sequences:: Linux-specific restartable sequences integration. @@ -1352,6 +1353,37 @@ Retrieves the name of thread @var{th}. @manpagefunctionstub{pthread_getname_np, 3} @end deftypefun +@node Thread Stack Bounds +@subsubsection Thread Stack Bounds + +@deftypefun int pthread_getstack_np (pthread_t @var{th}, void **@var{stackaddr}, size_t *@var{stacksize}) +@standards{GNU, pthread.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +Store the lowest usable address of the stack of thread @var{th} in +@code{*@var{stackaddr}} and the number of bytes usable from that +address in @code{*@var{stacksize}}, following the same convention as +@code{pthread_attr_getstack}. The reported size does not include the +guard area. + +For the initial thread the bounds are computed from the current +@code{RLIMIT_STACK} resource limit and the process memory map, so the +result may change if the limit is adjusted. On failure an error code +is returned, for instance @code{ENOENT} when the stack bounds cannot +be determined. + +Unlike @code{pthread_getattr_np}, this function does not acquire any +lock nor allocate memory, and it is async-signal-safe. + +The function reports the stack set up by the kernel or by +@code{pthread_create}. The alternate signal stack is not reflected in +the result, and a handler running on it still gets the bounds of the +thread stack. The alternate stack can be queried with @code{sigaltstack} +(@pxref{Signal Stack}), which is also async-signal-safe. + +Stacks switched by user code, such as with @code{makecontext} or coroutine +libraries, are not tracked by @theglibc{} and are not reported either. +@end deftypefun + @node Single-Threaded @subsubsection Detecting Single-Threaded Execution diff --git a/nptl/Makefile b/nptl/Makefile index 1a284d1dd2..5621756f2c 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -118,6 +118,7 @@ routines = \ pthread_getname \ pthread_getschedparam \ pthread_getspecific \ + pthread_getstack_np \ pthread_gettid_np \ pthread_join \ pthread_join_common \ @@ -328,6 +329,7 @@ tests = \ tst-pthread-timedlock-lockloop \ tst-pthread_exit-nothreads \ tst-pthread_exit-nothreads-static \ + tst-pthread_getstack_np \ tst-pthread_gettid_np \ tst-robust-fork \ tst-robust12 \ diff --git a/nptl/Versions b/nptl/Versions index b813b675b9..43f122e15c 100644 --- a/nptl/Versions +++ b/nptl/Versions @@ -383,6 +383,9 @@ libc { } GLIBC_2.43 { } + GLIBC_2.45 { + pthread_getstack_np; + } GLIBC_PRIVATE { __libc_alloca_cutoff; __lll_lock_wake_private; diff --git a/nptl/pthread_getstack_np.c b/nptl/pthread_getstack_np.c new file mode 100644 index 0000000000..cfd95e1d2f --- /dev/null +++ b/nptl/pthread_getstack_np.c @@ -0,0 +1,53 @@ +/* Get the stack bounds of a thread. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +int +pthread_getstack_np (pthread_t threadid, void **stackaddr, size_t *stacksize) +{ + struct pthread *thread = (struct pthread *) threadid; + + if (__glibc_likely (thread->stackblock != NULL)) + { + /* As per pthread_attr_getstack, the returned size does not include the + guard area. */ + *stacksize = thread->stackblock_size - thread->guardsize; +#if _STACK_GROWS_DOWN + *stackaddr = (char *) thread->stackblock + thread->guardsize; +#else + *stackaddr = thread->stackblock; +#endif + return 0; + } + + /* The initial thread stack is set up by the kernel. */ + void *addr; + size_t size; + int ret = __pthread_main_stack (&addr, &size); + if (ret != 0) + return ret; + +#if _STACK_GROWS_DOWN + *stackaddr = (char *) addr - size; +#else + *stackaddr = addr; +#endif + *stacksize = size; + return 0; +} diff --git a/nptl/tst-pthread_getstack_np.c b/nptl/tst-pthread_getstack_np.c new file mode 100644 index 0000000000..18b80d0460 --- /dev/null +++ b/nptl/tst-pthread_getstack_np.c @@ -0,0 +1,285 @@ +/* Test pthread_getstack_np. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The result must match what pthread_getattr_np plus pthread_attr_getstack + return. */ +static void +check_against_getattr_np (pthread_t thr) +{ + void *stackaddr; + size_t stacksize; + TEST_COMPARE (pthread_getstack_np (thr, &stackaddr, &stacksize), 0); + + pthread_attr_t attr; + TEST_COMPARE (pthread_getattr_np (thr, &attr), 0); + void *attr_stackaddr; + size_t attr_stacksize; + TEST_COMPARE (pthread_attr_getstack (&attr, &attr_stackaddr, + &attr_stacksize), 0); + TEST_COMPARE (pthread_attr_destroy (&attr), 0); + + TEST_VERIFY (stackaddr == attr_stackaddr); + TEST_COMPARE (stacksize, attr_stacksize); +} + +/* A local variable of the calling thread lies within the reported bounds. */ +static void +check_contains_local (void) +{ + void *stackaddr; + size_t stacksize; + TEST_COMPARE (pthread_getstack_np (pthread_self (), &stackaddr, + &stacksize), 0); + char here; + TEST_VERIFY ((uintptr_t) &here >= (uintptr_t) stackaddr); + TEST_VERIFY ((uintptr_t) &here < (uintptr_t) stackaddr + stacksize); +} + +static void * +thread_func (void *arg) +{ + check_against_getattr_np (pthread_self ()); + check_contains_local (); + return NULL; +} + +static void *main_stackaddr; +static size_t main_stacksize; + +/* Runs on the alternate signal stack, the reported bounds are still the ones + of the thread stack. */ +static void +signal_handler (int sig) +{ + void *stackaddr; + size_t stacksize; + TEST_COMPARE (pthread_getstack_np (pthread_self (), &stackaddr, &stacksize), + 0); + TEST_VERIFY (stackaddr == main_stackaddr); + TEST_COMPARE (stacksize, main_stacksize); +} + +/* Mount /proc so that /proc/self/maps cannot be opened, which forces the + AT_EXECFN fallback for the initial thread. */ +static void +check_proc_fallback (void *closure) +{ + if (!support_become_root ()) + { + puts ("info: cannot become root, skipping /proc fallback check"); + return; + } + if (!support_enter_mount_namespace ()) + { + puts ("info: cannot enter mount namespace, skipping /proc fallback" + " check"); + return; + } + if (mount ("none", "/proc", "tmpfs", 0, NULL) != 0) + { + printf ("info: cannot mount tmpfs on /proc (%m), skipping /proc" + " fallback check\n"); + return; + } + + /* The maps reader must now fail, so the fallback is exercised. */ + TEST_VERIFY (open64 ("/proc/self/maps", O_RDONLY) < 0); + + void *stackaddr; + size_t stacksize; + int ret = pthread_getstack_np (pthread_self (), &stackaddr, &stacksize); + + pthread_attr_t attr; + int gret = pthread_getattr_np (pthread_self (), &attr); + TEST_COMPARE (ret, gret); + + if (ret == 0) + { + /* The fallback (downward-growing stack) reproduces the value + computed from the maps, captured in the parent before the fork. */ + void *attr_stackaddr; + size_t attr_stacksize; + TEST_COMPARE (pthread_attr_getstack (&attr, &attr_stackaddr, + &attr_stacksize), 0); + TEST_COMPARE (pthread_attr_destroy (&attr), 0); + TEST_VERIFY (stackaddr == attr_stackaddr); + TEST_COMPARE (stacksize, attr_stacksize); + TEST_VERIFY (stackaddr == main_stackaddr); + TEST_COMPARE (stacksize, main_stacksize); + + char here; + TEST_VERIFY ((uintptr_t) &here >= (uintptr_t) stackaddr); + TEST_VERIFY ((uintptr_t) &here < (uintptr_t) stackaddr + stacksize); + } + else + { + /* Configurations without the fallback (e.g. an upward-growing + stack) report the failure instead of a stack. */ + printf ("info: no /proc fallback in this configuration (ret %d)\n", + ret); + TEST_COMPARE (ret, ENOENT); + } +} + + +/* Read the current [stack] vma from /proc/self/maps. */ +static bool +stack_vma (uintptr_t *lo, uintptr_t *hi) +{ + FILE *f = fopen ("/proc/self/maps", "r"); + if (f == NULL) + return false; + bool found = false; + char line[512]; + while (fgets (line, sizeof line, f) != NULL) + if (strstr (line, "[stack]") != NULL + && sscanf (line, "%" SCNxPTR "-%" SCNxPTR, lo, hi) == 2) + { + found = true; + break; + } + fclose (f); + return found; +} + +static __attribute__ ((noinline)) bool +stack_grows_down_1 (uintptr_t outer) +{ + char inner; + return (uintptr_t) &inner < outer; +} + +static bool +stack_grows_down (void) +{ + char outer; + return stack_grows_down_1 ((uintptr_t) &outer); +} + +/* The kernel does not grow the stack into the guard gap above the mapping + below it. With a mapping planted within that distance below the current + vma the stack can not grow at all, so the reported lowest address must be + the current vma bottom rather than the end of the planted mapping. This + must be the last check, since afterwards the stack can not grow. */ +static void +check_stack_guard_gap (void) +{ + if (!stack_grows_down ()) + { + puts ("info: stack grows up, skipping guard gap check"); + return; + } + uintptr_t lo, hi; + if (!stack_vma (&lo, &hi)) + { + puts ("info: no [stack] in /proc/self/maps, skipping guard gap check"); + return; + } + + long pagesz = sysconf (_SC_PAGESIZE); + uintptr_t planted = (lo - 100 * 1024) & -(uintptr_t) pagesz; + void *m = mmap ((void *) planted, pagesz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0); + if (m == MAP_FAILED) + { + printf ("info: cannot map below the stack (%m), skipping guard gap" + " check\n"); + return; + } + TEST_VERIFY ((uintptr_t) m == planted); + + void *stackaddr; + size_t stacksize; + TEST_COMPARE (pthread_getstack_np (pthread_self (), &stackaddr, &stacksize), + 0); + /* The vma may only have grown down since it was read. */ + uintptr_t lo2, hi2; + TEST_VERIFY (stack_vma (&lo2, &hi2)); + TEST_VERIFY (lo2 <= (uintptr_t) stackaddr && (uintptr_t) stackaddr <= lo); + TEST_VERIFY ((uintptr_t) stackaddr > planted + pagesz); + + check_against_getattr_np (pthread_self ()); +} + +static int +do_test (void) +{ + check_against_getattr_np (pthread_self ()); + check_contains_local (); + TEST_COMPARE (pthread_getstack_np (pthread_self (), &main_stackaddr, + &main_stacksize), 0); + + /* A thread with the default stack size, queried both by itself and + by another thread. */ + { + pthread_t thr = xpthread_create (NULL, thread_func, NULL); + check_against_getattr_np (thr); + xpthread_join (thr); + } + + /* A thread with a non-default stack size. */ + { + pthread_attr_t attr; + xpthread_attr_init (&attr); + xpthread_attr_setstacksize (&attr, 256 * 1024); + xpthread_join (xpthread_create (&attr, thread_func, NULL)); + xpthread_attr_destroy (&attr); + } + + /* From a signal handler running on the alternate signal stack. */ + { + struct support_stack altstack = support_stack_alloc (SIGSTKSZ); + stack_t ss = { .ss_sp = altstack.stack, .ss_size = altstack.size }; + TEST_COMPARE (sigaltstack (&ss, NULL), 0); + xsigaction (SIGUSR1, + &(struct sigaction) { + .sa_handler = signal_handler, + .sa_flags = SA_ONSTACK }, + NULL); + xraise (SIGUSR1); + support_stack_free (&altstack); + } + + /* The initial thread fallback when /proc is not accessible. */ + support_isolate_in_subprocess (check_proc_fallback, NULL); + + check_stack_guard_gap (); + + return 0; +} + +#include diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h index 95c0eb7e03..05e99845bf 100644 --- a/sysdeps/nptl/pthread.h +++ b/sysdeps/nptl/pthread.h @@ -1320,6 +1320,12 @@ extern int pthread_getcpuclockid (pthread_t __thread_id, #ifdef __USE_GNU /* Return the Linux TID for THREAD_ID. Returns -1 on failure. */ extern pid_t pthread_gettid_np (pthread_t __thread_id); + +/* Store the lowest usable address of the stack of THREAD_ID in *STACKADDR and + the number of usable bytes from that address in *STACKSIZE. */ +extern int pthread_getstack_np (pthread_t __thread_id, + void **__stackaddr, size_t *__stacksize) + __THROW __nonnull ((2, 3)); #endif diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index b66eed99d1..c93e82652b 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -563,6 +563,8 @@ sysdep_routines += \ spawnattr_setcgroup_np \ # sysdep_routines +CFLAGS-procutils.c += -fexceptions -fasynchronous-unwind-tables + tests += \ tst-affinity \ tst-affinity-pid \ diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 3156688add..98709d2629 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2775,3 +2775,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 8af5b0b581..706b936d9e 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3122,6 +3122,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index 35fcef2cc4..da979d7c6e 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2536,3 +2536,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index a6c6b951bf..aa1355c769 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2828,6 +2828,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index e76015fe66..1d58ccb253 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2825,6 +2825,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 1fb7cdcad5..169145176b 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2812,3 +2812,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 0710ccecf9..964f06daba 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2849,6 +2849,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index 3afe3a88eb..a77d27f2bb 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3032,6 +3032,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist index 7c6d7055c3..b2ef03ff16 100644 --- a/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist @@ -2287,3 +2287,4 @@ GLIBC_2.44 wprintf F GLIBC_2.44 write F GLIBC_2.44 writev F GLIBC_2.44 wscanf F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index c2b3a66d3a..8ec209bf27 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2296,3 +2296,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index d6855131e8..eccbd04296 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2808,6 +2808,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 4e3fe9c42f..4721e8e983 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2975,6 +2975,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index 29f0c5f954..dcd444a2ce 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2861,3 +2861,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 2ef62838f7..29a94f43fc 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2858,3 +2858,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 031e8961ac..94e5afff89 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2938,6 +2938,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index 8dc99d81b4..f4fe1b36cf 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2936,6 +2936,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 054c5b6391..6546b9d204 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2944,6 +2944,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 13f0148bc0..3fb80ff9bb 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2846,6 +2846,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index e7ffe07dd8..332829cf0b 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2286,3 +2286,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index dea4b20f05..42ff2ef985 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3165,6 +3165,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index b45e127463..d48eb09369 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3210,6 +3210,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 942cf6a027..99c1a046c0 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2919,6 +2919,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 65d78e5076..8ff2eabecd 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2995,3 +2995,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/procutils.c b/sysdeps/unix/sysv/linux/procutils.c index c254fa4a78..56e3fa21ad 100644 --- a/sysdeps/unix/sysv/linux/procutils.c +++ b/sysdeps/unix/sysv/linux/procutils.c @@ -16,6 +16,7 @@ License along with the GNU C Library; if not, see . */ +#include #include #include #include @@ -109,6 +110,12 @@ next_line (struct line_reader *lr, char **r) } } +static void +close_handler (void *arg) +{ + __close_nocancel_nostatus (*(int *) arg); +} + enum procutils_read_result_t __libc_procutils_read_file (const char *filename, char *buffer, size_t buffer_size, procutils_closure_t closure, @@ -127,7 +134,11 @@ __libc_procutils_read_file (const char *filename, char *buffer, if (lr.fd == -1) return procutils_read_error; + /* The cleanup handler is required to avoid leaking the descriptor if + the thread is asynchronously canceled. */ enum next_line_result_t r; + __libc_cleanup_push (close_handler, &lr.fd); + char *line; while ((r = next_line (&lr, &line)) == next_line_ok) if (closure (line, arg) != 0) @@ -135,6 +146,8 @@ __libc_procutils_read_file (const char *filename, char *buffer, __close_nocancel_nostatus (lr.fd); + __libc_cleanup_pop (0); + if (r == next_line_error) return procutils_read_error; return r == next_line_ok ? procutils_read_stop : procutils_read_eof; diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index dcab30d72e..2a7b4cc5b9 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2539,3 +2539,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 796ef35e26..bfc7c72113 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2739,3 +2739,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F diff --git a/sysdeps/unix/sysv/linux/s390/libc.abilist b/sysdeps/unix/sysv/linux/s390/libc.abilist index 8f2350ee0b..836850107a 100644 --- a/sysdeps/unix/sysv/linux/s390/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/libc.abilist @@ -2956,6 +2956,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index 7aa98c5aed..3ed78f5f0b 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2855,6 +2855,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index 6bd4f8f63a..4771b5ca2d 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2852,6 +2852,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index b52cab2a35..91e6722b52 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3186,6 +3186,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index ff99cd4f21..7c72b93287 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2822,6 +2822,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 306cd627fd..207f868422 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2771,6 +2771,7 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 8b9c448742..f17a31d3f0 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2790,3 +2790,4 @@ GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F +GLIBC_2.45 pthread_getstack_np F