6

My stackAlloc function looks like this:

void* stackAlloc(size_t size) {
    if (size > maxStackAllocation)
        return malloc(size);
    else 
        return _alloca(size);
}
void stackAllocFree(void *ptr, size_t size) {
    if (size > maxStackAllocation) {
        free(ptr);
    }
}

If I change so the stackAlloc function always use malloc instead of alloca everything works.

I changed the function to a macro, and now its working as expected:

#define maxStackAllocation 1024
#define stackAlloc(size) \
( \
    (size > maxStackAllocation)? \
         malloc(size): \
        _alloca(size) \
)

#define stackAllocFree(ptr, size) \
( \
    (size > maxStackAllocation)? \
        free(ptr): \
    void() \
)
hidayat
  • 9,493
  • 13
  • 51
  • 66

3 Answers3

9

Assuming you're running on Windows, since your code calls _alloca(), per the MSDN documentation:

_alloca allocates size bytes from the program stack. The allocated space is automatically freed when the calling function exits

Note that the memory is freed when the calling function exits - which I'm assuming also means the calling function returns.

Your code:

void* stackAlloc(size_t size) {
    if (size > maxStackAllocation)
        return malloc(size);
    else 
        return _alloca(size);
}

returns, thus freeing the memory obtained via _alloca().

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • 1
    I wonder if this applies if the function were marked `static inline __forceinline`. – Jonathon Reinhart Jun 13 '16 at 12:37
  • 2
    @JonathonReinhart, of course it applies there as well. `alloca` is not a "real" malloc, it just subtracts more space from the stackpointer. This means that it will ALWAYS be automatically freed, because the CPU takes care of that. Therefore it doesn't matter wether a function is inline or not. – Devolus Jun 13 '16 at 12:40
  • 1
    @JonathonReinhart Inlining is not allowed to change the semantics of the inlined function. (Inlining is not a macro-like substitution.) – molbdnilo Jun 13 '16 at 12:42
  • 1
    @Devolus I understand how `alloca` is implemented. If `esp` is subtracted in the (inlined) function, will the compiler add to `esp` immediately where the inlined function ends? Or will it forgo the cleanup until the calling function returns? – Jonathon Reinhart Jun 13 '16 at 13:36
  • @molbdnilo For "normal" inlining, I agree. But `__forceinline` is non-standard, so it would be reasonable for something like `alloca` to "work" in this case. Either way, the "right" answer here is, make this `stackAlloc` a macro, or don't use `alloca` at all. – Jonathon Reinhart Jun 13 '16 at 13:38
  • @JonathonReinhart, A quick test in VS2010 shows that it does NOT clean up immediately, which is what I would have expected anyway. There is no reason to do it, as it doesn't change the rest of a function. What I wonder though is, what happens if you do multiple allocations so the total becomes bigger than 1024. IMO there is no strict reason for this size limit, because the stack can be bigger anway (though obviously smaller then using heap allocation). – Devolus Jun 13 '16 at 14:01
  • @molbdnilo "_Inlining is not allowed to change the semantics of the inlined function_" says who? – curiousguy Dec 11 '18 at 23:10
3

From the man page,

This temporary space is automatically freed when the function that called alloca() returns to its caller.

So whenever your stackAlloc function returns, it will automatically free the memory.

James Elderfield
  • 2,389
  • 1
  • 34
  • 39
0

This works, but I'd advise against using it in production:

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

auto stackAlloc(const size_t size)
{
    return [size](){ return alloca(size); };
}

int main() {
    char *ch = (char *)stackAlloc(40000)();
    ch[39999] = '\0';

    return 0;
}

Counter-check: if I decrease stackAlloc's parameter, it doesn't work (which is the expected behaviour here) Feel free to add the check, etc. in stackAlloc (either by returning different lambdas or having the lambda do the check).

lorro
  • 10,687
  • 23
  • 36