why dereferencing a C pointer after "free" gives value 0 [duplicate] - c

This question already has answers here:
Why do I get different results when I dereference a pointer after freeing it?
(7 answers)
Closed 9 years ago.
Below is the code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p=(int *)malloc(sizeof(int));
*p=5;
printf("Before freeing=%p\n",p);
printf("Value of p=%d\n",*p);
//making it dangling pointer
free(p);
printf("After freeing =%p\n",p);
printf("Value of p=%d\n",*p);
return 0;
}
Below is the output:
Before freeing=0x1485010
Value of p=5
After freeing =0x1485010
Value of p=0
After freeing the pointer, dereferencing gives the output "0"(zero).
Below is another code that also gives '0'
include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p=(int *)malloc(sizeof(int));
printf("Before freeing=%p\n",(void *)p);
printf("Value of p=%d\n",*p);
return 0;
}
In this i have not freed the memory , just allocated it , still it gives '0' .
Is it like the default value of every uninitialized pointer is '0'??
why is it so ?

Don't rely on this, it's undefined behaviour. free() doesn't have to set the pointer to zero, this is just what your current implementation is doing for you. If you want to be 100% sure, regardless of your compiler, platform, etc. set your pointer to NULL after freeing it.

This is simply undefined behavior if we look at the C99 draft standard Annex J.2 which covers undefined behavior says:
The behavior is undefined in the following circumstances:
and included the following bullet:
The value of a pointer that refers to space deallocated by a call to the free or
realloc function is used (7.20.3).
Setting a pointer to NULL after free'ing is usually a good idea and you can find a good discussion here on that topic.

Dereferencing an invalid pointer leads to undefined results per spec. It's not guaranteed to fail.

While the answers "it doesn't matter, it is UB" are in general sufficient, one might be curious why the value changes. Curiosity is (IMHO) a valid reason to know the reason of why something happens.
It depends on the memory management which might decide to store addresses of the "next free block" or whatever in a freed memory area.
So what you observe is probably an action of the memory management.
For example, the memory management MIGHT be implemented in that way that it manages two linked lists and an upper pointer. One linked list contains the allocated memory chunks, pointing maybe 8 or 16 bytes before the "really usable" memory, and the other linked list points to the first free chunk, which in turn contains a pointer to the next one. The memory above the upper pointer is considered as free.
If you free the first memory block, the free list pointer points to it, and its first pointer sized data is zeroed, meaning that there is no other freed block. And there is your reason why the memory is zeroed out.
It is nice to know that things like these exist and how they work, but refrain the temptation to make use of that knowledge in production programs. One day they may fall onto your feet...

Related

Memory allocation in C - referencing freed/deallocated location doesn't always cause segfault [duplicate]

This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 2 years ago.
According to theory of c programming variable a should be a dangling pointer and it should throw segmentation fault error. But here variable a is still pointing to same memory location.
#include<stdio.h>
#include<stdlib.h>
int main() {
int* a = (int*)malloc(sizeof(int));
printf("%lu\n", sizeof(a));
free(a);
*a = 20;
printf("%d\n", (*a));
return 0;
}
output :
8
20
How this can happen ? I executed this program on GCC and Clang both. They both produced the same output.
After you have free()-d the allocation, attempt to use that memory invokes undefined behaviour. Segmentation fault is one of the many side effcets of UB, but not the guranteed one.
According to theory of c programming variable a should be a dangling pointer and it should throw segmentation fault error.
There is no such theory or rule in C.
Memory allocation reserves memory for your use. Calling free removes the reservation. The free routine is not required to mark the memory as inaccessible.
The C standard defines an abstract model in which malloc reserves space for an object, and free ends the lifetime of that object. Within this model, two rules in the C standard apply in particular to your question. C 2018 6.2.4 2 says:
… If an object is referred to outside of its lifetime, the behavior is undefined…
As used in the C standard, “undefined” means the standard does not impose any requirements. That means the standard does not say you can access the memory, it does not say you cannot access the memory, it does not say your program will behave as if the object is still there, it does not say your program will behave as if they object is not there. It does not say whether your program will crash or not crash. The C standard simply says nothing about what will happen.
That paragraph also says:
… The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.
That means that, after free(a), the value of a is indeterminate. It is no longer specified by the C standard. This rule in the C standard arose because some C implementations had to use various assistive means to refer to memory, such as a pointer containing data that referred to a table or structure with further information. Once the memory is freed, that table or structure may itself be altered or destroyed, and then attempting to use the pointer would fail in various ways. So, in the C model, the value of the pointer is indeterminate. This means your sentence “But here variable a is still pointing to same memory location” is not specified to be true by the C standard. And, while common modern C implementations do not have these pointers relying on additional data, the rule remains a rule, and compilers may take advantage of it in their optimization. So you cannot rely on the value of a pointer after it has been passed to free.
To be clear: You not only cannot rely on the memory that was pointed to by the pointer, you cannot rely on the value of the pointer. Simply executing free(a); if (a == NULL) … has undefined behavior.
As others have pointed out already, accessing a freed pointer is undefined behavior.
The reason why it seems "usable" even after the free() call is because in most implementations of free(), this function does not release the memory location immediately to the OS for performance reasons. The freed memory location is now, however, reusable.
Here's an example of possible behavior of malloc() and free():
int* a = malloc(sizeof(int)); // pointer `a` has address 0xABCD
free(a); // address 0xABCD is now considered freed
*a = 5; // this works because nobody has "touched" yet address 0xABCD
int* b = malloc(sizeof(int)); // malloc() will reuse address 0xABCD since it is considered "free"
Of course, this is just a possible behavior.
TL;DR: do not use a pointer after free(), you can't know what will happen. It's an extremely dangerous (and useless) practice.
Its undefined behaviour. You may/may not get a seg fault. After free(a), a is a dangling pointer which points to no where. free() just releases the memory block allocated by malloc() and it doesn't change the value of pointer pointing to heap in that process address space. On some platforms you might get segfault if you try dereferencing pointer after freeing. Its good practice if you assign pointer a to NULL after freeing.

How come I can initialize a pointer that has zero bytes allocated to it? [duplicate]

This question already has answers here:
What's the point of malloc(0)?
(17 answers)
Closed 4 years ago.
I know that malloc(size_t size) allocates size bytes and returns a pointer to the allocated memory. .
So how come when I allocate zero bytes to the integer pointer p, I am still able to initialize it?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = malloc(0);
*p = 10;
printf("Pointer address is: %p\n", p);
printf("The value of the pointer: %d\n", *p);
return 0;
}
Here is my program output, I was expecting a segmentation fault.
Pointer address is: 0x1ebd260
The value of the pointer: 10
The behavior of malloc(0) is implementation defined, it will either return a pointer or NULL. As per C Standard, you should not use the pointer returned by malloc when requested zero size space1).
Dereferencing the pointer returned by malloc(0) is undefined behavior which includes the program may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
1) From C Standard#7.22.3p1 [emphasis added]:
1 The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
When you call malloc(0) and write to the returned buffer, you invoke undefined behavior. That means you can't predict how the program will behave. It might crash, it might output strange results, or (as in this case) it may appear to work properly.
Just because the program could crash doesn't mean it will.
In general, C does not prevent you from doing incorrect things.
After int *p = malloc(0);, p has some value. It might be a null pointer, or it might point to one or more bytes of memory. In either case, you should not use it.1 But the C language does not stop you from doing so.
When you execute *p = 10;, the compiler may have generated code to write 10 to the place where p points. p may be pointing at actual writable memory, so the store instruction may execute without failing. And then you have written 10 to a place in memory where you should not. At this point, the C standard no longer specifies what the behavior of your program is—by writing to an inappropriate place, you have broken the model of how C works.
It is also possible your compiler recognizes that *p = 10; is incorrect code in this situation and generates something other than the write to memory described above. A good compiler might give you a warning message for this code, but the compiler is not obligated to do this by the C standard, and it can allow your program to break in other ways.
Footnote
1 If malloc returns a null pointer, you should not write to *p because it is not pointing to an object. If it returns something else, you should not write to *p because C 2018 7.22.3.1 says, for this of malloc(0), “the returned pointer shall not be used to access an object.”
I think it is good idea to look at segmentation fault definition https://en.wikipedia.org/wiki/Segmentation_fault
The following are some typical causes of a segmentation fault:
Attempting to access a nonexistent memory address (outside process's address space)
Attempting to access memory the program does not have rights to (such as kernel structures in process context)
Attempting to write read-only memory (such as code segment)
So in general, access to any address in program's data segment will not lead to seg fault. This approach makes sence as C doesn't have any framework with memory management in it (like C# or Java). So as malloc in this example returns some address (not NULL) it returns it from program's data segment which can be accessed by program.
However if program is complex, such action (*p = 10) may overwrite data belonging to some other variable or object (or even pointer!) and lead to undefined behaviour (including seg fault).
But please take in account, that as described in other answers such program is not best practice and you shouldn't use such approach in production.
This is a source code of malloc() (maybe have a litter difference between kernel versions but concept still like this), It can answer your question:
static void *malloc(int size)
{
void *p;
if (size < 0)
error("Malloc error");
if (!malloc_ptr)
malloc_ptr = free_mem_ptr;
malloc_ptr = (malloc_ptr + 3) & ~3; /* Align */
p = (void *)malloc_ptr;
malloc_ptr += size;
if (free_mem_end_ptr && malloc_ptr >= free_mem_end_ptr)
error("Out of memory");
malloc_count++;
return p;
}
When you assigned size is 0, it already gave you a pointer to first address of memory

C - What Happens To Memory After free()? [duplicate]

This question already has answers here:
What happens to memory after free()?
(4 answers)
Closed 9 years ago.
I have this struct type that I malloc for, and after I free it the pointer still points to the data I assigned. Is that just because the pointer is pointing to memory that is free but hasn't been reallocated yet?
#include <stdio.h>
struct S {
int value;
}
int main () {
S *s = malloc(sizeof(struct S));
s->value = 8910;
free(s);
printf("s: %i\n", s->value);
}
Freed memory doesn't belong to you anymore. But that doesn't mean it disappears or gets changed in any way. Why would your program bother? It would be a waste of time. It probably just marks the memory as available for use by subsequent malloc()s, and that's it. Or it might not. Using memory that doesn't belong to you might do anything: return wrong values, crash, return right values, or run a flight simulator game. It's not yours; don't mess with it and you'll never have to worry about what it might do.
The C standard defines the behavior of the free function:
The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation.
which means that a later call to malloc (or something else) might re-use the same memory space.
As soon as a pointer is passed to free(), the object it pointed to reaches the end of its lifetime. Any attempt to refer to the pointed-to object has undefined behavior (i.e., you're no longer allowed to dereference the pointer).
More than that, the value of the pointer itself becomes indeterminate, so any attempt to refer to the pointer value has undefined behavior. Reference: N1570 6.2.4p2:
If an object is referred to outside of its lifetime, the behavior is
undefined. The value of a pointer becomes indeterminate when the
object it points to (or just past) reaches the end of its lifetime.
It's true that free()'s argument is passed by value (like all C function arguments), and so free can't actually modify the pointer. One way to think of it is that the pointer has the "same" value before and after the call, but that value is valid before the call and indeterminate after the call.
It's likely that an attempt to refer to the pointer value, or even to dereference it, will appear to "work". That's one of the many possible symptoms of undefined behavior (and arguably the worst, since it makes it difficult to detect and diagnose the error).
free() just declares, to the language implementation or operating system, that the memory is no longer required. When it is written over is not defined behavior.

The state of a pointer after deallocation

What does the pointer of a dynamically allocated memory points to after calling the free() function.
Does the pointer points to NULL, or it still points to the same place it pointed before the deallocation.
does the implementation of free() has some kind of standard for this, or it's implemented differently in different platforms.
uint8_t * pointer = malloc(12);
printf("%p", pointer); // The current address the pointer points to
free (pointer);
printf("%p", pointer); // must it be NULL or the same value as before ?
Edit:
I know that the printf will produce the same results, I just want to know if I can count on that on different implementations.
The pointer value is not modified. You pass the pointer (memory address) by value to free(). The free() function does not have access to the pointer variable, so it cannot set it to NULL.
The two printf() calls should produce identical output.
According to the standard (6.2.4/2 of C99):
The value of a pointer becomes indeterminate when the object it points
to reaches the end of its lifetime.
In practice, all implementations I know of will print the same value twice for your example code. However, it is permitted that when you free the memory, the pointer value itself becomes a trap representation, and the implementation does something strange when you try to use the value of the pointer (even though you don't dereference it).
Supposing that an implementation wants to do something unusual, a hardware exception or program abort would be the most plausible I think. You probably have to imagine an implementation/hardware that does a lot of extra work, though, so that every time a pointer value is loaded into a register, it somehow checks whether the address is valid. That could be by checking it in the memory map (in which case I suppose my hypothetical implementation would only trap if the whole page containing the allocation has been released and unmapped), or some other means.
free() only deallocates the memory. The pointer is still pointing to the old location (dangling pointer), which you should manually set to NULL.
Setting the pointer to NULL is a good practice. As the memory location may be reused for other object, you may be able to access and modify data which doesn't belong to you. This is especially hard to debug, since it won't produce a crash, or produce crash at some point which is irrelevant. Setting to NULL will guarantee a re-producible crash if you ever access the non-existent object.
I tried this code in C++
#include<iostream>
using namespace std;
int main(void)
{
int *a=new int;
*a=5;
cout<<*a<<" "<<a<<"\n";
delete a;
*a=45;
cout<<*a<<" "<<a<<"\n";
}
The output was something like this
5 0x1066c20
45 0x1066c20
Running once more yielded a similar result
5 0x13e3c20
45 0x13e3c20
Hence it seems that in gcc the pointer still points to the same memory location after deallocation.
Moreover we can modify the value at that location.

C code - malloc and free

consider the below code:
int main()
{
int *a,address,size;
a= (int *) malloc(10);
address=(int*) a-1;
size=(int ) *(a-1); // sorry there was a bug wrong casting, now its corrected.
printf("address of malloc n:%d\n",address);
printf("size of malloc block b:%d\n",size);
printf("before%p",a);
a=a+1;
printf("\n after%p",a);
free(a);
getch();
}
Address of the malloc "a" was incremented and then freed (a+1). It will lead to memory leak, but how will the free know the end point till it has to free so that it will not free the next chunk of memory by mistake? Is there any end marker like in Char Array - '\0'?
I read in K&R chapter 8 section 8.7 that free maintains a list from which the free will know were to add back the free memory block to.
Is there any size from which table its declared by malloc? Then how will the above code work, i guess this is were the free list comes to picture right? Its just going to add the free linked list i.e a+1 on words only. and forget about the other memory location which will lead to memory leak.
But when you do a malloc(), I read that it returns a pointer-1 and will give the Size of the malloc block that was allocated, am I right?
Can anyone explain this in detail?
Question is not related to Code. its how exactly the Malloc and free function work with each other. if i say free(a), how exactly will the free function know the end of the block?
You are in the realm of undefined behavior.
Free must be passed a pointer returned by malloc as per the standard:
The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation. If ptr
is a null pointer, no action occurs. Otherwise, if the argument does
not match a pointer earlier returned by the calloc , malloc , or
realloc function, or if the space has been deallocated by a call to
free or realloc , the behavior is undefined.
-- ANSI Standard 1988
Section 4.10.3.2 :The free function
You can't ask the sorts of questions you have about C implementations in general. You are making assumptions about the C implementation, some of which may be true, but they aren't guaranteed to be true by the C standard. Perhaps on some implementations, freeing an invalid pointer means you have a memory leak, and perhaps on some implementations, reading the 4 bytes prior to the pointer returned by malloc will give you the size of the allocated memory, but this is not standardised. The code you have written invokes undefined and implementation-defined behaviour in a number of places. Without knowing what C implementation you are talking about, it is impossible to tell you what the code will do. When a program invokes undefined behaviour, the implementation is free to do whatever it wants to do. A conforming C implementation can cause your computer to melt down into a steaming pile of silicon for freeing an invalid pointer. Will it? Don't know. The behaviour of your code is undefined.
How free and malloc are implemented depend on the implementation, not on the C standard. The C standard explains what the functions do and it is up to each individual C implementation to provide conforming versions of free and malloc based on the descriptions of these functions in the C standard.
All that can be said the free(a+1) call is that it leads to undefined behaviour, since a+1 has never been returned by malloc() et al.
Upon closer inspection, the size=(int *)*(a-1) line also leads to undefined behaviour, since you're dereferencing a pointer outside the allocated region.
The mechanics of memory allocation (i.e. things like free lists) are implementation-specific and should not be relied upon except in very specific and very rare circumstances.
edit If you curious to learn how a possible implementation might work, here is a description of one popular malloc() implementation: dlmalloc.

Resources