Abstract:
alloca is useful for small arrays or strings, but can be dangerous if the array is larger than you expected.

Created by Peter Kankowski
Last changed
Filed under Win32 programming

Share on social sitesReddit Digg Delicious Buzz Facebook Twitter

The perils of alloca function

The difference between alloca and malloc is that memory is allocated on the stack instead of heap. The stack memory is automatically freed when you leave the function.

Stack allocation is much faster: your program just decrements the stack pointer and probes the allocated memory. The program stack is reused for other functions, so it's often contained in L1 or L2 cache, which makes this method even more effective. For these reasons, Agner Fog recommends using alloca for dynamic arrays and strings.

The limit on stack size

However, the maximum stack size is limited. By default, the limit is 1 MB in MSVC++ and 2 MB in GCC; you can increase it with /STACK linker option in MSVC++ or --stack in GCC (MinGW). The limit is stored in exe file headers (SizeOfStackReserve field of IMAGE_OPTIONAL_HEADER).

If you use alloca for user-supplied strings, and the user enters something very long, your program will crash with a "stack overflow" exception. Especially dangerous is calling alloca in a recursive function or a deeply nested function. The stack is also used for local variables (including fixed-length arrays) and return addresses, so the limit is lower than 1-2 MB of allocated data.

Here is a simple recursive program that crashes under both GCC 4 and MSVC++ 2005:

#include <malloc.h>

int OverflowMyStack(int start) {
    if (start == 0)
        return 0;

    char * p = (char *)_alloca(4096);
    *p = '0';
    return OverflowMyStack(start - 1);
}

int main () {
    return OverflowMyStack(512);
}

Solutions

Recent versions of MSVC++ contain _malloca function, which allocates memory on stack if less than 1 KB is requested, and uses heap otherwise. The function is really a macro that calls alloca or malloc depending on the requested size. You should call _freea from the same function to free the allocated memory.

If you use GCC or an earlier version of MSVC++, you can implement a similar macro yourself.

Conclusion

Using alloca, you can make your programs much faster, but you should consider its limitations to prevent the stack overflow bug. If malloca is available, use it. Beware of alloca in recursive functions.

Related articles

Dynamic arrays in C

Peter Kankowski
Peter Kankowski

About the author

Peter is the developer of Aba Search and Replace, a tool for replacing text in multiple files. He likes to program in C with a bit of C++, also in x86 assembly language, Python, and PHP.

Created by Peter Kankowski
Last changed

27 comments

Ten recent comments are shown below. Show all comments

ace,
I actually did answer saying that it is wrong class design

My question was "there is a reason I used it, can you guess it?" You still avoid the answer with your response. Let me give you a hint, it's a real technical reason.

taking into account its multiple possible calls.

That reminds me: you can also use your "allocator", which is "composite" whatever would that mean to the reader, and then pass the pointer outside the scope. So to be safe, it shouldn't exist. On another side, when I use "ScopeAlloc" and allocInScope( n ) I explicitly know at that point how long the result is valid, and I'll know even when I read the code ten years later. Even somebody who never saw anything else but the line where the class is used would know.

Back to the multiple calls argument, calling free or delete multiple times produces problems. So we shouldn't have free and delete functions then?

For this moment I can't judge

For me it's OK if we keep it so.

we can make stress tests

Stress tests? Do you want to again point that the best feature of your class is the "MAGIC" you wrote which should "catch overwrites of markers" for your debugging purposes? The "free two towels with your purchase" argument? No need for "stress", there's no "MAGIC" in my class. It comes from adhering to some principles: I don't "just use" strcpy. I don't cast something to something else, instead I just create what I need. I name the class to make the validity of its use obvious.

In fact, the actual class I really ever use is even simpler:

class ScopeAllocTCHAR
{
    enum { m = 260 };
    TCHAR  pre[ m ], * onHeap;
public:
    ScopeAllocTCHAR() : onHeap( 0 ) {}
    TCHAR* allocInScope( int n ) {
        // just 3 lines of code here, and no magic
    }
    ~ScopeAllocTCHAR() { delete[] onHeap; }
};

It's not template as I don't need that behaviour for other types and there's no passing the size for the stack, I've never found the need to vary it. I wrote the template version in previous post to point that you're misusing casts.

Dmitry Kostjuchenko,

It is also possible to pass pointer obtained from standard 'alloca' out of a scope and run into a problem. Actually by unskilled programmer or just by mistake this can be done at any time. Noone can make it so safe to avoid it at least not in C/C++. In C# it is possible so it is excellent for a dummies.

I will again repeat, it does not matter how do you provide pointer to allocated memory, through cast operator, normal function the idea of the class does not change. Your implementation is also same but differs by requiring to call .alloc while it is done in mine by constructor. It is all just implementation details, who likes what. I also do not like to bind any memory allocator to a type as if it is type based it shall be clearly stated that it is an array of a Type, for me it is much more convenient to split these things like that.

It is a pitty that you do not post complete class implementation and rather change it (your previous and next post). Last example 'ScopeAllocTCHAR' will suffer from accident copy of one instance to another resulting in leaks. So you provide some messy examples that already have bugs. I would prefer to see full implementation so that people who would read our posts could choose one or another.

'ScopeAllocTCHAR' is very limited in performance/usage benefits as 260 bytes would be very low for intensive string operations or some other needs were you use memory for allocating some bigger structs. So I would say I would never use such implementation and std::vector<TCHAR> would be much more convenient to use then :) but it is different story.

'I just create what I need' - it is ok if you work with just one type, but you can also reuse memory for different types and there you will have no other option but to cast into that type. That is why I provided or (void *) operator/getter or auto-cast operator (that is implicit and less visible method).

Well, I would conclude that both implementations can live and can be chosen/implemented depending on programmer preferences. I use my class in a number of C++ libraries succesfully and it serves very well to me in the design implementation which I showed here (thanks to our discussion I also added debugging of memory region that is useful to my view especially when you really must know that everything works ok for critical to reliability applications).

ace,
will suffer from accident copy of one instance (…) that already have bugs

There are no bugs. Unfortunately, you obviously tend to edit the same post many times, so then it's not clear from the discussion what was originally in any of yours. But I still don't like your class. I can't prove it anymore but I think you haven't had private copy constructors before you saw my small (not the smallest) class? Then you claim that I "post bugs" for something I explicitly explain why and where I omit it?

If there were some bug I wouldn't change my old post, I'd admit it and write a new one. But there are no bugs up to now.

is very limited in performance/usage benefits as 260 bytes would be very low for intensive string operations (…) I would say I would never use such implementation and std::vector< TCHAR > would be much more convenient

Any std::vector that I know allocates on heap. Anyway it's OK, you should really use the most concise solution you can find: the less code the better, unless it's on the critical path. Even then, from different possibilities, the smallest effective solution is the best one. That's why I used my class in a few places it really mattered. I know that 260 was the proper size. And I still don't know any practical case where your class with all that in it would be actually needed to solve some real problem and doesn't only increase the amount of unnecessary code.

but you can also reuse memory for different types

I've never needed that. In that almost improbable case I wouldn't refrain from using cast on the spot. But unless it becomes a typical scenario I wouldn't change the class. See above.

That is why I provided or (void *) operator/getter or auto-cast operator

And that's among the reasons I still don't like your class. See all above.

BTW In the meantime I looked at _malloca and I doubt I'll ever use it.

Dmitry Kostjuchenko,
I can't prove it anymore but I think you haven't had private copy constructors before you saw my small (not the smallest) class?

You miss a whole history of our discussion, copy constructor/assignment op. were there before you made a post - 'I don't like the class and I don't like the usage examples.'. I already said that 'composite_allocator' is used in my sub-system libs for a long time (debuuging capab. is only a new future added). ScopeAllocTCHAR is missing them and exposed for copying that I interpret as - serious bug, or you shall post full class implementation if it was partial.

"BTW In the meantime I looked at _malloca and I doubt I'll ever use it. " - this is why you misinterpret functionality 'composite_allocator' as you really never used 'malloca' and do not have an idea for its application. Creating/evaluating something you never used is really a bad idea. Please scroll up and find one of good working example with std::string fmtstrc(const char *fmt, …) function. It can use or 'malloca' or 'composite_allocator'. For 'malloca'/'composite_allocator':

std::string fmtstrc(const char *fmt, ...)
{
    va_list arg;
    va_start(arg, fmt);
 
    size_t size = vcprintf(fmt, arg);
 
#ifdef HAVE_MALLOCA
    void *__memory = malloca(size+1);
#else
    composite_allocator<1024> __memory(size+1); // allocate on stack or dynamically
#endif
    char *buf = (char *)__memory; // COMPOSITE_ALLOC_IMLICIT_CAST is defined
 
    vsnprintf(buf, size, fmt, arg);
    buf[ size ] = 0; // we can manually terminate, or use composite_allocator with __memory(size+1, 0)
 
    va_end(arg);
 
    std::string ret(buf);
#ifdef HAVE_MALLOCA
    freea(__memory);
#else
    return ret;
}
ace,
You miss a whole history of our discussion

Exactly! I miss a history since you're busy faking it. It is never clear when and how you edited which of your old posts (in fact it would be possible to track that with some external effort but it's just not worth). You know, that "edit" feature exists not for you to really change your old posts beyond recognition but to fix spelling or formatting errors. When you change the content, the whole discussion doesn't have sense anymore. That's impolite to others.

exposed for copying that I interpret as - serious bug

You can interpret it so, but in my opinion you're just wrong, I've already said why.

you really never used 'malloca' and do not have an idea for its application

I've never used malloca, but my small class I wrote long ago is already in use in production code for many years. That's one of the reasons I will never use malloca. My opinion about your class is already known: Instead of something that can be small and simple it's something unnecessary complex both on implementation and use side.

Creating/evaluating something you never used is really a bad idea

I could easily say that I don't like it exactly because I already made and used something significantly more elegant.

It can use or 'malloca' or 'composite_allocator'.

I've got an impression that your "example" has a leak when it's used with malloca. So who's "not having idea" then? Of course I wouldn't be surprised if you modify it before I look at the same post the next time, but think how much you can be respected then.

Dmitry Kostjuchenko,

Ace, do not get frustrated, you are inpolitedly trying to say that I correct my posts just to cheat you, I correct posts just to make anyone reading them not to run into problem if one would use pieace of code placed here. I wouldn't advise anyone of using your code as it is incomplete and erronious in design and application and I am surprised that you still argueing. Moreover copy protection of classes is not that cosmic programming technique that only you are aware of it, I am sorry to say but your words and tries to make me a liar are childish. It is a pitty that there is no history of edits so I would proove.

If you are talking about 'ScopeAllocTCHAR' than it is ok if you wrote it for your self only as you know how exactly it behaives, but if other programmes would have access to it it will be a disaster, belive me :) Or someone must look through commits to make sure it was used correctly. As it is not copy-protected I will repeat it has a class design bug. "You can interpret it so, but in my opinion you're just wrong" - I do not get why I am wrong if class instnace has very good probability to be ovewritten/copied resulting in memory leak and crash on N-th deallocation attempt.

Yes, you are correct that std::string fmtstrc(..) latest example was leaking dynamic memory and I actually forgot to fix it after a post, I corrected that post as I do not want to copy-paste it again here, do not blaim me for this :). It was a good example btw how malloca/freea could be misused by lack of attention of programmer, damn me! :)

ace,
you are inpolitedly trying to say that I correct my posts just to cheat you

No, I claim that you continuously attempt to cheat anybody who tries to read this thread by modifying old posts instead of writing the new content in the new posts. I just can't do more.

copy protection of classes is not that cosmic programming technique that only you are aware of

It's not, still you should be a man and admit that it didn't exist in your class and that you added that to yours only after you saw it in mine. I still don't remember seeing these lines in your class. I use C around 25 years, C++ around twenty and I see potential problems in the code really fast.

I do not get why I am wrong if class instnace has very good probability to be ovewritten/copied

Of course you don't as you don't understand basic principles – not every class must have all possible whistles and bells. In fact, the most classes shouldn't. It's only your problem that you believe that that what you wrote should be always used, even instead that every char buff[ M ]. In my humble opinion, your class shouldn't be used at all. That's how the potential programmer is protected the most.

I corrected that post as I do not want to copy-paste it again here, do not blaim me for this

So you keep doing that. That's exactly what finally convinces me that I shouldn't waste any more of my time on you.

To sum up: You made a class which was unnecessary complex. My comment pointed that. I initially didn't even want more than to say that. Later I even demonstrated exactly how much of what you did is wrong and unnecessary, I didn't even have to do that much, but I didn't expect that you will continue to misbehave. During the discussion you tried to fix more errors of yours in a way to make it appear that they didn't exist. During the discussion you increased the complexity of your class even more believing that it increases its value, bit it's still not worth. You still modify your old posts giving no chance to potential correspondent to refer to anything you wrote. Therefore you don't deserve to be treated as somebody with whom respectful discussion is possible. I think I served my "duty" (http://xkcd.com/386/) enough. I'd prefer to leave it to the others, if there are any survivors left, which I doubt.

Dmitry Kostjuchenko,

Ace, no problem, I also tired of this useless and pointless dscussion were you only trying to blaim me for anything while not introducing any real arguments which did make sense to me, let's stop these debates.

"It's not, still you should be a man and admit that it didn't exist in your class and that you added that to yours only after you saw it in mine" - sorry you are wrong, and I repeat, it is very pitty that these posts do not have SVN-like history, although I do not need to prove anything to you.

Some excessive complexity was added to introduce a debugging capability that could be useful for real life while also was an argument for your words of why not just using 'char x[256]'. I managed to show how besides just providing memory to user, such class can do useful debugging stuff just like 'malloca' in Debug compile under MSVC. COMPOSITE_ALLOC_IMLICIT_CAST define functionality was added after your words that (void *) operator looks ugly thus universal template cast operator was introduced for those who would find it same ugly. It was done for all other people not just for you :) I did not think that we were trying to fight for the goal who is smarter, I personally was trying to make class as flexible and useful as possible in terms of C/C++ coding practise. So we were pursueing different goals I guess.

Thank you for your time for this discussion, in some places I found it useful and that helped to improve 'composite_allocator'.

Nihlatak,

I'm sorry you had to go through this Dmitry.

Recently I got interested in alloca/malloca class implementations. I'll look into your implementation to gain some knowledge.

As for ace, he got nothing to look at all.

guziy,

Hi,

I am trying to use a c lib with ctypes and getting the following error

Error: in routine alloca() there is a

stack overflow: thread 0, max 137438739794KB, used 76KB, request 920B

could you, please, explain it ?

thanks

--

Sasha

Your name:


Comment: