alloca()
allocates memory from Stack rather than heap which is case in malloc()
. So, when I return from the routine the memory is freed. So, actually this solves my problem of freeing up of dynamically allocated memory. Freeing of memory allocated through malloc()
is a major headache and if somehow missed leads to all sorts memory problems.
Why is the use of alloca()
discouraged in spite of the above features?
I don't think that anybody has mentioned this, but alloca also has some serious security issues not necessarily present with malloc (though these issues also arise with any stack based arrays, dynamic or not). Since the memory is allocated on the stack, buffer overflows/underflows have much more serious consequences than with just malloc.
In particular, the return address for a function is stored on the stack. If this value gets corrupted, your code could be made to go to any executable region of memory. Compilers go to great lengths to make this difficult (in particular by randomizing address layout). However, this is clearly worse than just a stack overflow since the best case is a SEGFAULT if the return value is corrupted, but it could also start executing a random piece of memory or in the worst case some region of memory which compromises your program's security.
Everyone has already pointed out the big thing which is potential undefined behavior from a stack overflow but I should mention that the Windows environment has a great mechanism to catch this using structured exceptions (SEH) and guard pages. Since the stack only grows as needed, these guard pages reside in areas that are unallocated. If you allocate into them (by overflowing the stack) an exception is thrown.
You can catch this SEH exception and call _resetstkoflw to reset the stack and continue on your merry way. Its not ideal but it's another mechanism to at least know something has gone wrong when the stuff hits the fan. *nix might have something similar that I'm not aware of.
I recommend capping your max allocation size by wrapping alloca and tracking it internally. If you were really hardcore about it you could throw some scope sentries at the top of your function to track any alloca allocations in the function scope and sanity check this against the max amount allowed for your project.
Also, in addition to not allowing for memory leaks alloca does not cause memory fragmentation which is pretty important. I don't think alloca is bad practice if you use it intelligently, which is basically true for everything. :-)
Sadly the truly awesome
alloca()
is missing from the almost awesome tcc. Gcc does havealloca()
.It sows the seed of its own destruction. With return as the destructor.
Like
malloc()
it returns an invalid pointer on fail which will segfault on modern systems with a MMU (and hopefully restart those without).Unlike auto variables you can specify the size at run time.
It works well with recursion. You can use static variables to achieve something similar to tail recursion and use just a few others pass info to each iteration.
If you push too deep you are assured of a segfault (if you have an MMU).
Note that
malloc()
offers no more as it returns NULL (which will also segfault if assigned) when the system is out of memory. I.e. all you can do is bail or just try to assign it any way.To use
malloc()
I use globals and assign them NULL. If the pointer is not NULL I free it before I usemalloc()
.You can also use
realloc()
as general case if want copy any existing data. You need to check pointer before to work out if you are going to copy or concatenate after therealloc()
.3.2.5.2 Advantages of alloca
One pitfall with
alloca
is thatlongjmp
rewinds it.That is to say, if you save a context with
setjmp
, thenalloca
some memory, thenlongjmp
to the context, you may lose thealloca
memory (without any sort of notice). The stack pointer is back where it was and so the memory is no longer reserved; if you call a function or do anotheralloca
, you will clobber the originalalloca
.To clarify, what I'm specifically referring to here is a situation whereby
longjmp
does not return out of the function where thealloca
took place! Rather, a function saves context withsetjmp
; then allocates memory withalloca
and finally a longjmp takes place to that context. That function'salloca
memory is not all freed; just all the memory that it allocated since thesetjmp
. Of course, I'm speaking about an observed behavior; no such requirement is documented of anyalloca
that I know.The focus in the documentation is usually on the concept that
alloca
memory is associated with a function activation, not with any block; that multiple invocations ofalloca
just grab more stack memory which is all released when the function terminates. Not so; the memory is actually associated with the procedure context. When the context is restored withlongjmp
, so is the prioralloca
state. It's a consequence of the stack pointer register itself being used for allocation, and also (necessarily) saved and restored in thejmp_buf
.Incidentally, this, if it works that way, provides a plausible mechanism for deliberately freeing memory that was allocated with
alloca
.I have run into this as the root cause of a bug.
alloca() is very useful if you can't use a standard local variable because its size would need to be determined at runtime and you can absolutely guarantee that the pointer you get from alloca() will NEVER be used after this function returns.
You can be fairly safe if you
The real danger comes from the chance that someone else will violate these conditions sometime later. With that in mind it's great for passing buffers to functions that format text into them :)
Here's why:
Not that anyone would write this code, but the size argument you're passing to
alloca
almost certainly comes from some sort of input, which could maliciously aim to get your program toalloca
something huge like that. After all, if the size isn't based on input or doesn't have the possibility to be large, why didn't you just declare a small, fixed-size local buffer?Virtually all code using
alloca
and/or C99 vlas has serious bugs which will lead to crashes (if you're lucky) or privilege compromise (if you're not so lucky).