[libc-commits] [libc] [libc] Add pthread_getstack_np extension (PR #217049)

Alexey Samsonov via libc-commits libc-commits at lists.llvm.org
Thu Aug 20 20:55:46 PDT 2026


https://github.com/vonosmas updated https://github.com/llvm/llvm-project/pull/217049

>From f99a42386b1122e6b381a936814f6ddfbcd99a86 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Tue, 18 Aug 2026 13:01:12 +0000
Subject: [PATCH 1/3] [libc] Add pthread_getstack_np extension

The function returns the stack (size and address) of the given thread,
much like a combination of pthread_getattr_np+pthread_attr_getstack.
However, unlike that combination, this function is guaranteed to be
async-signal-safe. I'm adding it because guaranteeing
async-signal-safety for pthread_getattr_np is tricky because of the
increased scope. In particular, it's hard to avoid memory allocation as
that function would need to store CPU affinity for an unknown number of
CPUs.

I'm not trying to emulate OpenBSD's
[pthread_stackseg_np](https://man.openbsd.org/pthread_stackseg_np.3) as
we discussed previously, because the function has an unusual interface
(it returns the stack through a stack_t, but it has ss_sp point to the
top of the stack instead of the base). It also does not claim to be
async-signal-safe. With a view towards a standardization attempt, I
tried to design something that fits in with the existing APIs.  Note
that this does not mean that the design is final, and I am open to
changing the interface (before or after submitting this patch).

The trickiest part of this patch is what to do with the main thread,
which has a kernel-allocated dynamically-growing stack. Glibc's
pthread_getattr_np computes this values by parsing /proc/$PID/maps,
which is another reason this function is not async-signal-safe (and it
also requires /proc to be mounted). While one can parse /proc in an
async-signal-safe way, doing that is not trivial, and it still requires
/proc.

Other options I've considered is using `getrlimit(RLIMIT_STACK`
(captured either at application startup or at the time of the
pthread_getstack_np call), but I rejected that because that does not
return an accurate value -- it can both under- (if the limit is
increased) or over-estimate (if the limit decreases or something is
mapped in the way of the expanding stack) the size of the stack.

This is why I came to believe that the most correct option is to return
"I don't know" -- a special constant (PTHREAD_STACK_DYNAMIC_NP)
indicating that the stack size may change (another "quirk" of the main
thread).

I calculate the top of the stack by taking the value of AT_EXECFN
(normally the first thing placed on the stack by the kernel). I do this
in order to best match the behavior of the function for non-main thread
(where the returned region typically includes other objects stored on
the "stack" (e.g. the TLS data).
---
 libc/config/linux/aarch64/entrypoints.txt     |   1 +
 libc/config/linux/riscv/entrypoints.txt       |   1 +
 libc/config/linux/x86_64/entrypoints.txt      |   1 +
 .../include/llvm-libc-macros/pthread-macros.h |   3 +
 libc/include/pthread.yaml                     |  12 ++
 libc/src/pthread/CMakeLists.txt               |  15 +++
 libc/src/pthread/pthread_getstack_np.cpp      |  36 +++++
 libc/src/pthread/pthread_getstack_np.h        |  44 ++++++
 libc/startup/linux/CMakeLists.txt             |   2 +
 libc/startup/linux/do_start.cpp               |  14 +-
 .../integration/src/pthread/CMakeLists.txt    |  22 +++
 .../src/pthread/pthread_getstack_np_test.cpp  | 125 ++++++++++++++++++
 12 files changed, 275 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/pthread/pthread_getstack_np.cpp
 create mode 100644 libc/src/pthread/pthread_getstack_np.h
 create mode 100644 libc/test/integration/src/pthread/pthread_getstack_np_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 9c9c5fb1d10b5..98aaa00b52dd7 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1106,6 +1106,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_getname_np
     libc.src.pthread.pthread_getschedparam
     libc.src.pthread.pthread_getspecific
+    libc.src.pthread.pthread_getstack_np
     libc.src.pthread.pthread_getthreadid_np
     libc.src.pthread.pthread_getunique_np
     libc.src.pthread.pthread_join
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index c3feab0a82209..5f03a202dbc02 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1298,6 +1298,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_getname_np
     libc.src.pthread.pthread_getschedparam
     libc.src.pthread.pthread_getspecific
+    libc.src.pthread.pthread_getstack_np
     libc.src.pthread.pthread_getthreadid_np
     libc.src.pthread.pthread_getunique_np
     libc.src.pthread.pthread_join
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index c13c495111200..8a08bc6c4b22a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1303,6 +1303,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_getname_np
     libc.src.pthread.pthread_getschedparam
     libc.src.pthread.pthread_getspecific
+    libc.src.pthread.pthread_getstack_np
     libc.src.pthread.pthread_getthreadid_np
     libc.src.pthread.pthread_getunique_np
     libc.src.pthread.pthread_join
diff --git a/libc/include/llvm-libc-macros/pthread-macros.h b/libc/include/llvm-libc-macros/pthread-macros.h
index d6518189f1ccb..58717200b5fd6 100644
--- a/libc/include/llvm-libc-macros/pthread-macros.h
+++ b/libc/include/llvm-libc-macros/pthread-macros.h
@@ -77,4 +77,7 @@
 #define PTHREAD_RWLOCK_PREFER_WRITER_NP 1
 #define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 2
 
+// llvm libc extensions
+#define PTHREAD_STACK_DYNAMIC_NP 0
+
 #endif // LLVM_LIBC_MACROS_PTHREAD_MACRO_H
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index c3e967c67ee8f..784b1c207b9f7 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -50,6 +50,10 @@ macros:
     standards:
       - gnu
     macro_header: pthread-macros.h
+  - macro_name: "PTHREAD_STACK_DYNAMIC_NP"
+    standards:
+      - llvm_libc_ext
+    macro_header: pthread-macros.h
 types:
   - type_name: pthread_t
   - type_name: pthread_once_t
@@ -242,6 +246,14 @@ functions:
     return_type: void *
     arguments:
       - type: pthread_key_t
+  - name: pthread_getstack_np
+    standards:
+      - llvm_libc_ext
+    return_type: int
+    arguments:
+      - type: pthread_t
+      - type: void **__restrict
+      - type: size_t *__restrict
   - name: pthread_join
     return_type: int
     arguments:
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 17bfc95792a84..94af498779291 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -967,3 +967,18 @@ add_entrypoint_object(
     libc.src.__support.macros.null_check
     libc.src.__support.threads.thread
 )
+
+add_entrypoint_object(
+  pthread_getstack_np
+  SRCS
+    pthread_getstack_np.cpp
+  HDRS
+    pthread_getstack_np.h
+  DEPENDS
+    libc.hdr.types.pthread_t
+    libc.hdr.types.size_t
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.null_check
+    libc.src.__support.threads.thread
+)
diff --git a/libc/src/pthread/pthread_getstack_np.cpp b/libc/src/pthread/pthread_getstack_np.cpp
new file mode 100644
index 0000000000000..09f3294bfb334
--- /dev/null
+++ b/libc/src/pthread/pthread_getstack_np.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of the pthread_getstack_np function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pthread/pthread_getstack_np.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/threads/thread.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
+              "Mismatch between pthread_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(int, pthread_getstack_np,
+                   (pthread_t th, void **__restrict stackaddr,
+                    size_t *__restrict stacksize)) {
+  LIBC_CRASH_ON_NULLPTR(stackaddr);
+  LIBC_CRASH_ON_NULLPTR(stacksize);
+  auto *thread = reinterpret_cast<Thread *>(&th);
+  *stackaddr = thread->attrib->stack;
+  *stacksize = thread->attrib->stacksize;
+  return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_getstack_np.h b/libc/src/pthread/pthread_getstack_np.h
new file mode 100644
index 0000000000000..9990f9147c5fa
--- /dev/null
+++ b/libc/src/pthread/pthread_getstack_np.h
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for pthread_getstack_np function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSTACK_NP_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSTACK_NP_H
+
+#include "hdr/types/pthread_t.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Returns the stack address and stack size of the thread referred to by the
+// thread ID `th` in the buffers pointed to by `stackaddr` and `stacksize`,
+// respectively. `stackaddr` points to the lowest address in the region,
+// regardless of the direction of stack growth.
+//
+// If the size of the stack is not fixed (stack can grow dynamically), the
+// stacksize argument is set to PTHREAD_STACK_DYNAMIC_NP (0) and stackaddr
+// points to the base of the stack (as if it was describing the empty stack
+// range after popping its entire contents). This allows one to compute the
+// currently used part of the stack by taking the range between this value and
+// the current stack pointer. This behavior is specific to the main thread.
+//
+// On success, the function returns zero; on error, it returns a nonzero error
+// number. Currently, the function always succeeds.
+//
+// This function is async-signal-safe.
+int pthread_getstack_np(pthread_t th, void **__restrict stackaddr,
+                        size_t *__restrict stacksize);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSTACK_NP_H
diff --git a/libc/startup/linux/CMakeLists.txt b/libc/startup/linux/CMakeLists.txt
index 647de99a32125..11aa97ef97c40 100644
--- a/libc/startup/linux/CMakeLists.txt
+++ b/libc/startup/linux/CMakeLists.txt
@@ -112,7 +112,9 @@ add_object_library(
     libc.config.app_h
     libc.hdr.elf_proxy
     libc.hdr.link_macros
+    libc.hdr.pthread_macros
     libc.hdr.stdint_proxy
+    libc.hdr.sys_auxv_macros
     libc.hdr.sys_mman_macros
     libc.hdr.types.struct_link_map
     libc.hdr.types.struct_r_debug
diff --git a/libc/startup/linux/do_start.cpp b/libc/startup/linux/do_start.cpp
index 85f46a8e97fcf..7db9de59b0ab0 100644
--- a/libc/startup/linux/do_start.cpp
+++ b/libc/startup/linux/do_start.cpp
@@ -9,7 +9,9 @@
 #include "config/linux/app.h"
 #include "hdr/elf_proxy.h"
 #include "hdr/link_macros.h"
+#include "hdr/pthread_macros.h"
 #include "hdr/stdint_proxy.h"
+#include "hdr/sys_auxv_macros.h"
 #include "hdr/sys_mman_macros.h"
 #include "hdr/types/struct_link_map.h"
 #include "hdr/types/struct_r_debug.h"
@@ -25,7 +27,6 @@
 #include "src/unistd/environ.h"
 #include "startup/linux/gnu_property_section.h"
 #include "startup/linux/irelative.h"
-
 #include <sys/syscall.h>
 
 extern "C" int main(int argc, char **argv, char **envp);
@@ -110,6 +111,7 @@ static TLSDescriptor tls;
   uintptr_t program_hdr_count = 0;
   unsigned long hwcap = 0;
   unsigned long hwcap2 = 0;
+  const char *execfn = nullptr;
   auxv::Vector::initialize_unsafe(
       reinterpret_cast<const auxv::Entry *>(env_end_marker + 1));
   auxv::Vector auxvec;
@@ -130,10 +132,20 @@ static TLSDescriptor tls;
     case AT_HWCAP2:
       hwcap2 = aux_entry.val;
       break;
+    case AT_EXECFN:
+      execfn = reinterpret_cast<const char *>(aux_entry.val);
+      break;
     default:
       break; // TODO: Read other useful entries from the aux vector.
     }
   }
+  // AT_EXECFN is typically the last thing on the stack. Round it up to the
+  // next page boundary.
+  uintptr_t stack_addr =
+      (reinterpret_cast<uintptr_t>(execfn) + app.page_size - 1) &
+      ~(app.page_size - 1);
+  main_thread_attrib.stack = reinterpret_cast<void *>(stack_addr);
+  main_thread_attrib.stacksize = PTHREAD_STACK_DYNAMIC_NP;
 
   intptr_t base = 0;
   app.tls.size = 0;
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index cdf791b03a4d9..1efcaf76f35ff 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -292,6 +292,28 @@ add_integration_test(
     libc.src.__support.CPP.new
 )
 
+add_integration_test(
+  pthread_getstack_np_test
+  SUITE
+    libc-pthread-integration-tests
+  SRCS
+    pthread_getstack_np_test.cpp
+  DEPENDS
+    libc.hdr.pthread_macros
+    libc.hdr.stdint_proxy
+    libc.hdr.sys_mman_macros
+    libc.include.pthread
+    libc.src.pthread.pthread_attr_destroy
+    libc.src.pthread.pthread_attr_init
+    libc.src.pthread.pthread_attr_setstack
+    libc.src.pthread.pthread_create
+    libc.src.pthread.pthread_getstack_np
+    libc.src.pthread.pthread_join
+    libc.src.pthread.pthread_self
+    libc.src.sys.mman.mmap
+    libc.src.sys.mman.munmap
+)
+
 add_integration_test(
   pthread_setschedparam_test
   SUITE
diff --git a/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp b/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp
new file mode 100644
index 0000000000000..0a5435df1b0a5
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp
@@ -0,0 +1,125 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Integration tests for pthread_getstack_np.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/pthread_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "hdr/sys_mman_macros.h"
+#include "src/pthread/pthread_attr_destroy.h"
+#include "src/pthread/pthread_attr_init.h"
+#include "src/pthread/pthread_attr_setstack.h"
+#include "src/pthread/pthread_create.h"
+#include "src/pthread/pthread_getstack_np.h"
+#include "src/pthread/pthread_join.h"
+#include "src/pthread/pthread_self.h"
+#include "src/sys/mman/mmap.h"
+#include "src/sys/mman/munmap.h"
+#include "test/IntegrationTest/test.h"
+
+#include <linux/param.h> // For EXEC_PAGESIZE.
+#include <pthread.h>
+
+static void check_readable(const void *start, size_t size) {
+  auto *bytes = static_cast<const volatile char *>(start);
+  for (size_t offset = 0; offset < size; offset += EXEC_PAGESIZE)
+    (void)bytes[offset];
+  if (size > 0)
+    (void)bytes[size - 1];
+}
+
+static void *child_func(void *) {
+  void *stackaddr = nullptr;
+  size_t stacksize = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getstack_np(LIBC_NAMESPACE::pthread_self(),
+                                                &stackaddr, &stacksize),
+            0);
+  ASSERT_NE(stackaddr, static_cast<void *>(nullptr));
+  ASSERT_NE(stacksize, static_cast<size_t>(PTHREAD_STACK_DYNAMIC_NP));
+  ASSERT_TRUE(stacksize > 0);
+
+  uintptr_t local_var_addr = reinterpret_cast<uintptr_t>(&stackaddr);
+  uintptr_t stack_low = reinterpret_cast<uintptr_t>(stackaddr);
+  uintptr_t stack_high = stack_low + stacksize;
+  ASSERT_TRUE(local_var_addr >= stack_low);
+  ASSERT_TRUE(local_var_addr < stack_high);
+
+  check_readable(stackaddr, stacksize);
+
+  return nullptr;
+}
+
+static void test_main_thread() {
+  void *stackaddr = nullptr;
+  size_t stacksize = 1234;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getstack_np(LIBC_NAMESPACE::pthread_self(),
+                                                &stackaddr, &stacksize),
+            0);
+  ASSERT_NE(stackaddr, static_cast<void *>(nullptr));
+  ASSERT_EQ(stacksize, static_cast<size_t>(PTHREAD_STACK_DYNAMIC_NP));
+  ASSERT_EQ(reinterpret_cast<uintptr_t>(stackaddr) % EXEC_PAGESIZE,
+            static_cast<uintptr_t>(0));
+
+  // Stack grows downwards on linux, so local variables on the main thread stack
+  // should be at addresses lower than the initial stack top address.
+  uintptr_t local_var_addr = reinterpret_cast<uintptr_t>(&stackaddr);
+  ASSERT_TRUE(local_var_addr < reinterpret_cast<uintptr_t>(stackaddr));
+
+  // The stack region between the current stack frame and the top of the stack
+  // should be readable.
+  check_readable(&stackaddr,
+                 reinterpret_cast<uintptr_t>(stackaddr) - local_var_addr);
+}
+
+static void test_child_thread_default() {
+  pthread_t th;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&th, nullptr, child_func, nullptr),
+            0);
+  void *retval = nullptr;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th, &retval), 0);
+}
+
+static void test_child_thread_custom_stack() {
+  size_t custom_stacksize = PTHREAD_STACK_MIN * 2;
+  void *custom_stack =
+      LIBC_NAMESPACE::mmap(nullptr, custom_stacksize, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(custom_stack, MAP_FAILED);
+  ASSERT_NE(custom_stack, static_cast<void *>(nullptr));
+
+  pthread_attr_t attr;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_init(&attr), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_setstack(&attr, custom_stack,
+                                                  custom_stacksize),
+            0);
+
+  pthread_t th;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&th, &attr, child_func, nullptr), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_attr_destroy(&attr), 0);
+
+  void *stackaddr = nullptr;
+  size_t stacksize = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getstack_np(th, &stackaddr, &stacksize), 0);
+  ASSERT_EQ(stackaddr, custom_stack);
+  ASSERT_EQ(stacksize, custom_stacksize);
+  check_readable(stackaddr, stacksize);
+
+  void *retval = nullptr;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th, &retval), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::munmap(custom_stack, custom_stacksize), 0);
+}
+
+TEST_MAIN() {
+  test_main_thread();
+  test_child_thread_default();
+  test_child_thread_custom_stack();
+  return 0;
+}

>From 68e404b1ddb5aeedfcfabe37186007c1ab69a6b1 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 19 Aug 2026 07:18:22 +0000
Subject: [PATCH 2/3] use sysconf for page size

---
 libc/test/integration/src/pthread/CMakeLists.txt       |  2 +-
 .../src/pthread/pthread_getstack_np_test.cpp           | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 1efcaf76f35ff..19d02bbc3f0c4 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -302,7 +302,6 @@ add_integration_test(
     libc.hdr.pthread_macros
     libc.hdr.stdint_proxy
     libc.hdr.sys_mman_macros
-    libc.include.pthread
     libc.src.pthread.pthread_attr_destroy
     libc.src.pthread.pthread_attr_init
     libc.src.pthread.pthread_attr_setstack
@@ -312,6 +311,7 @@ add_integration_test(
     libc.src.pthread.pthread_self
     libc.src.sys.mman.mmap
     libc.src.sys.mman.munmap
+    libc.src.unistd.sysconf
 )
 
 add_integration_test(
diff --git a/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp b/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp
index 0a5435df1b0a5..a7bf655070446 100644
--- a/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp
+++ b/libc/test/integration/src/pthread/pthread_getstack_np_test.cpp
@@ -23,14 +23,13 @@
 #include "src/pthread/pthread_self.h"
 #include "src/sys/mman/mmap.h"
 #include "src/sys/mman/munmap.h"
+#include "src/unistd/sysconf.h"
 #include "test/IntegrationTest/test.h"
 
-#include <linux/param.h> // For EXEC_PAGESIZE.
-#include <pthread.h>
-
 static void check_readable(const void *start, size_t size) {
+  size_t pagesize = LIBC_NAMESPACE::sysconf(_SC_PAGESIZE);
   auto *bytes = static_cast<const volatile char *>(start);
-  for (size_t offset = 0; offset < size; offset += EXEC_PAGESIZE)
+  for (size_t offset = 0; offset < size; offset += pagesize)
     (void)bytes[offset];
   if (size > 0)
     (void)bytes[size - 1];
@@ -65,7 +64,8 @@ static void test_main_thread() {
             0);
   ASSERT_NE(stackaddr, static_cast<void *>(nullptr));
   ASSERT_EQ(stacksize, static_cast<size_t>(PTHREAD_STACK_DYNAMIC_NP));
-  ASSERT_EQ(reinterpret_cast<uintptr_t>(stackaddr) % EXEC_PAGESIZE,
+  ASSERT_EQ(reinterpret_cast<uintptr_t>(stackaddr) %
+                LIBC_NAMESPACE::sysconf(_SC_PAGESIZE),
             static_cast<uintptr_t>(0));
 
   // Stack grows downwards on linux, so local variables on the main thread stack

>From aeaf30979a27b8fb757d03274e7c00b1f84a8b14 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Thu, 20 Aug 2026 20:55:35 -0700
Subject: [PATCH 3/3] Update libc/src/pthread/pthread_getstack_np.cpp

---
 libc/src/pthread/pthread_getstack_np.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/pthread/pthread_getstack_np.cpp b/libc/src/pthread/pthread_getstack_np.cpp
index 09f3294bfb334..7997e1abdd58d 100644
--- a/libc/src/pthread/pthread_getstack_np.cpp
+++ b/libc/src/pthread/pthread_getstack_np.cpp
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 ///
 /// \file
-/// Implementation of the pthread_getstack_np function.
+/// Implementation of the pthread_getstack_np function (LLVM-libc extension).
 ///
 //===----------------------------------------------------------------------===//
 



More information about the libc-commits mailing list