void someFunc()
{
int stackInt = 4;
someOtherFunc(&stackInt);
}
Is it the case that stackInt's address space could be reallocated after someFunc ends, making it unsafe to assume that the value passed to someOtherFunc represents the stackInt variable with value 4 that was passed to it? In other words, should I avoid passing stack variables around by address and expecting them to still be alive after the function they were initialised in has ended?
Yes, definitely.
You don't have to avoid passing stack-allocated variables by reference/pointer altogether, though, just storing pointers or references to stack-allocated variables.
After someFunc() returns and another function is called, the space that was used for stackInt will be used for some other variable in the new function. Therefore, the function someOtherFunc() cannot safely assume that if it keeps a copy of the pointer it is passed, that pointer will remain valid. If it stashes a copy of the value that was pointed at, that is fine.
So, although it is fine to pass stack variables around by address (so, for example someOtherFunc() could modify the value of stackInt and, if there was code in someFunc() that accessed it after the call, the value might not be 4 still), it is not safe to store the pointer and expect it to point to anywhere valid after someFunc() returns.
It is absolutely fine to pass stack variables as parameters in all possible ways
The stack allocated variables will be overwritten only when the function declaring those variables is completed its execution.
So until you return from someFunc() there is no harm to stackInt.
As long as you don't spawn new thread from someOtherFunc and use stackInt there, this will work.
Related
So I am working with a "standard" library with more than a decade of history for brain image I/O. I encountered this function:
nifti_image* nifti_image_read( const char *hname , int read_data ){
nifti_image* nim;
...
<<<some IO operations>>>
...
return nim;
}
My question is, how come this function is returning a local pointer to an automatic variable? Isn't this practice prohibited since the nim pointer goes out of scope and is supposed to be deleted after completion of the function?
I have already read this question but couldn't get my answer:
It's just returning the value of the nim pointer.
During the << some IO operations >> part I assume nim is set to point at some permanent memory in the heap or global.
This function is returning the value stored in the pointer and it is ok. The pointer value is the address of an object which is probably a allocated dynamically and is NOT deleted at the end, even if it was C++. The only possible issue is the case where the pointer points to another local variable, not allocated dynamically. So even though the pointer itself goes out of scope, the caller that receives the return value gets a copy of the address of a valid object.
You're not returning a pointer to a local variable. You're returning the value of a local variable which happens to be a pointer.
Assuming the pointer is not pointing to another local variable itself, this is a safe operation.
In c, let us say I have the following code:
int func(){
char* s = "bla";
}
I am not sure as to what this is compiled.
Since s isn't static, it doesn't survive after func() ends so it seems that the pointer to "bla" is lost.
On the other hand, the program should still know the address to "bla" so the next time func() is called, s will get the same address.
I wonder if the above code is ok or if I must declare s as static?
It is not clear how you are going to use this local pointer. Nevertheless the address of the string literal will be the same. It does not depend on how many times the function will be called. This string literal has static storage duration. So the pointer will be initialized with the same address each time when the function gets the control. There is no need to declare the pointer itself as static unless you change its initial value and want that it would be stored in the pointer between function's calls.
For example:
void func1(){
int i = 123;
func2(&i);
}
void func2(int *a){
*a = 456;
}
When func1 calling func2, a pointer to local variable is passed to func2 -- the pointer is pointed to the stack. Is this safe for the rules of C?
Thanks.
The scope of i is func1 and it outlives the call to func2. So it is perfectly safe.
As stated in most of the answers before, it is perfectly safe to pass the pointer to func2() in your special case.
In a real world piece of software however, I consider this harmful as you don't have control on what func2() is doing with your variable. func2() may create an alias to its parameter to use it asynchronously at a later point in time. And at that time, the local variable int i may be gone when this alias is used later.
So from my point of view passing a pointer to a local (automatic) variable is extremely dangerous and should be avoided.
You may do so if you declare the variable in func1() as static int i;
In that case, it is ensured, that the memory for i won't get recycled and overwritten. However you will need to setup some Mutex locking for access control to this memory in a concurrent environment.
To illustrate this problem here is some code I just stumbled in yesterday while doing software testing at my customer. And yes, it crashes...
void func1()
{
// Data structure for NVMemory calls
valueObj_t NVMemObj;
// a data buffer for eeprom write
UINT8 DataBuff[25];
// [..]
/* Assign the data pointer to NV Memory object */
NVMemObj.record = &DataBuff[0];
// [..]
// Write parameter to EEPROM.
(void)SetObject_ASync(para1, para2, para3, &NVMemObj);
return;
}
void SetObject_ASync(para1, para2, para3, valueObj_t *MemoryRef)
{
//[..]
ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr = MemoryRef->record;
//[..]
return;
}
In this case, the data in the DataBuff is long gone when the pointer in ASyncQueue.CommandArray[ASyncQueue.NextFreeEntry].BufferPtr is used to store the data to the EEPROM.
To fix this code, it is at least necessary to declare static UINT8 DataBuff[25]; Additionally, it shall be considered to also declare static valueObj_t NVMemObjas we don't know what the called function is doing with that pointer.
To put it briefly:
TL;DR
Even though it is legal in the C-language I consider it as harmful to pass pointers to automatic variables in a function call. You never know (and often you don't want to know) what exactly the called function does with the passed values. When the called function establishes an alias, you get in big trouble.
Just my 2 cents.
Yes it is safe to pass a pointer to a local variable but you can't return a pointer to an automatic local variable from a function.
Yes, your code is safe.
As long as the object's lifetime is not over, it's safe to pass local variables like you do.
Is this safe for the rules of C?
What you are doing is safe as the local variable is still valid and within the scope. Accessing the local varaible outside of its scope is undefined behvaior but this is totally fine
In your case, you can safely use &i till the time i is valid.
Now, as we can see i has a lifetime till the end of func1(). As, the func2() is being called from the func1() and the func1() has not yet finished execution, so, i is still valid.
That's why , usually passing the address of a local variable to another function is usually allowed (the variable's lifetime is not over) but, returning the address of a local variable (immediately after return, local variables of the function cease to exist) is not allowed.
TL;DR :You can safely use &i as the argument of func2() as shown here.
I recently read about scope rules in C. It says that a local or auto variable is available only inside the block of the function in which it is declared. Once outside the function it no longer is visible. Also that its lifetime is only till the end of the final closing braces of the function body.
Now here is the problem. What happens when the address of a local variable is returned from the function to the calling function ?
For example :-
main()
{
int *p=fun();
}
int * fun()
{
int localvar=0;
return (&localvar);
}
once the control returns back from the function fun, the variable localvar is no longer alive. So how will main be able to access the contents at this address ?
The address can be returned, but the value stored at the address cannot reliably be read. Indeed, it is not even clear that you can safely assign it, though the chances are that on most machines there wouldn't be a problem with that.
You can often read the address, but the behaviour is undefined (read 'bad: to be avoided at all costs!'). In particular, the address may be used for other variables in other functions, so if you access it after calling other functions, you are definitely unlikely to see the last value stored in the variable by the function that returned the pointer to it.
Why then is a function returning a pointer ever required?
One reason is often 'dynamic memory'. The malloc() family of functions return a pointer to new (non-stack) memory.
Another reason is 'found something at this location in a value passed to me'. Consider strchr() or strstr().
Another reason is 'returning pointer to a static object, either hidden in the function or in the file containing the source for the function'. Consider asctime() et al (and worry about thread-safety).
There are probably a few others, but those are probably the most common.
Note that none of these return a pointer to a local (stack-based) variable.
The variable is gone, but the memory location still exists and might even still contain the value you set. It will however probably get overwritten pretty fast as more functions are called and the memory address gets reused for another function's local variables. You can learn more by reading about the Call Stack, which is where local variables of functions are stored.
Referencing that location in memory after the function has returned is dangerous. Of course the location still exists (and it may still contain your value), but you no longer have any claim to that memory region and it will likely be overwritten with new data as the program continues and new local variables are allocated on the stack.
gcc gives me the following warning:
t.c: In function ‘test’:
t.c:3:2: warning: function returns address of local variable [enabled by default]
Consider this test program:
int * test(int p) {
int loc = p;
return &loc;
}
int main(void) {
int *c = test(4);
test(5);
printf("%d\n", *c);
return 0;
}
What do you think this prints?
Why can I return from a function an array setup by malloc:
int *dog = (int*)malloc(n * sizeof(int));
but not an array setup by
int cat[3] = {0,0,0};
The "cat[ ]" array is returned with a Warning.
Thanks all for your help
This is a question of scope.
int cat[3]; // declares a local variable cat
Local variables versus malloc'd memory
Local variables exist on the stack. When this function returns, these local variables will be destroyed. At that point, the addresses used to store your array are recycled, so you cannot guarantee anything about their contents.
If you call malloc, you will be allocating from the heap, so the memory will persist beyond the life of your function.
If the function is supposed to return a pointer (in this case, a pointer-to-int which is the first address of the integer array), that pointer should point to good memory. Malloc is the way to ensure this.
Avoiding Malloc
You do not have to call malloc inside of your function (although it would be normal and appropriate to do so).
Alternatively, you could pass an address into your function which is supposed to hold these values. Your function would do the work of calculating the values and would fill the memory at the given address, and then it would return.
In fact, this is a common pattern. If you do this, however, you will find that you do not need to return the address, since you already know the address outside of the function you are calling. Because of this, it's more common to return a value which indicates the success or failure of the routine, like an int, than it is to return the address of the relevant data.
This way, the caller of the function can know whether or not the data was successfully populated or if an error occurred.
#include <stdio.h> // include stdio for the printf function
int rainCats (int *cats); // pass a pointer-to-int to function rainCats
int main (int argc, char *argv[]) {
int cats[3]; // cats is the address to the first element
int success; // declare an int to store the success value
success = rainCats(cats); // pass the address to the function
if (success == 0) {
int i;
for (i=0; i<3; i++) {
printf("cat[%d] is %d \r", i, cats[i]);
getchar();
}
}
return 0;
}
int rainCats (int *cats) {
int i;
for (i=0; i<3; i++) { // put a number in each element of the cats array
cats[i] = i;
}
return 0; // return a zero to signify success
}
Why this works
Note that you never did have to call malloc here because cats[3] was declared inside of the main function. The local variables in main will only be destroyed when the program exits. Unless the program is very simple, malloc will be used to create and control the lifespan of a data structure.
Also notice that rainCats is hard-coded to return 0. Nothing happens inside of rainCats which would make it fail, such as attempting to access a file, a network request, or other memory allocations. More complex programs have many reasons for failing, so there is often a good reason for returning a success code.
There are two key parts of memory in a running program: the stack, and the heap. The stack is also referred to as the call stack.
When you make a function call, information about the parameters, where to return, and all the variables defined in the scope of the function are pushed onto the stack. (It used to be the case that C variables could only be defined at the beginning of the function. Mostly because it made life easier for the compiler writers.)
When you return from a function, everything on the stack is popped off and is gone (and soon when you make some more function calls you'll overwrite that memory, so you don't want to be pointing at it!)
Anytime you allocate memory you are allocating if from the heap. That's some other part of memory, maintained by the allocation manager. Once you "reserve" part of it, you are responsible for it, and if you want to stop pointing at it, you're supposed to let the manager know. If you drop the pointer and can't ask to have it released any more, that's a leak.
You're also supposed to only look at the part of memory you said you wanted. Overwriting not just the part you said you wanted, but past (or before) that part of memory is a classic technique for exploits: writing information into part of memory that is holding computer instructions instead of data. Knowledge of how the compiler and the runtime manage things helps experts figure out how to do this. Well designed operating systems prevent them from doing that.
heap:
int *dog = (int*)malloc(n*sizeof(int*));
stack:
int cat[3] = {0,0,0};
Because int cat[3] = {0,0,0}; is declaring an automatic variable that only exists while the function is being called.
There is a special "dispensation" in C for inited automatic arrays of char, so that quoted strings can be returned, but it doesn't generalize to other array types.
cat[] is allocated on the stack of the function you are calling, when that stack is freed that memory is freed (when the function returns the stack should be considered freed).
If what you want to do is populate an array of int's in the calling frame pass in a pointer to an that you control from the calling frame;
void somefunction() {
int cats[3];
findMyCats(cats);
}
void findMyCats(int *cats) {
cats[0] = 0;
cats[1] = 0;
cats[2] = 0;
}
of course this is contrived and I've hardcoded that the array length is 3 but this is what you have to do to get data from an invoked function.
A single value works because it's copied back to the calling frame;
int findACat() {
int cat = 3;
return cat;
}
in findACat 3 is copied from findAtCat to the calling frame since its a known quantity the compiler can do that for you. The data a pointer points to can't be copied because the compiler does not know how much to copy.
When you define a variable like 'cat' the compiler assigns it an address. The association between the name and the address is only valid within the scope of the definition. In the case of auto variables that scope is the function body from the point of definition onwards.
Auto variables are allocated on the stack. The same address on the stack is associated with different variables at different times. When you return an array, what is actually returned is the address of the first element of the array. Unfortunately, after the return, the compiler can and will reuse that storage for completely unrelated purposes. What you'd see at a source code level would be your returned variable mysteriously changing for no apparent reason.
Now, if you really must return an initialized array, you can declare that array as static. A static variable has a permanent rather than a temporary storage allocation. You'll need to keep in mind that the same memory will be used by successive calls to the function, so the results from the previous call may need to be copied somewhere else before making the next call.
Another approach is to pass the array in as an argument and write into it in your function. The calling function then owns the variable, and the issues with stack variables don't arise.
None of this will make much sense unless you carefully study how the stack works. Good luck.
You cannot return an array. You are returning a pointer. This is not the same thing.
You can return a pointer to the memory allocated by malloc() because malloc() has allocated the memory and reserved it for use by your program until you explicitly use free() to deallocate it.
You may not return a pointer to the memory allocated by a local array because as soon as the function ends, the local array no longer exists.
This is a question of object lifetime - not scope or stack or heap. While those terms are related to the lifetime of an object, they aren't equivalent to lifetime, and it's the lifetime of the object that you're returning that's important. For example, a dynamically alloced object has a lifetime that extends from allocation to deallocataion. A local variable's lifetime might end when the scope of the variable ends, but if it's static its lifetime won't end there.
The lifetime of an object that has been allocated with malloc() is until that object has been freed using the free() function. Therefore when you create an object using malloc(), you can legitimately return the pointer to that object as long as you haven't freed it - it will still be alive when the function ends. In fact you should take care to do something with the pointer so it gets remembered somewhere or it will result in a leak.
The lifetime of an automatic variable ends when the scope of the variable ends (so scope is related to lifetime). Therefore, it doesn't make sense to return a pointer to such an object from a function - the pointer will be invalid as soon as the function returns.
Now, if your local variable is static instead of automatic, then its lifetime extends beyond the scope that it's in (therefore scope is not equivalent to lifetime). So if a function has a local static variable, the object will still be alive even when the function has returned, and it would be legitimate to return a pointer to a static array from your function. Though that brings in a whole new set of problems because there's only one instance of that object, so returning it multiple times from the function can cause problems with sharing the data (it basically only works if the data doesn't change after initialization or there are clear rules for when it can and cannot change).
Another example taken from another answer here is regarding string literals - pointers to them can be returned from a function not because of a scoping rule, but because of a rule that says that string literals have a lifetime that extends until the program ends.