|
|
Message-ID: <CAJt8pk898VS4ugU5cFpi0+NGxaNfeWRzdvvcPS=y0FdXAQA_Ug@mail.gmail.com> Date: Wed, 9 Sep 2026 10:35:39 +0200 From: Pavel Labath <labath@...gle.com> To: libc-coord@...ts.openwall.com Subject: An async-signal-safe way to get thread’s stack Hello libc-coord, there are many situations where a thread needs to know its stack boundaries, but there is no standard way to get that, leading many projects to maintain their own web of #ifdefs for this purpose (e.g. https://searchfox.org/firefox-main/source/js/src/util/NativeStack.cpp and https://github.com/WebKit/WebKit/blob/b008d85bb026f03ac31665a9f99536906c88bf77/Source/WTF/wtf/StackBounds.cpp). In Linux, we have pthread_getattr_np as a de-facto standard. This (in conjunction with pthread_attr_getstack) lets us get the stack boundary, but this approach has the problem of not working in async-signal contexts. pthread_getattr_np is a complicated function. E.g., the GLIBC implementation takes locks, opens files and allocates memory, all of which are async-signal-unsafe operations. A lot of this complexity is due to the main thread, which has a kernel-managed dynamically expanding stack. Yet, there are use cases where one needs this information from inside a signal handler. E.g. an (in process) unwinder or a profiler can use this information to read the stack quickly, without risking a SIGSEGV. There is some prior art in this space. One is pthread_stackseg_np in OpenBSD <https://man.openbsd.org/pthread_stackseg_np.3> <https://github.com/openbsd/src/blob/88e222c6018bdf12ed942519539f8780ce322467/lib/librthread/rthread_np.c#L83>. The function isn’t documented as async-signal-safe, though the implementation /mostly/ appears to be so (the first call to the function initializes some data structures, which likely isn’t safe). The implementation uses RLIMIT_STACK to get the stack size of the main thread. The function also uses stack_t in an unusual way (returning the bottom of the stack instead of the lowest address). We also have stack_getbounds on Solaris <https://docs.oracle.com/cd/E88353_01/html/E37843/stack-getbounds-3c.html> <https://github.com/kofemann/opensolaris/blob/master/usr/src/lib/libc/port/gen/stack.c#L39>. The function is documented as async-signal-safe. The stack bounds for the main thread are initialized at startup using RLIMIT_STACK, with ss_size set to zero for RLIM_INFINITY. I’ve added a pthread_getstack_np extension <https://github.com/llvm/llvm-project/pull/217049> to LLVM-libc. The function has a pthread_attr_getstack-like API. For the main thread it behaves similar to Solaris stack_getbounds, except that it sets the size to zero (PTHREAD_STACK_DYNAMIC_NP) unconditionally. However, please don’t take this email as a request to adopt this API. This is something that we created for experimentation and I’d be happy to change that API if we come up with a better one. In fact, I am hoping that’s exactly what will happen. Would it be possible to coordinate on a common API to perform this operation? I suspect the main point of contention will be the main thread, as all of the mentioned approaches have their downsides. The two properties I’m looking for are async-safety and a guarantee that returned info identifies the readable portion of the stack. Comments?
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.