Dangling pointers in C - c

When a pointer is allocated memory using malloc, pointer (say x)will now point to memory address.
Later I free this(x) memory pointer,but pointer is still pointing to it's old memory.
This would now create dangling pointer.
(Because I did not point the old pointer to NULL after free)
Now, assume I use malloc and assume new pointer(y) now points to same memory location as old pointer (x)
Doesn't memsetting new pointer (y) to 0 solve dangling pointer issue.
Assume I have only one struct type.So every malloc which I do is always of same size of same structure.
If it was different struct , I know i may still have some data at the end of struct if new pointer (y) has small memory allocation than pointer (x)

The term dangling pointer means that whatever address in memory it points to is invalid. If you make it valid, like your 2nd malloc, then the address becomes valid. If you store the same address in two different variables (via your assumption) both are valid pointers:
#include <stdio.h>
#include <stdlib.h>
struct s { int i; };
int main() {
struct s *p = malloc(sizeof(struct s));
printf("before: %p\n", (void *) p);
free(p);
// p is dangling
printf("after: %p\n", p);
struct s *p2 = malloc(sizeof(struct s));
// p and p2 are valid
printf("before: %p\n", (void *) p2);
free(p2);
// p and p2 are dangling
printf("after: %p\n", p2);
}
and the output from my pleasingly corroborative malloc:
before: 0x561b73d3b260
after: 0x561b73d3b260
before: 0x561b73d3b260
after: 0x561b73d3b260

Dangling pointers are only a concern if you try to use them after you've freed them.
Yes, it's possible that a new allocation can return the same address that x has. But you can never know whether this is going to happen, so you still can't use x any more. It would just be a coincidence if its address became valid again.
Even if you keep allocating and freeing the same size, there's no expectation that it will keep reusing the same address.
For safety you must assume that a freed pointer will never become valid again.

Related

C print address of pointer to array problem

When I run the following code:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int array[100];
int (*array_ptr)[100];
void *buff = malloc(500);
int *ptr;
printf("array: %p \narray+1: %p\n", array, array+1);
printf("array_ptr: %p \narray_ptr+1: %p\n", array_ptr, array_ptr+1);
printf("buff: %p\n", buff);
printf("ptr: %p\n", ptr);
}
the result is like this:
array: 0x7fffe6dc6bd0
array+1: 0x7fffe6dc6bd4
array_ptr: (nil)
array_ptr+1: 0x190
buff: 0x1f80260
ptr: 0x7fffe6dd417c
I run it multiple times, array, array+1, buff and ptr all change values randomly, but array_ptr and array_prt+1 never change, although the pointer arithmetic result 0x190 is as expected.
Does it indicate that the array pointed by array_ptr is stored in heap? But the dynamically allocated memory chunk pointed by buff is also supposed to be in heap and its value changes, why is that? Thanks!
array_ptr is uninitialized pointer, and gets an undefined value(in your case 0).
array_ptr+1 is sizeof(int)*100 = 400 = 0x190 more than array_ptr
ptr is also an uninit pointer, which in your case points to garbage.
You need to initialize pointers after they're defined to get any valid results
To your question, array is on the stack, buff is on the heap, and ptr/array_ptr are uninitialized will give you garbage or segmentation fault if you try to access their data
Does it indicate that the array pointed by array_ptr is stored in heap?
No. array_ptr points to nothing, neither on the stack nor on the heap.
int (*array_ptr)[100];
array_ptr is one pointer to an array of 100 int objects, but with this statement you do not create an array with 100 int objects by which array_ptr is pointing to the first element of this array. It only creates the pointer itself.
With:
printf("array_ptr: %p \narray_ptr+1: %p\n", array_ptr, array_ptr+1);
You are trying to print the addresses of objects the pointer array_ptr and its offset by 1 point to, but this isn´t possible since array_ptr is not initialized to point to such objects. Thus, You´ll get any kind of Undefined Behavior/ unpredictable results.
You need to initialize array_ptr with, f.e. the address of the first int object of array:
int (*array_ptr)[100] = array;
The same goes for the pointer ptr with:
printf("ptr: %p\n", ptr);
ptr needs to have an address of an object it points to in order to show the address of that object.
But the dynamically allocated memory chunk pointed by buff is also supposed to be in heap and its value changes, why is that?
This is a completely different thing. With malloc you do allocate memory on the heap (if it was successful of course) and you do get a pointer to that memory back, which isn´t the case with int (*array_ptr)[100];.

Can I free memory originally allocated from another pointer?

If I allocated memory from another pointer, then declare a pointer equal to the other pointer, can I then free the memory allocated with the first pointer by using free() on the new pointer?
Example:
typedef struct foo{
int n;
char c;
} foo;
foo* bar = malloc(sizeof(foo));
foo* tmp = bar; // declaring pointer identical to other pointer
free(tmp); // can I do this to free *bar?
Yes, it is completely fine.
Your implementation of malloc will most likely mark the chunk of memory as allocated before returning a pointer to it.
Now you can have as many pointer variables as you want which point to this chunk of memory and you can free that memory by calling free on any of them.
The pointer itself doesn't contain information about whether the memory it points to has been allocated. It just points to it.
int* i = malloc(sizeof(int) * 23);
int* j = i;
free(j);
// free(i); // this is undefined behavior, the memory was already freed
Yes you can do what you are asking about. But it is not another pointer, what you are freeing is the same pointer. When malloc returns a pointer, it is essentially giving you an integer that is the address of the start of the chunk of memory that it has reserved for you. When you are done are done with the memory, you pass that address to free. As far as free is concerned, there is no difference between:
free(malloc(17));
,
void *p = malloc(17);
free(p);
or
void *p1 = malloc(17);
void *p2 = p1;
free(p2);
In all of these cases the value returned from malloc is getting to free, and that is all that matters.

Allocating a value to a pointer in c

I am trying to give a value to a pointer.
this code works fine
int i =5;
int *ptr ;
ptr = &i;
printf(" %d\n",*ptr);
but this code shows an error
int i =5;
int *ptr ;
*ptr = 5;
printf(" %d\n",*ptr);
can someone explain this to me?
int *ptr gets initialized to a random location, which possibly points to invalid memory, and you try to write 5 to that location.
When you declare int *ptr, you're creating a variable called ptr which can hold the address of an int. When you dereference it in *ptr = 5, you're saying "store 5 in the address that ptr points to" - but as ptr is uninitialised, where it points to is undefined. So you're invoking undefined behaviour.
An int * does not store an int, but just an address that points to one. There still has to be a real int at that address.
If you want to allocate an int that exists outside of the local scope, you can use malloc. A simple conversion of your example without error checking:
int *ptr = malloc(sizeof(int));
*ptr = 5;
printf(" %d\n",*ptr);
If you do use malloc, just remember to free the allocated memory when you're finished:
free(ptr);
The second version assigns 5 to the memory pointed to by ptr, but you haven't yet initialized ptr to point to a known location.
So it writes the value to the memory at whatever address happens to be in ptr, which is whatever was in memory where ptr was declared.
You can't deterrence a pointer that doesn't point to somewhere you own.
int* ptr;
That allocates space for the pointer, but it doesn't allocate space for the chunk the pointer points to.
Also, since it's not initialized, ptr has an indeterminate value. This means that not only does it likely point to something you don't own, it also would be rather difficult to check if it's a valid pointer. It's usually a good idea to initialize pointers to either NULL (or nullptr if available) or an actual location (like you did in the first example).

Exact output of free() in C?

I wanted to ask, if I have a pointer pointing at some struct, but then I free(struct) then if I dereference the pointer, will it be pointing to NULL? As in can I check, pointer != NULL or is this undefined?
Thanks!
Calling free() on the pointer does not change the pointer value. It will still point to the same memory that no longer belongs to your application. You should always assign NULL to a free'd pointer immediately after you free it to ensure that you don't use it again.
void *p = malloc(10); // p points to allocated memory
free(p); // p still points to invalid memory
p = NULL; // good practice
Consider the below code
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
free(p);
}
Here variable p is a local variable of a function main. Size of this variable will be 4 bytes(in 32bit m/c) or 8 bytes(in 64 bit m/c). Now we are allocating memory for storing 10 integer elements and that address is stored in variable p. Now we are calling free function to which we are passing the dynamic memory address which is stored in the local variable p. Now free function will free the memory and it will not be able to assign NULL to the variable p. Because we passed address as value, not reference to the pointer.
We can define a wrapper function for free like below
void myfree(void **p)
{
free(*p);
*p = NULL;
}
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
myfree(&p);
}
Or we can define macro function also
#define MYFREE(x) \
free(x); \
x = NULL;
It's undefined. C does not define what it does with the contents of the pointer, although most implementations do nothing.
Take a look at this page.
It clearly says:
Notice that this function leaves the value of ptr unchanged, hence it
still points to the same (now invalid) location, and not to the null
pointer.
Note that it is up to you to make sure that pointer is not dereferenced after being freed.

Use after free error?

int main(void) {
int* p = (int*) malloc(sizeof(int));
int* q = (int*) malloc(sizeof(int));
*p = 10;
*q = 20;
p = q;
printf(“%d %d”, *p, *q);
free(p);
free(q);
}
Why does the above code contain use-after-free error? There's no more expression after free(p) and free(q). Obviously we are not using them anymore!
You have two problems here.
First, you are deleting the same heap variable twice:
free(p);
free(q);
Second, you have a memory-leak, because the variable created by p is no longer accessible.
Notice that onebyone's comment is really important. If you change the line:
p = q;
into:
*p = *q;
There would be no problems at all in your code :) Hello Pointers!
You set p to q, so you are free()ing it twice.
Since q and p point to the same memory at the point you are freeing them, you're effectively freeing the memory twice.
Because here:
p = q;
...you're throwing away the old value of p. You now have two copies of the pointer that was returned by the second malloc, and none of the pointer that was returned by the first malloc.
So then here:
free(p);
free(q);
...the same pointer value gets passed to free twice: use-after-free error. The other pointer value never gets passed to free at all: memory leak.
It's a fundamental memory manipulation error!
Never do so!
You allocate memory at pointer p and after that you just rewrite pointer at p=q.
Previous value of pointer you lost, p is a lost pointer!
You can never free the memory allocated above for pointer p! It's a lost memory block for p.
It's memory leak... Try to free it at line free(p) in real free memory allocated for pointer q, but not for p!.
Next line free(q) is another try to free the same memory that was freed in previous line. That will be unpredictable behavior depending on the system it may be nothing special, and may be an error at program finish.
You must replace line free(p) before line p=q.
And always before rewrite pointer with previously allocated memory free them! Consider it a strict rule!

Resources