2

On Windows I can get the stack-boundaries from the Thread Information Block like this:

 void *stackBottom, *stackTop; #if defined _MSC_VER void **teb = (void **)NtCurrentTeb(); stackBottom = teb[2]; stackTop = teb[1]; #else #error "unsupported platform" #endif 

... or with GetCurrentThreadStackLimits(). But GetCurrentThreadStackLimits() doesn't return the boundaries of the currently allocated Stack (Windows does overcommit stacks) but the whole address-range of the stack to where it ultimately might extend.

Is something similar like the above possible with Linux ?

[EDIT] I've got it:

#include <iostream> #include <pthread.h> using namespace std; int main() { pthread_attr_t attrs; if( pthread_getattr_np( pthread_self(), &attrs ) != 0 ) return -1; void *stackAddr; size_t stackSize; if( pthread_attr_getstack( &attrs, &stackAddr, &stackSize ) != 0 ) return -1; cout << "stack-address: " << stackAddr << endl; cout << "stack-size: " << stackSize << endl; cout << "var-addr: " << (void *)&stackAddr << endl; } 

This determines the base-address of the stack and its size. As var_addr shows stackAddr is the lower bound, i.e. the stack begins at (char *)stackAddr + stackSize. The next thing I'm going to do is to determine the performance of that code.

9
  • see this So answer: stackoverflow.com/a/23253635/5639126 Commented Jul 27, 2020 at 9:00
  • 5 min network search resulted in grep -A 1 stack /proc/$$/smaps Commented Jul 27, 2020 at 10:04
  • Does this answer your question? How do I find the maximum stack size? Commented Jul 27, 2020 at 10:05
  • 1: secretsquirrel: using a proc filesystem-access for this purpose is too slow. 2: KamilCuk: same as with secretsquirrel 3: KamilCuk: don't want to get the maximum stack size but the stack-boundaries of a certain stack or the current stack. Commented Jul 27, 2020 at 10:59
  • There is also linux.die.net/man/3/pthread_attr_getstacksize Commented Jul 27, 2020 at 11:23

1 Answer 1

0

The pthread_getattr_np() appears to be glibc specific and judging by its strace, it also opens and parses /proc/self/maps (not super slow but a bunch of syscalls in there).

I figured out it can be done with just one cheap syscall: getrlimit to get the size of the stack. The head of the stack is then tail minus size (downward growth) and tail can be obtained from extern char **environ;.

This LWN article https://lwn.net/Articles/631631/ describes the initial linux stack layout. It starts with (or ends with considering the downward growth of stacks):

  • a null pointer (4-8 zero bytes) at the very tail of the stack
  • the executable's file name
  • environment variable strings

Working backwards from that you can get to the tail/bottom.

#include <string.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/resource.h> void perrorAndExit(char const*X) { perror(X); _exit(1); } int main(int C, char **V){ //print maps data to check the later result: close(3); int mapsfd = open("/proc/self/maps",O_RDONLY); if(0>mapsfd) perrorAndExit("open"); system("cat /dev/fd/3 | grep stack"); //shows higher head (indicating a smaller stack) than what's accessible //I guess it shows only the faulted-in part of the stack struct rlimit rlim; if(0>getrlimit(RLIMIT_STACK,&rlim)) perrorAndExit("getrlimit"); extern char **environ; //get the last envvar pointer, which points to the highest addr envvar string char **ee=environ; for (;*ee;ee++){}--ee; char *filename = *ee + strlen(*ee) + 1; //move past it into the filename char *null = filename + strlen(filename)+1; //move filename into the null pointer char *tail = null + sizeof(void*); //get the tail char *head = tail - rlim.rlim_cur; printf("%zu-%lx\n", (unsigned long)rlim.rlim_cur, (unsigned long)tail); head[0] = 0; //still accessible //head[-1] = 0; //segfaults return 0; } 

This of course works just for the main stack (sufficient for my use case, might not be for yours).

Sign up to request clarification or add additional context in comments.

3 Comments

Doesn't getrlimit return the default stack size of the process and not the stack size of the thread, which may be set to an indivudal value ?
@BonitaMontero Yeah, this is not for when you're in a pthread. If you're the one to invoke the phtread_create call, then that case it simple: give it your own stack for which you already know the bounds (at least that's what I'm doing). For the main stack the above works (seemingly, also on MacOS with some rounding) and is faster than a SIGSEGV protected stackwalk until stackoverflow.
I just want to get the limits from inside the thread and not with external help. And I even want to get the limits if the stack-size is defaulted.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.