Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: Call free on an automatic variable?

Tags:

c

int main()
{
    int x = 0;
    free(x);
}

This compiles and appears to be a no-op. What actually happens? is this behavior defined?

Thanks!

like image 615
rshepherd Avatar asked Feb 25 '10 22:02

rshepherd


People also ask

Does C automatically free malloc?

In C/C++ "auto" variables are allocated on the stack. They are destroyed right at the exit from the function. This will happen automatically. You do not need to write anything for this.

Can I free a static variable in C?

You shouldn't do that. free is only used for memory dynamically allocated from heap by malloc family of functions. Memory for num is statically allocated in data segment and can't be released.

When should I use free () in C?

“free” method in C is used to dynamically de-allocate the memory. The memory allocated using functions malloc() and calloc() is not de-allocated on their own. Hence the free() method is used, whenever the dynamic memory allocation takes place. It helps to reduce wastage of memory by freeing it.

What is a automatic variable in C?

Automatic VariableAll variables in C that are declared inside the block, are automatic variables by default. We can explicitly declare an automatic variable using auto keyword. void main(){ int x=10;//local variable (also automatic) auto int y=20;//automatic variable.


1 Answers

No, the behavior is not defined. Moreover, the code is not supposed to compile.

Firstly, the code is not supposed to compile because it contains a constraint violation. The expression you are passing as an operand to free has int type. The parameter of free has void * type. The only case when an int value can be implicitly converted to void * type is when the int value is an Integral Constant Expression (ICE) with value 0. In your case x is not an ICE, meaning that it is not implicitly convertible to void *. The only reason your code compiles is that for historical reasons (to support legacy code) your compiler quietly overlooks the constraint violation present in the free(x) call. I'm sure that if you elevate the level of warnings in your compiler, it will complain (at least with a warning). A pedantic compiler will immediately issue an error for free(x) call. Try Comeau Online, for example in C89/90 mode:

"ComeauTest.c", line 6: error: argument of type "int" is incompatible with parameter
          of type "void *"
      free(x); 
           ^

(Also, did you remember to include stdlib.h before calling free?)

Secondly, let's assume that the code compiles, i.e. it is interpreted by the compiler as free((void *) x). In this case a non-constant integral value x is converted to pointer type void *. The result of this conversion is implementation defined. Note, that the language guarantees that when an ICE with value of 0 is converted to pointer type, the result is a null pointer. But in your case x is not an ICE, so the result of the conversion is implementation-defined. In C there's no guarantee that you will obtain a null pointer by converting a non-ICE integer with value 0 to pointer type. On your implementation it probably just happened that (void *) x with non-ICE x equal to 0 produces a null pointer value of type void *. This null pointer value, when passed to free, results in a no-op, per the specification of free.

In general case though, passing such a pointer to free will result in undefined behavior. The pointers that you can legally pass to free are pointers obtained by previous calls to malloc/calloc/realloc and null pointers. Your pointer violates this constraint in general case, so the behavior is undefined.

This is what happens in your case. But, again, your code contains a constraint violation. And even if you override the violation, the behavior is undefined.

P.S. Note, BTW, that many answers already posted here make the same serious mistake. They assume that (void *) x with zero x is supposed to produce a null pointer. This is absolutely incorrect. Again, the language makes absolutely no guarantees about the result of (void *) x when x is not an ICE. (void *) 0 is guaranteed to be null pointer, but (void *) x with zero x is not guaranteed to be null pointer.

This is covered in C FAQ http://c-faq.com/null/runtime0.html . For those interested in better understanding of why it is so it might be a good idea to read the entire section on null pointers http://c-faq.com/null/index.html

like image 101
AnT Avatar answered Oct 23 '22 15:10

AnT