Why is the use of alloca() not considered good practice?

前端 未结 22 2466
甜味超标
甜味超标 2020-11-22 03:00

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.

相关标签:
22条回答
  • 2020-11-22 03:25

    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.

    0 讨论(0)
  • 2020-11-22 03:26

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

    0 讨论(0)
  • 2020-11-22 03:26

    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.

    0 讨论(0)
  • 2020-11-22 03:26

    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

    0 讨论(0)
  • 2020-11-22 03:28

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

    0 讨论(0)
  • 2020-11-22 03:29

    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.

    0 讨论(0)
提交回复
热议问题