Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can alloca() memory be reallocated?

Memory allocated by malloc can be reallocated with realloc. Is there a similar function for alloca? Reallocating stack memory could be useful when you don't want memory to be allocated on the heap, and you need to allocate variable stack memory multiple times, for example in a library function, where you need dynamic memory, but don't want to allocate on the heap, because the user of the library might use a custom heap allocation strategy. It would look like this:

int main(void) {
    float * some_mem = alloca(40 * sizeof(float));
    // do something with this memory...

    // now we need a different amount of memory, but some_mem still occupies a lot of the stack, so just reallocate it.

    // is something like this possible?
    some_mem = realloca(some_mem, 50 * sizeof(float));
}

The important thing is that this all happens on the stack. Q: is there a way to reallocate dynamic stack memory?

like image 661
Phridge Avatar asked May 31 '19 10:05

Phridge


People also ask

Does Alloca need to be freed?

Since every compiler does alloca() differently, you'd have to rewrite your freea() for each compiler. But I find it hard to believe this would be worth the trouble. Just use malloc/free if you need to explicitly free it - those functions are usually heavily optimized.

How does alloca work?

The alloca() function allocates size bytes of space in the stack frame of the caller. This temporary space is automatically freed when the function that called alloca() returns to its caller.

Can alloca return null?

You can check for errors with alloca. It returns NULL on failure. You have the same problem as with error checking malloc. On platforms with overcommit (any fork-based UNIX, except maybe Solaris) it doesn't fail at allocation time, it fails when you try to access the memory and fail to map a page.

Should I use Alloca?

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. do not return the pointer, or anything that contains it.


2 Answers

No: that wouldn't work with a stack as commonly implemented. A variable on the stack occupies a fixed range of addresses. The next variable comes immediately after it, so there's no room to grow. Consider a function like this:

void f(int x) {
    int i;
    float *a = alloca(40 * sizeof(float));
    int k;
    …
}

The stack after the function prologue looks something like this:

----------------+-----+-----+-----+-------------------+-----+---------------------
...             | ret | x   | i   | a                 | k   | ...                 
----------------+-----+-----+-----+-------------------+-----+---------------------
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
previous frames                    f's frame                 free space at the top

There's no room to grow a.

I'm showing a highly simplified example: in the real world, variables end up in registers, variables can be reordered even if they do end up on the stack, etc. But only one variable can be the last one on the stack with room to grow.

So if realloca existed, it could only be applied to the variable that's at the top of the stack. (Or else it would have to move everything else that's on top of it, but that would require updating all existing pointers to those, which is not possible in general.) This would be a very limited mechanism, so support for this feature would have a very small benefit. Supporting it would have a significant cost, because compilers are normally free to put things on the stack in the order they want: this feature would require a new mechanism to let the compiler know that one specific variable must go to the top.

It's possible that some C implementation somewhere has realloca, but it's unlikely given the cost/benefit ratio.

Of course realloca can easily be implemented if alloca does not use a stack allocation strategy. But allocating on the stack is the whole point of alloca. If you want resizable objects, you need a memory management structure with a heap interface, and that's what malloc is for.


As a practical matter, there are several possible approaches to dynamic memory management in a library.

The most common approach is to call malloc, realloc and free when you need them. That's what they're for.

In some environments, it's useful to support custom allocators. You can give the user of the library the option to pass pointers to alternative implementations of malloc, realloc and free. It's useful when you want to write a portable library that needs to be used by code that is itself fully portable. Most of the time, though, users who want to use custom allocators can do it by linking their own malloc and friends. And even that is rarely useful.

If you need code that can work in an environment without dynamic allocation (such as safety-critical environments), then you should not use alloca either. alloca is worse than malloc because it causes unpredictable stack usage and can lead to a stack overflow which won't be detected at all, or which will only be detected by a program crash. If you need a variable (or large) amount of temporary memory in a function, have the user pass a suitably-sized buffer to you.

/** [documentation of the function] …
 * working_buffer must point to an array of floats of 3*n elements.
 */
void f(size_t n, float *working_buffer);

Better, if you have the code size budget, pass the array size and verify it.

/** [documentation of the function] …
 * working_buffer must point to an array of floats of 3*n elements.  
 */
int f(size_t n, float *working_buffer, size_t working_buffer_length)
{
    if (working_buffer_length < 3 * n) return -EINVAL;
    …
}
like image 147
Gilles 'SO- stop being evil' Avatar answered Oct 07 '22 07:10

Gilles 'SO- stop being evil'


The accepted answer has correctly pointed out that usually there is not enough benefit from realloca because allocations are difficult to "grow".

Another issue I see is that these allocations have a life time till the end of the function. What happens when you pass this pointer to another function and call realloca on it there? This function would not be able to change the stack frame of a function deeper on the stack. It also cannot reallocate it in its own frame because the object would be destroyed when it returns, whereas the original object would still have to be alive.

This problem is not there for malloc/realloc because the heap has a global lifetime.

One could argue that the semantics can be defined in such way that a function can be realloced only in the function it was alloc'd in. This greatly reduces the use such a function would have.

like image 3
Ajay Brahmakshatriya Avatar answered Oct 07 '22 08:10

Ajay Brahmakshatriya