492

alloca() allocates memory on the stack rather than on the heap, as in the case of malloc(). So, when I return from the routine the memory is freed. So, actually this solves my problem of freeing up dynamically allocated memory. Freeing of memory allocated through malloc() is a major headache and if somehow missed leads to all sorts of memory problems.

Why is the use of alloca() discouraged in spite of the above features?

Matteo Ugolotti
  • 367
  • 3
  • 12
Vaibhav
  • 5,749
  • 3
  • 22
  • 18
  • 52
    Just a quick note. Although this function can be found in most compilers it is not required by the ANSI-C standard and therefore could limit portability. Another thing is, that you must not! free() the pointer you get and it's freed automatically after you exit the function. – merkuro Jun 19 '09 at 16:38
  • @meruko Good point..certainly effects portablity – Vaibhav Jun 19 '09 at 16:42
  • 12
    Also, a function with alloca() won't be inlined if declared as such. – Justicle Jun 23 '09 at 00:29
  • 2
    @Justicle, can you provide some explanation? I'm very curious what's behind this behaviour – migajek Aug 01 '10 at 20:35
  • @migajek, Igor's answer just added below shows why inlining is dangerous, and so if Justicle is correct it should be a good thing. – Bill Forster Aug 04 '10 at 23:47
  • 63
    Forget all the noise about portability, no need to call `free` (which is obviously an advantage), non-ability to inline it (obviously heap allocations are very much heavier) and etc. The only reason to avoid `alloca` is for large sizes. That is, wasting tons of stack memory is not a good idea, plus you have a chance of a stack overflow. If this is the case - consider using `malloca` / `freea` – valdo Nov 02 '11 at 12:23
  • Are there any examples where alloca() becomes extremely useful, like: it can be used for randomizing stack allocation against stack overflow attacks? Or aren't there any? – user31986 Jul 07 '16 at 20:23
  • @user31986 - if in main(), you did something like `global_ptr_var=alloca( rand( get_seed()) % 12345)` before calling `actual_main`, that would have the effect of making the whole program run with a (somewhat) random stack base. So that might be useful. – greggo May 02 '17 at 17:55
  • I'd just use a VLA for this on platforms that support it (which might not be all C compilers supporting the newest standard now that they're optional rather than mandatory like in C99...) – JAB Feb 22 '18 at 00:28
  • 11
    Another positive aspect of `alloca` is that the stack cannot be fragmented like the heap. This could prove useful for hard real-time run-forever style applications, or even safety critical applications, since the WCRU can then be statically analyzed without resorting to custom memory pools with their own set of problems (no temporal locality, sub-optimal resource use). – Andreas May 17 '18 at 06:51
  • This issue is covered in [question 7.32](http://c-faq.com/malloc/alloca.html) of the [C FAQ list](http://c-faq.com). – Steve Summit Aug 05 '21 at 17:20

24 Answers24

329

The answer is right there in the man page (at least on Linux):

RETURN VALUE The alloca() function returns a pointer to the beginning of the allocated space. If the allocation causes stack overflow, program behaviour is undefined.

Which isn't to say it should never be used. One of the OSS projects I work on uses it extensively, and as long as you're not abusing it (alloca'ing huge values), it's fine. Once you go past the "few hundred bytes" mark, it's time to use malloc and friends, instead. You may still get allocation failures, but at least you'll have some indication of the failure instead of just blowing out the stack.

Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
Sean Bright
  • 118,630
  • 17
  • 138
  • 146
  • 47
    So there's really no problem with it that you wouldn't also have with declaring large arrays? – T.E.D. Jun 19 '09 at 16:32
  • 10
    @sean I understand this, if I allocate too much memory ( as stack space is limited as compared to heap) this would lead to overflow; but same is the case with a local array as well. If I remain within my limits then I should be fine, right? Then also I still see anti alloa comments. – Vaibhav Jun 19 '09 at 16:32
  • Yes, if you remain within your limits, your code can assume a certain stack size, and the stack above your function's frame is consistently the same size, you should be fine. – Sean Bright Jun 19 '09 at 16:42
  • Not the same as large arrays, since the OS will guarentee space for those... they're statically sized. – singpolyma Jun 23 '09 at 00:28
  • 18
    @singpolyma - The following crashes for me, so I'm not sure what you mean: int main(int argc, char **argv) { char byebye[1024 * 1024 * 10]; /* 10MB array */; byebye[0] = 0; return 0; } – Sean Bright Jun 23 '09 at 01:34
  • 119
    @Sean: Yes, stack overflow risk is the reason given, but that reason is a bit silly. Firstly because (as Vaibhav says) large local arrays cause exactly the same problem, but are not nearly as vilified. Also, recursion can just as easily blow the stack. Sorry but I'm -1ing you to hopefully counter the prevailing idea that the reason given in the man page is justified. – j_random_hacker Jun 27 '10 at 13:22
  • 4
    I'm not entirely sure what point you are making... Don't use large local arrays? Functions that fail with undefined behavior should be used frequently and in earnest? Documentation cannot be trusted? – Sean Bright Jun 29 '10 at 12:54
  • 59
    My point is that the justification given in the man page makes no sense, since alloca() is exactly as "bad" as those other things (local arrays or recursive functions) that are considered kosher. – j_random_hacker Jun 30 '10 at 01:44
  • I think the warning in man page does make sense. There is no reason alloca couldn't work some magic to resize the stack to accommodate the allocation, so it's worth pointing out that any such magic is be implementation dependent, and is not required by the standard. – Charles E. Grant Aug 01 '10 at 20:45
  • 4
    @j_random_hacker: do you really think large local arrays are considered kosher? – ninjalj Aug 01 '10 at 22:27
  • 50
    @ninjalj: Not by highly experienced C/C++ programmers, but I do think many people who fear `alloca()` do not have the same fear of local arrays or recursion (in fact many people who will shout down `alloca()` will praise recursion because it "looks elegant"). I agree with Shaun's advice ("alloca() is fine for small allocations") but I disagree with the mindset that frames alloca() as uniquely evil among the 3 -- they are equally dangerous! – j_random_hacker Aug 02 '10 at 05:33
  • 8
    `alloca` is fine to use for small allocations, or if you your function is a leaf function (or very nearly a leaf function). That way, you can place an upper bound on how much stack space will be used from there on out. Example: If you have a logging function that needs to convert a string from ASCII to Unicode (or vice-versa), it can be more efficient to use `alloca` instead of `malloc` for the conversion buffer. – Adam Rosenfield Mar 10 '11 at 22:33
  • 19
    +1 to negate @j_random_hacker's down-vote. The man page is perfectly justified in stating what will happen if `alloca()` blows the stack (in fact, it would be irresponsible not to explain this). And Sean's surrounding explanation is perfectly sound, even to the point of qualifying the answer so that it is not interpreted as an outright proscription of `alloca()`. Nothing in Sean's answer implies the mindset j_random_hacker speaks of. In fact, Sean's first two comments, posted several hours earlier than j_random_hacker's first comment, make it abundantly clear that that is not Sean's viewpoint. – Marcelo Cantos Apr 15 '12 at 23:28
  • 41
    Note: Given Linux's "optimistic" memory allocation strategy, you very likely *won't* get any indication of a heap-exhaustion failure... instead malloc() will return you a nice non-NULL pointer, and then when you try to actually access the address space it points to, your process (or some other process, unpredictably) will get killed by the OOM-killer. Of course this is a "feature" of Linux rather than a C/C++ issue per se, but it's something to keep in mind when debating whether alloca() or malloc() is "safer". :) – Jeremy Friesner Jul 28 '13 at 02:53
  • 2
    @j_random_hacker: It's really quite simple. You can have fixed-size allocations on the stack without alloca, or dynamically-sized allocations with alloca. You're right in a way--in either case you have to be considerate of the stack. – John Thoits Jan 16 '19 at 21:51
  • 7
    I would add that it's unfortunate that this answer doesn't specify the single greatest advantage of alloca when it's not the wrong choice: avoiding the delete/free overhead. I made a function over 100x faster one time by using alloca simply because I removed the heap memory management overhead. – John Thoits Jan 16 '19 at 21:54
  • 2
    "Also, recursion can just as easily blow the stack. " many modern systems have stack guard pages that are used to either automatically grow the stack or at least produce an error. Recursion will normally cause the guard page to be hit, while a single large allocation can jump straight over it. – plugwash Oct 30 '20 at 07:33
  • @JeremyFriesner the "optimistic" memory allocation strategy can be disabled with vm.overcommit_memory = 2. In this case, malloc should properly fail on memory exhaustion. – Jean-Baptiste Poittevin Jul 27 '22 at 08:59
  • @Jean-BaptistePoittevin agreed; however, unless you are in direct control of all of the machine(s) your program is running on, you can't rely on that setting being present. – Jeremy Friesner Jul 27 '22 at 13:55
  • If you are afraid of stack overflow then don't use functions either. Any function call may cause stack overflow. So put all your code to `main()`. And even this might not help if you use nested code blocks. – anton_rh Jun 15 '23 at 13:18
  • @anton_rh This is good advice. I’ll update my answer to incorporate it. – Sean Bright Jun 15 '23 at 17:03
265

One of the most memorable bugs I had was to do with an inline function that used alloca. It manifested itself as a stack overflow (because it allocates on the stack) at random points of the program's execution.

In the header file:

void DoSomething() {
   wchar_t* pStr = alloca(100);
   //......
}

In the implementation file:

void Process() {
   for (i = 0; i < 1000000; i++) {
     DoSomething();
   }
}

So what happened was the compiler (Microsoft VC++ 6) inlined DoSomething function and all the stack allocations were happening inside Process() function and thus blowing the stack up. In my defence (and I wasn't the one who found the issue; I had to go and cry to one of the senior developers when I couldn't fix it), it wasn't straight alloca, it was one of ATL string conversion macros.

So the lesson is - do not use alloca in functions that you think might be inlined.

Jango
  • 378
  • 4
  • 8
Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
  • 140
    Interesting. But wouldn't that qualify as a compiler bug? After all, the inlining changed the behaviour of the code (it delayed the freeing of the space allocated using alloca). – sleske Oct 17 '10 at 18:55
  • 81
    Apparently, at least GCC will take this into account: "Note that certain usages in a function definition can make it unsuitable for inline substitution. Among these usages are: use of varargs, use of alloca, [...]". http://gcc.gnu.org/onlinedocs/gcc/Inline.html – sleske Oct 17 '10 at 18:57
  • 180
    What compiler were you smoking? – Thomas Eding Nov 16 '11 at 21:34
  • 4
    Microsoft VC++ 6. – Igor Zevaka Nov 17 '11 at 08:03
  • 1
    I've just tried this in VS2010, you can happily combine alloca with _forceinline and the compiler won't even produce a warning. Still an issue for some compilers.... – Benj Mar 15 '12 at 13:16
  • 7
    Apologies, I was compiling in debug mode! VS2010 gives: warning C4750: 'bool __cdecl inlined_TestW32Mem5(void)': function with _alloca() inlined into a loop – Benj Mar 15 '12 at 13:40
  • 3
    And that's if you _forceinline (otherwise the function isn't inlined if it has alloca) – Benj Mar 15 '12 at 13:43
  • 26
    What I don't understand is why the compiler does not make good use of the scope to determine that allocas in subscope are more or less "freed": stack pointer could come back to its point before entering the scope, like what is done when returning from function (couldn't it?) – moala May 16 '12 at 12:18
  • 3
    Even worse: A colleague managed to use alloca directly in a while(!done) loop... – BertR Jan 24 '13 at 11:07
  • 4
    This lesson does not mean that `alloca()` shouldn't be used. It simply means you should not allow the compiler to inline it. That is easily avoidable on GCC and Clang by saying `__attribute__((__noinline__))` on any function that calls `alloca()`. Problem solved. – Todd Lehman Aug 25 '15 at 22:49
  • @moala - that could get complex, e.g. if the caller is also using alloca. It's probably no harder to do than some of the things compilers already do, but since 'alloca' is still considered an 'edge' issue, compiler designers are unlikely to add that extra complexity to support this. Related point: having alloca in your function will cause the optimizer to 'punt' a lot of things, for one thing it no longer knows the size of the local frame, and has to use a frame register, when otherwise it might not need to. – greggo May 02 '17 at 18:09
  • 26
    I've downvoted, but the answer is well written: I agree with others you're faulting alloca for what is a clearly a **compiler bug**. The compiler has made a faulty assumption in an optimization it should not have made. Working around a compiler bug is fine, but I wouldn't fault anything for it but the compiler. – Evan Carroll Sep 06 '18 at 19:02
  • 6
    @EvanCarroll It isn't a necessarily compiler bug, because `alloca` is not a standardized function. To fix the issue on that compiler, all the vendors have to do is add it to the documentation. "This compiler's function inlining logic ignores `alloca`. `alloca` memory is only disposed by a return from a non-inlined function". That doesn't contravene any major standard; not ISO C or POSIX, only some *de facto* behaviors of other implementations. – Kaz Jul 09 '20 at 15:08
  • 1
    @EvanCarroll I should have written *de facto* or documented behaviors of other implementations. Also, if we take a historic perspective, I believe `alloca` was invented first as a hack provided in a header file. Compiler awareness of `alloca` is a later refinement, but I don't think it can be relied upon as universal. – Kaz Jul 09 '20 at 15:25
  • From what I understand alloca was originally a hack based on a routine written in ASM that did not restore the stack pointer when returning. When combined with a sufficiently dumb C compiler this worked but it would break horribly on anything resembling a modern complier. – plugwash Oct 27 '21 at 20:51
  • It can't be a compiler bug that alloca breaks when in line because the safety of using alloca is already implementation-dependent. – fixermark Nov 13 '22 at 05:40
106

Old question but nobody mentioned that it should be replaced by variable length arrays.

char arr[size];

instead of

char *arr=alloca(size);

It's in the standard C99 and existed as compiler extension in many compilers.

Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
  • 7
    It's mentioned by Jonathan Leffler on a comment to Arthur Ulfeldt's answer. – ninjalj Aug 01 '10 at 22:31
  • 5
    Indeed, but it shows also how easy it is missed, as I hadn't seen it despite reading all responses before posting. – Patrick Schlüter Aug 02 '10 at 09:50
  • 10
    One note -- those are variable length arrays, not dynamic arrays. The latter are resizable and usually implemented on the heap. – Tim Čas Dec 09 '12 at 16:42
  • @Benj: Is this still an issue with recent MSVC versions? – einpoklum Jul 17 '15 at 20:58
  • @einpoklum I don't believe so, though I haven't tried it: https://msdn.microsoft.com/en-us/library/hh409293.aspx – Benj Jul 18 '15 at 13:37
  • 1
    Visual Studio 2015 compiling some C++ has the same issue. – ahcox Apr 07 '16 at 15:35
  • How does the compiler implement variable size array? – Karthik Raj Palanichamy Sep 14 '17 at 09:51
  • Just by adjusting the stack pointer. When you call a function, there's a little bit of code that adjusts the sp and sometimes also a frame pointer which allows to address the local variables allocated on the stack. The stack pointer is adjusted depending on the size of the different variable. For normal variables that value is a constant emitted by the compiler. In case of of a VLA that value depends on a parameter or another variable. That's why VLA are interesting, their allocation doesn't cost very much as it is only a simple calculation added to an operation that has to be done anyway. – Patrick Schlüter Sep 14 '17 at 16:31
  • 5
    Linus Torvalds doesn't like [VLAs in the Linux kernel](https://lkml.org/lkml/2018/3/7/621). As of version 4.20 Linux should be almost VLA free. – Cristian Ciupitu Jan 10 '19 at 15:18
  • 5
    Unfortunately, there are compilers out there (Keil for ARM) that implement VLA on the heap by silently linking malloc() into the code. That's a major annoyance, as you never know where the memory is allocated and I don't know whether tehy correctly call free() afterwards. – opt12 Sep 19 '19 at 13:09
74

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

  • do not return the pointer, or anything that contains it.
  • do not store the pointer in any structure allocated on the heap
  • do not let any other thread use the pointer

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 :)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • 17
    The VLA (variable length array) feature of C99 supports dynamically sized local variables without explicitly requiring alloca() to be used. – Jonathan Leffler Jun 22 '09 at 23:57
  • 2
    neato! found more info in section '3.4 Variable Length Array' of http://www.programmersheaven.com/2/Pointers-and-Arrays-page-2 – Arthur Ulfeldt Jun 23 '09 at 00:15
  • 2
    But that is not different from handling with pointers to local variables. They can be fooled around with as well... – glglgl Oct 18 '12 at 07:28
  • 3
    @Jonathan Leffler one thing you can do with alloca but you can't do with VLA is using restrict keyword with them. Like this: float* restrict heavily_used_arr = alloca(sizeof(float)*size); instead of float heavily_used_arr[size]. It might help some compilers (gcc 4.8 in my case) to optimize the assembly even if size is a compilation constant. See my question about it: http://stackoverflow.com/questions/19026643/using-restrict-with-arrays – Piotr Lopusiewicz Oct 01 '13 at 23:29
  • @JonathanLeffler A VLA is local to the block that contains it. On the other hand, `alloca()` allocates memory that lasts until the end of the function. This means that there appears to be no straightforward, convenient translation to VLA of `f() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }`. If you think it is possible to automatically translate uses of `alloca` to uses of VLA but require more than a comment to describe how, I can make this a question. – Pascal Cuoq Mar 24 '14 at 09:40
  • @PascalCuoq: There isn't always a direct, let alone automatic, translation between code using `alloca()` and code using a VLA. I observe that in your `f()`, the `/* use p */` code probably has to have further conditionals depending on whether `p` is null or not. The gist of the code using a VLA might be: `f() { int x = 1; if (c) { /* compute x */ } char p[x]; /* use p */ }`. – Jonathan Leffler Mar 24 '14 at 14:25
  • Some nits: (1) It is safe to return the pointer if the caller only uses that pointer for addressing statistics and never dereferences it. (2) It is perfectly safe to store the pointer in a structure allocated on the heap, as long as you remove the structure from the heap before the stack frame is closed. I don't know why anyone would do this, but it should be perfectly safe. (3) It's fine to let other threads use the pointer if you can guarantee the memory is valid for the entire duration in which they use it — for example, some long-running calculation. – Todd Lehman May 15 '15 at 01:02
  • Let's also note that you have to follow the same restriction Arthur mentions with VLA's as well as `alloca()` results. – einpoklum Jul 17 '15 at 20:57
  • I would add: validate the size first, if it depends on untrusted data, before calling, so you aren't asking for an absurdly large increase in the stack frame. And (like all of the above), this also applies to VLAs. – greggo Jun 20 '19 at 18:19
45

As noted in this newsgroup posting, there are a few reasons why using alloca can be considered difficult and dangerous:

  • Not all compilers support alloca.
  • Some compilers interpret the intended behaviour of alloca differently, so portability is not guaranteed even between compilers that support it.
  • Some implementations are buggy.
A. Wilcox
  • 1,782
  • 2
  • 12
  • 18
FreeMemory
  • 8,444
  • 7
  • 37
  • 49
  • 29
    One thing I saw mentioned on that link which is not elsewhere on this page is that a function that uses `alloca()` requires separate registers for holding the stack pointer and frame pointer. On x86 CPUs >= 386, the stack pointer `ESP` can be used for both, freeing up `EBP` -- unless `alloca()` is used. – j_random_hacker Jun 27 '10 at 13:30
  • 14
    Another good point on that page is that unless the compiler's code generator handles it as a special case, `f(42, alloca(10), 43);` could crash due to possibility that the stack pointer is adjusted by `alloca()` *after* at least one of the arguments is pushed on it. – j_random_hacker Jun 27 '10 at 13:38
  • 4
    The linked post appears to be written by John Levine-- the dude who wrote "Linkers and Loaders", I would trust whatever he says. – user318904 Aug 13 '11 at 06:06
  • 3
    The linked post is a _reply_ to a posting by John Levine. – A. Wilcox Dec 29 '14 at 05:07
  • 3
    +1 for not making irrelevant arguments like the much-higher-voted answers, which forget that their arguments can be applied just as well to variable-length arrays or any stack-guzzling devices. – einpoklum Jul 17 '15 at 21:00
  • 11
    Bear in mind, a *lot* has changed since 1991. All modern C compilers (even in 2009) have to handle alloca as a special case; it's an intrinsic rather than an ordinary function, and may not even call a function. So, the alloca-in-parameter issue (which arose in K&R C from the 1970's) should not be a problem now. More detail in a comment I made on Tony D's answer – greggo May 02 '17 at 17:45
  • A question: is there an equivalent to `alloca` that is supported by all compilers? – mercury0114 Oct 04 '20 at 20:05
31

One issue is that it isn't standard, although it's widely supported. Other things being equal, I'd always use a standard function rather than a common compiler extension.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
27

still alloca use is discouraged, why?

I don't perceive such a consensus. Lots of strong pros; a few cons:

  • C99 provides variable length arrays, which would often be used preferentially as the notation's more consistent with fixed-length arrays and intuitive overall
  • many systems have less overall memory/address-space available for the stack than they do for the heap, which makes the program slightly more susceptible to memory exhaustion (through stack overflow): this may be seen as a good or a bad thing - one of the reasons the stack doesn't automatically grow the way heap does is to prevent out-of-control programs from having as much adverse impact on the entire machine
  • when used in a more local scope (such as a while or for loop) or in several scopes, the memory accumulates per iteration/scope and is not released until the function exits: this contrasts with normal variables defined in the scope of a control structure (e.g. for {int i = 0; i < 2; ++i) { X } would accumulate alloca-ed memory requested at X, but memory for a fixed-sized array would be recycled per iteration).
  • modern compilers typically do not inline functions that call alloca, but if you force them then the alloca will happen in the callers' context (i.e. the stack won't be released until the caller returns)
  • a long time ago alloca transitioned from a non-portable feature/hack to a Standardised extension, but some negative perception may persist
  • the lifetime is bound to the function scope, which may or may not suit the programmer better than malloc's explicit control
  • having to use malloc encourages thinking about the deallocation - if that's managed through a wrapper function (e.g. WonderfulObject_DestructorFree(ptr)), then the function provides a point for implementation clean up operations (like closing file descriptors, freeing internal pointers or doing some logging) without explicit changes to client code: sometimes it's a nice model to adopt consistently
    • in this pseudo-OO style of programming, it's natural to want something like WonderfulObject* p = WonderfulObject_AllocConstructor(); - that's possible when the "constructor" is a function returning malloc-ed memory (as the memory remains allocated after the function returns the value to be stored in p), but not if the "constructor" uses alloca
      • a macro version of WonderfulObject_AllocConstructor could achieve this, but "macros are evil" in that they can conflict with each other and non-macro code and create unintended substitutions and consequent difficult-to-diagnose problems
    • missing free operations can be detected by ValGrind, Purify etc. but missing "destructor" calls can't always be detected at all - one very tenuous benefit in terms of enforcement of intended usage; some alloca() implementations (such as GCC's) use an inlined macro for alloca(), so runtime substitution of a memory-usage diagnostic library isn't possible the way it is for malloc/realloc/free (e.g. electric fence)
  • some implementations have subtle issues: for example, from the Linux manpage:

    On many systems alloca() cannot be used inside the list of arguments of a function call, because the stack space reserved by alloca() would appear on the stack in the middle of the space for the function arguments.


I know this question is tagged C, but as a C++ programmer I thought I'd use C++ to illustrate the potential utility of alloca: the code below (and here at ideone) creates a vector tracking differently sized polymorphic types that are stack allocated (with lifetime tied to function return) rather than heap allocated.

#include <alloca.h>
#include <iostream>
#include <vector>

struct Base
{
    virtual ~Base() { }
    virtual int to_int() const = 0;
};

struct Integer : Base
{
    Integer(int n) : n_(n) { }
    int to_int() const { return n_; }
    int n_;
};

struct Double : Base
{
    Double(double n) : n_(n) { }
    int to_int() const { return -n_; }
    double n_;
};

inline Base* factory(double d) __attribute__((always_inline));

inline Base* factory(double d)
{
    if ((double)(int)d != d)
        return new (alloca(sizeof(Double))) Double(d);
    else
        return new (alloca(sizeof(Integer))) Integer(d);
}

int main()
{
    std::vector<Base*> numbers;
    numbers.push_back(factory(29.3));
    numbers.push_back(factory(29));
    numbers.push_back(factory(7.1));
    numbers.push_back(factory(2));
    numbers.push_back(factory(231.0));
    for (std::vector<Base*>::const_iterator i = numbers.begin();
         i != numbers.end(); ++i)
    {
        std::cout << *i << ' ' << (*i)->to_int() << '\n';
        (*i)->~Base();   // optionally / else Undefined Behaviour iff the
                         // program depends on side effects of destructor
    }
}
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • no +1 because of the fishy idiosyncratic way of handling several types :-( – einpoklum Jul 17 '15 at 21:02
  • @einpoklum: well that's deeply enlightening... thanks. – Tony Delroy Jul 18 '15 at 05:25
  • 2
    Let me rephrase: This is a very good answer. Up to the point where I think you're suggesting that people use a sort of a counter-pattern. – einpoklum Jul 18 '15 at 09:36
  • 1
    The comment from the linux manpage is very old and, I'm pretty sure, obsolete. All modern compilers know what alloca() is, and won't trip over their shoelaces like that. In old K&R C, (1) all functions used frame pointers (2) All function calls were {push args on stack}{call func}{add #n,sp}. alloca was a lib function that would just bump the stack up, the compiler didn't even know about that happening. (1) and (2) are not true any more so alloca can't work that way (now it's an intrinsic). In old C, calling alloca in the middle of pushing args would obviously break those assumptions too. – greggo May 02 '17 at 17:31
  • 9
    Regarding the example, I'd be generally concerned about something that *requires* always_inline to avoid memory corruption.... – greggo May 02 '17 at 17:33
  • 1
    Uses placement new to return an alloca buffer. If the function ends up not inlined you trash the stack. Your code is undefined. – Joshua Sep 25 '19 at 01:05
  • 1
    if anyone gonna read this: modern C++ style for allocating on stack is via *allocator* - create it and make all vectors and "new" be directed through it – Noone AtAll Jul 22 '20 at 07:25
21

Lots of interesting answers to this "old" question, even some relatively new answers, but I didn't find any that mention this....

When used properly and with care, consistent use of alloca() (perhaps application-wide) to handle small variable-length allocations (or C99 VLAs, where available) can lead to lower overall stack growth than an otherwise equivalent implementation using oversized local arrays of fixed length. So alloca() may be good for your stack if you use it carefully.

I found that quote in.... OK, I made that quote up. But really, think about it....

@j_random_hacker is very right in his comments under other answers: Avoiding the use of alloca() in favor of oversized local arrays does not make your program safer from stack overflows (unless your compiler is old enough to allow inlining of functions that use alloca() in which case you should upgrade, or unless you use alloca() inside loops, in which case you should... not use alloca() inside loops).

I've worked on desktop/server environments and embedded systems. A lot of embedded systems don't use a heap at all (they don't even link in support for it), for reasons that include the perception that dynamically allocated memory is evil due to the risks of memory leaks on an application that never ever reboots for years at a time, or the more reasonable justification that dynamic memory is dangerous because it can't be known for certain that an application will never fragment its heap to the point of false memory exhaustion. So embedded programmers are left with few alternatives.

alloca() (or VLAs) may be just the right tool for the job.

I've seen time & time again where a programmer makes a stack-allocated buffer "big enough to handle any possible case". In a deeply nested call tree, repeated use of that (anti-?)pattern leads to exaggerated stack use. (Imagine a call tree 20 levels deep, where at each level for different reasons, the function blindly over-allocates a buffer of 1024 bytes "just to be safe" when generally it will only use 16 or less of them, and only in very rare cases may use more.) An alternative is to use alloca() or VLAs and allocate only as much stack space as your function needs, to avoid unnecessarily burdening the stack. Hopefully when one function in the call tree needs a larger-than-normal allocation, others in the call tree are still using their normal small allocations, and the overall application stack usage is significantly less than if every function blindly over-allocated a local buffer.

But if you choose to use alloca()...

Based on other answers on this page, it seems that VLAs should be safe (they don't compound stack allocations if called from within a loop), but if you're using alloca(), be careful not to use it inside a loop, and make sure your function can't be inlined if there's any chance it might be called within another function's loop.

phonetagger
  • 7,701
  • 3
  • 31
  • 55
  • 2
    I agree with this point. The dangerous of `alloca()` is true, but the same can be said to memory leaks with `malloc()` (why not use a GC then? one might argue). `alloca()` when used with care can be really useful to decrease the stack size. – Felipe Tonello Feb 02 '17 at 15:44
  • Another good reason not to use dynamic memory, especially in embedded: it's more complicated than sticking to the stack. Using dynamic memory requires special procedures and data structures, whereas on the stack it's (to simplify things) a matter of adding/subtracting a higher number from stackpointer. – tehftw Sep 17 '18 at 06:31
  • Sidenote: The "using a fixed buffer[MAX_SIZE]" example highlights why overcommit memory policy works so well. Programs allocate memory they may never touch except at the limits of their buffer length. So it's fine that Linux (and other OS's) don't actually assign a page of memory until its first used (as opposed to malloc'd). If the buffer is larger than one page, the program may only use the first page, and not waste the rest of the physical memory. – Katastic Voyage Jun 23 '19 at 03:46
  • 1
    @KatasticVoyage Unless MAX_SIZE is greater than (or at least equal to) the size of your system's virtual memory page size, your argument doesn't hold water. Also on embedded systems without virtual memory (many embedded MCU's don't have MMU's), the overcommit memory policy may be good from an "ensure your program will run in all situations" standpoint, but that assurance comes with the price that your stack size must be likewise allocated to support that overcommit memory policy. On some embedded systems, that's a price that some manufacturers of low-cost products aren't willing to pay. – phonetagger Sep 05 '19 at 18:09
19

I don't think anyone has mentioned this: Use of alloca in a function will hinder or disable some optimizations that could otherwise be applied in the function, since the compiler cannot know the size of the function's stack frame.

For instance, a common optimization by C compilers is to eliminate use of the frame pointer within a function, frame accesses are made relative to the stack pointer instead; so there's one more register for general use. But if alloca is called within the function, the difference between sp and fp will be unknown for part of the function, so this optimization cannot be done.

Given the rarity of its use, and its shady status as a standard function, compiler designers quite possibly disable any optimization that might cause trouble with alloca, if would take more than a little effort to make it work with alloca.

UPDATE: Since variable-length local arrays have been added to C, and since these present very similar code-generation issues to the compiler as alloca, I see that 'rarity of use and shady status' does not apply to the underlying mechanism; but I would still suspect that use of either alloca or VLA tends to compromise code generation within a function that uses them. I would welcome any feedback from compiler designers.

greggo
  • 3,009
  • 2
  • 23
  • 22
  • 2
    > *I would still suspect that use of either alloca or VLA tends to compromise code generation* I would think that use of alloca requires a frame pointer, because the stack pointer moves in ways that are not obvious at compile time. alloca can be called in a loop to keep grabbing more stack memory, or with a run-time calculated size, etc. If there is a frame pointer, generated code has a stable reference to locals and the stack pointer can do whatever it wants; it is not used. – Kaz Jun 12 '20 at 18:17
  • 6
    If the alternative to VLA or alloca is to invoke `malloc` and `free`, the function may be more efficient with their use, even if it makes framing required. – Kaz Jul 09 '20 at 15:02
18

All of the other answers are correct. However, if the thing you want to alloc using alloca() is reasonably small, I think that it's a good technique that's faster and more convenient than using malloc() or otherwise.

In other words, alloca( 0x00ffffff ) is dangerous and likely to cause overflow, exactly as much as char hugeArray[ 0x00ffffff ]; is. Be cautious and reasonable and you'll be fine.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
13

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. :-)

SilentDirge
  • 827
  • 9
  • 17
  • The problem is, that `alloca()` can demand so much space, that the stackpointer lands in the heap. With that, a attacker who can control the size for `alloca()` and the data that goes into that buffer can overwrite the heap (which is very bad). – 12431234123412341234123 Nov 02 '18 at 18:50
  • SEH is a Windows-only thing. That's great if you only care about your code running on Windows, but if your code needs to be cross-platform (or if you're writing code that only runs on a non-Windows platform), then you can't rely on having SEH. – George Jun 11 '20 at 13:00
11

One pitfall with alloca is that longjmp rewinds it.

That is to say, if you save a context with setjmp, then alloca some memory, then longjmp to the context, you may lose the alloca memory. The stack pointer is back where it was and so the memory is no longer reserved; if you call a function or do another alloca, you will clobber the original alloca.

To clarify, what I'm specifically referring to here is a situation whereby longjmp does not return out of the function where the alloca took place! Rather, a function saves context with setjmp; then allocates memory with alloca and finally a longjmp takes place to that context. That function's alloca memory is not all freed; just all the memory that it allocated since the setjmp. Of course, I'm speaking about an observed behavior; no such requirement is documented of any alloca 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 of alloca 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 with longjmp, so is the prior alloca state. It's a consequence of the stack pointer register itself being used for allocation, and also (necessarily) saved and restored in the jmp_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.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • 6
    That's what it's supposed to do though - `longjmp` goes back and makes it so the program forgets about everything that happened in the stack: all the variables, function calls etc. And `alloca` is just like an array on the stack, so it's expected they will be clobbered like everything else on the stack. – tehftw Sep 17 '18 at 06:37
  • 5
    `man alloca` gave the following sentence: "Because the space allocated by alloca() is allocated within the stack frame, that space is automatically freed if the function return is jumped over by a call to longjmp(3) or siglongjmp(3).". So it is documented that memory allocated with `alloca` gets clobbered after a `longjmp`. – tehftw Sep 17 '18 at 06:40
  • 1
    @tehftw The situation described occurs without a function return being jumped over by `longjmp`. The target function has not yet returned. It has done `setjmp`, `alloca` and then `longjmp`. The `longjmp` may rewind the `alloca` state back to what it was at `setjmp` time. That is to say, the pointer moved by `alloca` suffers from the same problem as a local variable that has not been marked `volatile`! – Kaz Sep 17 '18 at 14:37
  • 7
    I don't understand why it would be supposed to be unexpected. When you `setjmp` then `alloca`, and then `longjmp`, it's normal that `alloca`would be rewinded. The whole point of `longjmp` is to get back to the state that was saved at `setjmp`! – tehftw Sep 17 '18 at 17:38
  • @tehftw I've never seen this particular interaction documented. Therefore, it cannot be relied upon either way, other than by empirical investigation with compilers. – Kaz Sep 18 '18 at 02:16
  • 1
    `man alloca` documented that interaction. I personally would rely on that interaction if I was using `alloca` with `longjmp`, as it is documented. What documentation for alloca did you read that it wasn't documented there? – tehftw Sep 18 '18 at 09:39
  • 1
    @tehftw "Linux Programmer's Manual" man page; GCC documentation on `__builtin_alloca()` (the basis for `alloca`), MSDN on Microsoft's `alloca`; Solaris 11 man page; FreeBSD man page. Only the Linux one mentions interaction between alloca and `longjmp`; but only about the memory being freed when a function return is jumped over by `longjmp`. – Kaz Sep 18 '18 at 20:39
  • 1
    Funny that MSDN doesn't have that, as I wanted to ask about whether Micrisoft are the guys who failed to document it :P I'm surprised at the others for not saying it explicitily, though. From what I read, it seems GCC, FreeBSD and MSDN assume "restores stack environment" is clear enough that the memory from `alloca` will be forgotten after a `longjmp` before it. – tehftw Sep 19 '18 at 06:47
  • 1
    It seems to me that it proves that `setjmp`/`longjmp` are dangerous beasts. – Yongwei Wu Jul 22 '20 at 08:06
10

Here's why:

char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;

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 to alloca 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).

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    The world may never know. :( That said, I'm hoping you could clarify a question I have about `alloca`. You said that nearly all code that uses it has a bug, but I was planning on using it; I'd normally ignore such a claim, but coming from you I won't. I'm writing a virtual machine and I'd like to allocate variables that don't escape from the function on the stack, instead of dynamically, because of the enormous speed-up. Is there an alternate approach that has the same performance characteristics? I know I can get close with memory pools, but that still isn't as cheap. What would you do? – GManNickG May 26 '11 at 02:33
  • Feel free to allocate small objects on the stack - it's safe - but in this case a single fixed-size buffer (e.g. `unsigned char buf[1024];`) with some simple code to manage carving it up and maintaining alignment would work just as well, and would be more portable by avoiding `alloca`. The only benefits VLA or `alloca` can give you are the ability to make arbitrarily large allocations (with the danger that entails) or the ability to make arbitrarily small allocations (e.g. to avoid wasting stack space when less than 1024 bytes are needed). – R.. GitHub STOP HELPING ICE May 26 '11 at 02:52
  • 7
    `*0=9;` is not valid C. As for testing the size you pass to `alloca`, test it against what? There's no way to know the limit, and if you're just going to test it against a tiny fixed known-safe size (e.g. 8k) you might as well just use a fixed-size array on the stack. – R.. GitHub STOP HELPING ICE Nov 17 '11 at 03:07
  • 7
    The trouble with your "either the size is known to be small enough or it's input-dependent and thus could be arbitrarily large" argument as I see it is that it applies just as strongly to recursion. A practical compromise (for both cases) is to assume that if the size is bounded by `small_constant * log(user_input)` then we probably have enough memory. – j_random_hacker Apr 16 '12 at 03:00
  • 1
    Indeed, you have identified the ONE case where VLA/alloca is useful: recursive algorithms where the max space needed at any call frame could be as large as N, but where the sum of the space needed at all recursion levels is N or some function of N that does not grow quickly. – R.. GitHub STOP HELPING ICE Apr 16 '12 at 05:17
  • Insightful answer. Are there historical vulnerabilities that have resulted from using `alloca()` on inputs controlled by an attacker (or allocating a VLA based on the same), perhaps recorded as CVEs? – Pascal Cuoq Mar 24 '14 at 10:00
  • 1
    *There's no way to know the limit* -- Stack can be explicitly set[1], so it can be known, it's just not very practical. [1 - pthread_attr_setstack](http://man7.org/linux/man-pages/man3/pthread_attr_setstack.3.html) – bestsss Jun 11 '14 at 11:08
  • @bestsss: That does not help because you have no control over how much the compiler uses. Obviously real compilers aim for some sanity, but they can still waste plenty aligning stack frames, inlining functions that have large stack-based buffers and not reusing the space as soon as the inline function is done, etc. BTW `pthread_attr_setstack` has some major issues and should not be used. `pthread_attr_setstacksize` is the preferred operation. – R.. GitHub STOP HELPING ICE Jun 11 '14 at 13:21
  • What are the issues aside non-portability - like architectures with 2 stacks one for data one for return addresses and tri-red zone (e.g. Itanium)? I mean besides some difficulty to use it properly what can cause problems? – bestsss Jun 11 '14 at 19:22
  • "almost certainly comes from some sort of input"? Not my code. I use `alloca()` for allocating variable-size structs (that is, structs with a variable-size array as the last element). It's awesome.. – Todd Lehman Aug 25 '15 at 23:19
  • @ToddLehman: Where does the size of that "variable-size last element" come from? – R.. GitHub STOP HELPING ICE Aug 26 '15 at 00:08
  • @R.. — A static const table. Or in most cases (in the program in which I use it the most), it's the number of factors in the prime factorization of a number, which inherently is capped at 63 for a 64-bit integer — no matter how large, even if it's provided by the user. Therefore, I can safely stake my life on the fact that there are never more than 63 elements. This, in fact, goes beyond due diligence of checking user-supplied input. Here, it is physically impossible (short of a code bug) to have more than 63 elements. – Todd Lehman Aug 26 '15 at 00:59
  • @ToddLehman: Then there's no point in using `alloca`. Use a fixed-size 63-element array. The stack usage will not be noticeably different, and your program will perform better (because `alloca` requires a frame pointer register or equivalent, increasing register pressure and complexity of local data access). As discussed above, nearly the only places where you can't just substitute a constant-size array in place of `alloca` are places where `alloca` is unsafe. – R.. GitHub STOP HELPING ICE Aug 26 '15 at 03:27
  • 1
    @R.. — Nope! No good. Can't use a fixed-size 63-element array for this, because then I'd have to have two separate struct definitions (one for a fixed-size array and one for a variable-size array), which in would in turn mean twice as many functions that operate on the struct. I actually need the variable-size array for the structs that are allocated from the heap. In certain cases, I can allocate on the stack for temporary processing. It's really nice having just one struct that does it all, and it would be a nightmare if I had to use a fixed-size array. `alloca` is pure sweetness for this. – Todd Lehman Aug 26 '15 at 05:33
  • @ToddLehman: Older compilers had no problem with code that used one function to work with structures which matched except for the size of an included array. I wish the Standard would acknowledge that such techniques were useful and should be recognized on the 99% of platforms where they will naturally work if the "optimizer" doesn't get in the way. – supercat Mar 31 '16 at 22:21
  • @supercat — But even then, why bother having two different structure definitions (one for heap, one for stack)? `alloca` is insanely fast. For all practical purposes, it's just as fast to allocate a variable-sized struct on the stack with `alloca` than it is to allocate a fixed-size struct on the stack as a variable. I mean, sure, it would work to have two different definitions and maybe do a cast to keep the compiler happy, but why bother? Dynamically allocating a variable-size struct on the stack saves space compared to fixed-size allocation, and it doesn't waste time. Have cake, eat it too! – Todd Lehman Apr 01 '16 at 15:01
  • 1
    @ToddLehman: The way alloca() is specified makes it impossible for many compilers to support it without--at minimum--disabling what would otherwise be useful optimizations. The normal implementation presupposes that at the time alloca() is performed, there will be nothing on the stack that will need to be removed before the next time the stack pointer can be reloaded with the frame pointer. If that reload doesn't happen as expected (e.g. because of function in-lining) bad things can happen. Actually, I think you could get by with one function to work on the structure if you use a union... – supercat Apr 01 '16 at 15:14
  • 1
    ...between the FAM structure and a fixed-sized array sufficient to force the required allocation. If alloca() had more tightly-specified usage which required using a freea() [which could be specified either as requiring that every alloca() be matched with freea(), or saying that any freea() will release everything alloca'ed after the given object], then all compilers could implement it. The concept of a LIFO alloc is a good one, regardless of whether it uses the execution stack to hold variables, since it can avoid fragmentation if code creates a temporary object of estimated size... – supercat Apr 01 '16 at 15:17
  • 1
    ...and then constructs a new object of exact size, suitably formats the data from the temporary object into the new one, and no longer needs the temporary object. Even if an implementation used the heap for the temporary object, it could make the allocation somewhat oversized and recycle the same object between uses. – supercat Apr 01 '16 at 15:19
  • @supercat — Wouldn't a `union` result in a size equal to the larger of the two sizes inside it, e.g., always the size of the fixed-size structure? That would be ok in the case of stack allocation, but in the case of heap allocation it would defeat the whole purpose of using a variable-size structure. Interesting idea, though, if it could be made work. As to portability...good point. In my case, however, portability isn't something I care about, because I'm writing specifically for Clang/LLVM and iOS, so that's why I use `alloca` liberally. But I understand the conerns. – Todd Lehman Apr 01 '16 at 18:44
  • 1
    @ToddLehman: You would only use the union for the stack allocation, and pass the address of the object inside it to code expecting the heap type. – supercat Apr 01 '16 at 18:46
  • @supercat — Interesting...could work! Alternatively, you could define two structures (one with a zero-element array as the last element and the other with a non-zero length array as the last element) and cast the pointer, rather than using a `union`. Not quite as clean, but it would avoid having three `typedef`s (one for the variable-size struct, one for the fixed-size struct, and one for the union) because it would require only two `typedef`s. Then again, `alloca` is still arguably nicer than having to write two `typedef`s for every variable-length struct, assuming `alloca` is available. – Todd Lehman Apr 01 '16 at 19:04
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107983/discussion-between-supercat-and-todd-lehman). – supercat Apr 01 '16 at 19:10
  • Your argument against alloca due to the variable input size can be made for many recursive functions too. – Thomas Eding Jan 09 '21 at 23:20
9

alloca () is nice and efficient... but it is also deeply broken.

  • broken scope behavior (function scope instead of block scope)
  • use inconsistant with malloc (alloca()-ted pointer shouldn't be freed, henceforth you have to track where you pointers are coming from to free() only those you got with malloc())
  • bad behavior when you also use inlining (scope sometimes goes to the caller function depending if callee is inlined or not).
  • no stack boundary check
  • undefined behavior in case of failure (does not return NULL like malloc... and what does failure means as it does not check stack boundaries anyway...)
  • not ansi standard

In most cases you can replace it using local variables and majorant size. If it's used for large objects, putting them on the heap is usually a safer idea.

If you really need it C you can use VLA (no vla in C++, too bad). They are much better than alloca() regarding scope behavior and consistency. As I see it VLA are a kind of alloca() made right.

Of course a local structure or array using a majorant of the needed space is still better, and if you don't have such majorant heap allocation using plain malloc() is probably sane. I see no sane use case where you really really need either alloca() or VLA.

kriss
  • 23,497
  • 17
  • 97
  • 116
  • I don't see the reason for the downvote (without any comment, by the way) – gd1 Feb 25 '15 at 18:39
  • 1
    Only names have scope. `alloca` doesn't create a name, only a memory range, which has **lifetime**. – curiousguy Oct 27 '15 at 06:27
  • @curiousguy: you're merely playing with words. For automatic variables I could as well speak of lifetime of the underlying memory as it match the scope of the name. Anyway the trouble is not how we call it, but the instability of the lifetime/scope of memory returned by alloca and the exceptional behavior. – kriss Oct 27 '15 at 08:53
  • 3
    I wish alloca had had a corresponding "freea", with a specification that calling "freea" would undo the effects of the "alloca" that created the object and all subsequent ones, and a requirement that storage 'alloca'ed within a fucntion must be 'freea'ed within it as well. That would have made it possible for nearly all implementations to support alloca/freea in a compatible fashion, would have eased the inlining issues, and generally made things a lot cleaner. – supercat Mar 31 '16 at 22:15
  • 3
    @supercat — I wish so too. For that reason (and more), I use an abstraction layer (mostly macros and inline functions) so that I don't ever call `alloca` or `malloc` or `free` directly. I say things like `{stack|heap}_alloc_{bytes,items,struct,varstruct}` and `{stack|heap}_dealloc`. So, `heap_dealloc` just calls `free` and `stack_dealloc` is a no-op. This way, the stack allocations can easily be downgraded to heap allocations, and the intentions are more clear as well. – Todd Lehman Apr 01 '16 at 15:09
  • calling alloca inside a function prevents it from being inlined. – greggo Oct 12 '20 at 17:47
8

alloca is not worse than a variable-length array (VLA), but it's riskier than allocating on the heap.

On x86 (and most often on ARM), the stack grows downwards, and that brings with it a certain amount of risk: if you accidentally write beyond the block allocated with alloca (due to a buffer overflow for example), then you will overwrite the return address of your function, because that one is located "above" on the stack, i.e. after your allocated block.

_alloca block on the stack

The consequence of this is two-fold:

  1. The program will crash spectacularly and it will be impossible to tell why or where it crashed (stack will most likely unwind to a random address due to the overwritten frame pointer).

  2. It makes buffer overflow many times more dangerous, since a malicious user can craft a special payload which would be put on the stack and can therefore end up executed.

In contrast, if you write beyond a block on the heap you "just" get heap corruption. The program will probably terminate unexpectedly but will unwind the stack properly, thereby reducing the chance of malicious code execution.

rustyx
  • 80,671
  • 25
  • 200
  • 267
7

Processes only have a limited amount of stack space available - far less than the amount of memory available to malloc().

By using alloca() you dramatically increase your chances of getting a Stack Overflow error (if you're lucky, or an inexplicable crash if you're not).

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • 4
    That depends very much on the application. It is not unusual for a memory-limited embedded application to have a stack size larger than the heap (if there even IS a heap). – EBlake Mar 04 '20 at 21:20
7

A place where alloca() is especially dangerous than malloc() is the kernel - kernel of a typical operating system has a fixed sized stack space hard-coded into one of its header; it is not as flexible as the stack of an application. Making a call to alloca() with an unwarranted size may cause the kernel to crash. Certain compilers warn usage of alloca() (and even VLAs for that matter) under certain options that ought to be turned on while compiling a kernel code - here, it is better to allocate memory in the heap that is not fixed by a hard-coded limit.

Nubok
  • 3,502
  • 7
  • 27
  • 47
  • 8
    `alloca()` is no more dangerous than `int foo[bar];` where `bar` is some arbitrary integer. – Todd Lehman Aug 25 '15 at 23:20
  • 3
    @ToddLehman That's correct, and for that exact reason we've banned VLAs in the kernel for several years, and have been VLA-free since 2018 :-) – Chris Down Apr 25 '20 at 11:33
5

Sadly the truly awesome alloca() is missing from the almost awesome tcc. Gcc does have alloca().

  1. It sows the seed of its own destruction. With return as the destructor.

  2. Like malloc() it returns an invalid pointer on fail which will segfault on modern systems with a MMU (and hopefully restart those without).

  3. 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 use malloc().

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 the realloc().

3.2.5.2 Advantages of alloca

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
zagam
  • 87
  • 1
  • 2
  • 5
    Actually the alloca spec does not say it returns an invalid pointer on fail (stack overflow) it says it has undefined behavior... and for malloc it says it returns NULL, not a random invalid pointer (OK, Linux optimistic memory implementation makes that useless). – kriss Sep 02 '14 at 10:04
  • @kriss Linux may kill your process, but at least it doesn't venture into undefined behaviour – craig65535 Oct 06 '17 at 07:25
  • @craig65535: the expression *undefined behavior* usually means that that behavior isn't defined by C or C++ specification. Not in any way that it will be random or unstable on any given OS or compiler. Therefore it's meaningless to associate UB with the name of an OS like "Linux" or "Windows". It has nothing to do with it. – kriss Oct 07 '17 at 07:06
  • I was trying to say that malloc returning NULL, or in the case of Linux, a memory access killing your process, is preferable to the undefined behaviour of alloca. I think I must have misread your first comment. – craig65535 Oct 07 '17 at 18:19
3

Actually, alloca is not guaranteed to use the stack. Indeed, the gcc-2.95 implementation of alloca allocates memory from the heap using malloc itself. Also that implementation is buggy, it may lead to a memory leak and to some unexpected behavior if you call it inside a block with a further use of goto. Not, to say that you should never use it, but some times alloca leads to more overhead than it releaves frome.

  • 1
    It sounds as if gcc-2.95 broke alloca and probably can't be safely used for programs that require `alloca`. How would it have cleaned up the memory when `longjmp` is used to abandon frames that did `alloca`? When would anyone use gcc 2.95 today? – Kaz Sep 18 '18 at 02:20
2

In my opinion, alloca(), where available, should be used only in a constrained manner. Very much like the use of "goto", quite a large number of otherwise reasonable people have strong aversion not just to the use of, but also the existence of, alloca().

For embedded use, where the stack size is known and limits can be imposed via convention and analysis on the size of the allocation, and where the compiler cannot be upgraded to support C99+, use of alloca() is fine, and I've been known to use it.

When available, VLAs may have some advantages over alloca(): The compiler can generate stack limit checks that will catch out-of-bounds access when array style access is used (I don't know if any compilers do this, but it can be done), and analysis of the code can determine whether the array access expressions are properly bounded. Note that, in some programming environments, such as automotive, medical equipment, and avionics, this analysis has to be done even for fixed size arrays, both automatic (on the stack) and static allocation (global or local).

On architectures that store both data and return addresses/frame pointers on the stack (from what I know, that's all of them), any stack allocated variable can be dangerous because the address of the variable can be taken, and unchecked input values might permit all sorts of mischief.

Portability is less of a concern in the embedded space, however it is a good argument against use of alloca() outside of carefully controlled circumstances.

Outside of the embedded space, I've used alloca() mostly inside logging and formatting functions for efficiency, and in a non-recursive lexical scanner, where temporary structures (allocated using alloca() are created during tokenization and classification, then a persistent object (allocated via malloc()) is populated before the function returns. The use of alloca() for the smaller temporary structures greatly reduces fragmentation when the persistent object is allocated.

2

Why no one mentions this example introduced by GNU documention?

https://www.gnu.org/software/libc/manual/html_node/Advantages-of-Alloca.html

Nonlocal exits done with longjmp (see Non-Local Exits) automatically free the space allocated with alloca when they exit through the function that called alloca. This is the most important reason to use alloca

Suggest reading order 1->2->3->1:

  1. https://www.gnu.org/software/libc/manual/html_node/Advantages-of-Alloca.html
  2. Intro and Details from Non-Local Exits
  3. Alloca Example
Rick
  • 7,007
  • 2
  • 49
  • 79
1

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.

0

IMO the biggest risk with alloca and variable length arrays is it can fail in a very dangerous manner if the allocation size is unexpectedly large.

Allocations on the stack typically have no checking in user code.

Modern operating systems will generally put a guard page in place below* to detect stack overflow. When the stack overflows the kernel may either expand the stack or kill the process. Linux expanded this guard region in 2017 to be significantly large than a page, but it's still finite in size.

So as a rule it's best to avoid allocating more than a page on the stack before making use of the previous allocations. With alloca or variable length arrays it's easy to end up allowing an attacker to make arbitrary size allocations on the stack and hence skip over any guard page and access arbitrary memory.

* on most widespread systems today the stack grows downwards.

plugwash
  • 9,724
  • 2
  • 38
  • 51
  • I've heard that explanation many times, but it doesn't make any sense to me. Calling any function can "fail in a very dangerous manner", especially if that function is recursive or uses a lot of stack memory. – Sapphire_Brick Jan 27 '22 at 01:52
  • A recursive function (that uses a normal amount of stack space per recursion level) will allocate stack space gradually, so it will hit the guard page and trigger stack expansion or stack overflow handling. – plugwash Jan 27 '22 at 11:57
  • A function that allocates a fixed large amount of space on the stack is indeed a risk, but it's still IMO less of a risk than alloca/VLA because if it was going to cause memory violations it would likely cause them during development. – plugwash Jan 27 '22 at 11:59
  • Whereas with alloca/VLA you can have a function that normally allocates an appropriate amount of space on the stack, but can be manipulated by an attacker to access locations at arbitrary offsets from the stack. – plugwash Jan 27 '22 at 12:01
-1

Most answers here largely miss the point: there's a reason why using _alloca() is potentially worse than merely storing large objects in the stack.

The main difference between automatic storage and _alloca() is that the latter suffers from an additional (serious) problem: the allocated block is not controlled by the compiler, so there's no way for the compiler to optimize or recycle it.

Compare:

while (condition) {
    char buffer[0x100]; // Chill.
    /* ... */
}

with:

while (condition) {
    char* buffer = _alloca(0x100); // Bad!
    /* ... */
}

The problem with the latter should be obvious.

alecov
  • 4,882
  • 2
  • 29
  • 55
  • Do you have any practical examples demonstrating the difference between VLA and `alloca` (yes, I do say VLA, because `alloca` is more than just creator of statically-sized arrays)? – Ruslan Apr 29 '17 at 15:33
  • There are use cases for the second one, which the first doesn't support. I may want to have 'n' records after the loop is done running 'n' times - perhaps in a linked-list or tree; this data structure then being disposed of when the function eventually returns. Which is not to say I would code anything that way :-) – greggo Jan 18 '18 at 19:20
  • 2
    And I would say that "compiler can't control it" is because that's the way that alloca() is defined; modern compilers know what alloca is, and treat it specially; it's not just a library function like it was in the 80's. C99 VLAs are basically alloca with block scope (and better typing). Not any more or less control, just conforming to different semantics. – greggo Jan 18 '18 at 19:28
  • @greggo: If you're the downvoter, I would gladly hear why you think my answer is not useful. – alecov Jan 18 '18 at 20:16
  • In C, recycling is not the task of the compiler, instead it is the task of the c library (free() ). alloca() is freed on return. – peterh Dec 10 '19 at 13:16
  • A compiler can certainly optimize and recycle `_alloca(FIXED_COMPILE_TIME_VALUE)` in many cases. – Thomas Eding Jan 09 '21 at 23:28
  • If you pull the alloca out of the loop, that should be fine – user16217248 Jun 28 '21 at 06:22