About alloca()
The C programming language offers a nifty feature for temporary memory allocation - alloca(3C). The advantage of alloca() over memory allocation via the heap is compelling:
- No need to perform expensive list/tree searches in heap management structures
- No need to execute expensive sbrk() syscalls to grow the heap
- No need to perform locking in MT applications
- No need to perform garbage collection - automatic free on function exit
Typical problems resulting from the use of alloca()
Unfortunately, alloca() has one critical flaw - it cannot fail. Or rather, it will not fail gracefully. It always returns a buffer address. If the buffer was too large, stack memory runs out and nasty things will happen to your application:
- The attempt to access the buffer will, at some offset into the buffer - crash.
- Making another function call will end up writing data onto the stack - crash.
- Since other local variables of the function having done alloca() might've been relocated, they possibly are no longer backed by stack memory; using any of these locals then means - crash.
From a diagnosability point of view, the crash will simply be a SIGSEGV or SIGBUS (invalid address / access to address that isn't mapped), and it will not necessarily happen close to the location in the code where alloca() was called. To complicate things further, the crash may be reproducible in one environment, while it may not occur in another. The reason for this is because default stacksizes are dependent on the user environment (see ulimit(1)), and/or because stacksizes for threads in a multithreaded application may differ (from the process' main stacksize and/or from each other's stacksize).
How to make alloca() safe to use
Well, in the past, and on many current operating systems, the answer is "you can't", or at best "it's so expensive to do it that you'd better use malloc()". This is so because your function would have to query 'its' stack boundaries before deciding whether to use alloca() or malloc(), and doing so involves some very unportable, low-level hacking (like setting a temporary signal handler and attempting to read a byte roughtly from the area where the buffer would end up, and checking whether that'd trigger a fault), and/or expensive calls to system-level monitoring interfaces (the use of procfs to find the limits of the mapping that e.g. a local variable address is found in). It's a very expensive operation, and hence defeats the purpose of alloca().
Solaris 10 to the rescue ! There are a few new interfaces in Solaris 10 which allow to do this check quickly and efficiently. The following test programm illustrates that:
#include#include #include #include #include #define RESERVE 8192 int main(int argc, char **argv) { int sz = atoi(argv[1]); char *buf; int done_alloca = 0; if (!stack_inbounds((char *)&sz - (sz + RESERVE))) { if ((buf = malloc(sz)) == NULL) { perror("too large for alloca(), and malloc() failed"); return(1); } } else { buf = alloca(sz); done_alloca = 1; } bzero(buf, sz); printf("got %u bytes, at addr %p, via %s()\n", sz, buf, done_alloca ? "alloca" : "malloc"); if (!done_alloca) free(buf); return(0); }
As you can see, it's pretty simple on Solaris 10 to check whether there's enough space on the thread stack to successfully do alloca() or not. And since stack_inbounds() does not perform any system calls, but only inspects the thread context, it's pretty fast as well.
The feature is already used in OpenSolaris - check the code in usr/src/cmd/ldapcachemgr/cachemgr.c how it allows to gracefully deal with previously impossible-to-address stack overflow issues.
Further reading
Check the Jim Litchfield's blog for further details on stack boundary queries.
Courtesy also to my colleague I.Zymin, who talked me into evaluating this feature.

thanks
Posted by 电炉 on October 04, 2007 at 10:17 PM BDT #
How is using alloca() better than using a local variable? In C99, local variables can include arrays with dynamically-determined sizes.
Posted by Zooko on October 04, 2007 at 10:27 PM BDT #
Er, you need to deal with direction of stack growth...
Posted by Nico on October 04, 2007 at 11:04 PM BDT #