Passing pointer to local variable to function: is it safe? - c

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.

Related

static vs local definition of a pointer

For one of my projects, I am using a pointer to point a float type global variable. I am wondering if I define this as static vs local pointer with in a function, would one be a better definition than the other.
For Ex:
float a;
float b;
void foo(void)
{
static float *ptra;
float *ptrb;
ptra = &a;
ptrb = &b;
}
A static pointer is used to implement a function which returns the same buffer to the program, allocating it the first time it is called
Apart from
ptrb = &b;
being pointless (scope etc...)
Why use static pointer?
It serves no purpose and is very bad coding style.
If using a non static definition covers all needs, then use this. If it doesn't, use static.
I think the other answer is correct. I would add this as explanation: A static pointer (or variable) has the same life cycle than a global pointer (or variable), except that its "scope" is limited to the function.
It is not only used to return the same buffer (only one use case). You can also use it for other situations. For example if you want to implement a global counter or just save some state during the whole program life cycle (can be useful for a recursive function).
From my personal experience you may use it only in very rare cases.
static is persistent so if you declare it in a function, when you call the function again the value is the same as it was last time.
So use them when you need same value whenever function is called.
And about local pointer if pointer points to a local variable in the function block , so outside function block scope of variable ends and the pointer becomes dangling pointer . And thus accessing such pointer will cause segmentation fault.

initializing a local variable to data-segment string

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.

scope rules in C

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?

C stack/scope, variable's lifetime after functions ends

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.

Is there any point in declaring pointers for variables that are on the stack?

void my_cool_function()
{
obj_scene_data scene;
obj_scene_data *scene_ptr = &scene;
parse_obj_scene(scene_ptr, "test.txt");
}
Why would I ever create a pointer to a local variable as above if I can just do
void my_cool_function()
{
obj_scene_data scene;
parse_obj_scene(&scene, "test.txt");
}
Just in case it's relevant:
int parse_obj_scene(obj_scene_data *data_out, char *filename);
In the specific code you linked, there isn't really a reason.
It could be functionally necessary if you have a function taking an obj_scene_data **. You can't do &&scene, so you'd have to create a local variable before passing the address on.
Yes absolutely you can do this for many reasons.
For example if you want to iterate over the members of a stack allocated array via a pointer.
Or in other cases if you want to point sometimes to one memory address and other times to another memory address. You can setup a pointer to point to one or the other via an if statement and then later use your common code all within the same scope.
Typically in these cases your pointer variable goes out of scope at the same time as your stack allocated memory goes out of scope. There is no harm if you use your pointer within the same scope.
In your exact example there is no good reason to do it.
If the function accepts a NULL pointer as input, and you want to decide whether to pass NULL based on some condition, then a pointer to a stack variable is useful to avoid having to call the same function in separate code paths, especially if the rest of the parameters are the same otherwise. For example, instead of this:
void my_function()
{
obj_data obj = {0};
if( some condition )
other_function(&scene, "test.txt");
else
other_function(NULL, "test.txt");
}
You could do this:
void my_function()
{
obj_data obj = {0};
obj_data *obj_ptr = (condition is true) ? &obj : NULL;
other_function(obj_ptr, "test.txt");
}
If parse_obj_scene() is a function there may be no good reason to create a separate pointer. But if for some unholy reason it is a macro it may be necessary to reassign the value to the pointer to iterate over the subject data.
Not in terms of semantics, and in fact there is a more general point that you can replace all local variables with function calls with no change in semantics, and given suitable compiler optimisations, equal efficiency. (see section 2.3 of "Lambda: The Ultimate Imperative".)
But the point of writing code to communicate with the next person to maintain it, and in an imperative language without tail call optimisation, it is usual to use local variables for things which are iterated over, for automatic structures, and to simplify expressions. So if it makes the code more readable, then use it.

Resources