Hi all:
I am reading the Linux System Programming written by Robert Love.In the memory
management chapter,Love said it is dangerous to use alloca() allocated memory in the parameters to a function call,code like the below is off-limits.
1 2 3
void* alloca(size_t size);//allocate size bytes from the stack,return the pointer to that
/*DO NOT DO THIS*/
ret = foo(x,alloca(10));
as far as i am concerned,the allocated memory will exist in the middle of the stack space reserved for the function parameters,but i dont see any danger there.
Anyone who has any thoughts on this,please share.
I'm with you on this, but the concerns may be:
1. Stack space. The stack should be considered a scarce resource, although these days scarce means less than it did in the past.
2. Conventions. As long as the called function is aware that the buffer isn't from the heap (and doesn't call realloc/free on it) it should be ok.
I've not seen any. The times I've run into notes on alloca, are cautions to avoid it, but mostly to it's non-portability. Surprisingly, it's not a standard function.
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 argument
It would be compiler dependant and I don't know all the details. But I would assume that this is not an unlikely scenario.
When the compiler generates the code for a function it calculates stack offsets from the formal parameter declarations to access each variable.
When generating the code to call that function it may populate the formal parameters with the actual parameters based on an offset from the current stack pointer. If one of the actual parameters calls alloca() (which has the side effect of changing the stack pointer) in the middle of the parameter copying process that could mess up the calculations and place the actual parameters too far up the stack.
The compiler generated code for the execution of the function may well be expecting them to be lower down and consecutive to one another. After all, it has no idea that alloca() has been called in the middle of the actual parameter copying process.
For example, to copy the actual parameters a1, a2 and 3 into the formal parameters f1, f2 and f3 I might do this:
1 2 3 4 5 6 7 8 9 10
// tos == top of stack
tos += sizeof(f1);
*tos = a1;
tos += sizeof(f2);
*tos = a2;
tos += sizeof(f3);
*tos = a3;
Now imagine if instead of copying a2 into f2's offset it calls alloca() which moves the top of stack (tos) we would have something like:
1 2 3 4 5 6 7 8 9 10
// tos == top of stack
*tos = a1;
tos += sizeof(f1);
*tos = alloca(12); // tos is incremented by 12 bytes
tos += sizeof(f2);
*tos = a3; // now this parameter is 12 bytes too high
tos += sizeof(f3);
I couldn't produce any parameter corruption of the type that I described may happen. But I did detect a drift in where memory is allocated on the stack between successive calls suggesting a memory leak. It certainly strikes me as a sensitive place to change the stack pointer.
EDIT: I just realised that alloca() is not deallocated until the *calling* function exits. So the memory drift will occur until the calling function has ended. When I allowed for that, the memory offsets returned to normal. So, no memory leak either.
@Galik,i know what you mean and that is a good point.It is just your second code snippet that makes me head-lost again.
Isn't it like below:
1 2 3 4 5 6 7 8 9 10
//tos = top of stack
tos += sizeof(f1); //same as your first code snippet
*tos = a1;
tos = alloca(12) ;
tos += sizeof(f2);
*tos = alloca(12); //because we need to copy the start address of allocated block to the formal parameter
tos += sizeof(f3); //same operation as you first code snippet
*tos = a3;
Plus,When you mean the implementation is compiler dependent, does it imply my version of the stack pointer movement is also probable ?
What I gave was just an example of how things *might* go wrong. I don't know how my compiler actually implements a function call but my tests indicate that using alloca() does not interfere with it.
I can't really understand your version of the call. What I was trying to convey is the idea of pushing the actual parameters onto the stack in succession, but making a function call in the middle of that process that modified the top of the stack. That would place the subsequent push operations higher up the stack than the function execution code might be expecting.
when you mean 'higher up the stack', is it possible to lower down the stack because the allocated memory could be from the lower part of the stack space .
My understanding of alloca() is that it simply moves the stack pointer forward so it allocates memory at the current top-of-stack. But that too is probably implementation dependant.