No warnings when trying to access freed memory in C [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 8 years ago.
I'm trying to understand the how the memory is managed in C. In the sample code below, in the comments I have added my understanding on how the memory is managed.
I would like to know if I'm correct
In the final part of the code, I'm trying to access a part of memory which is already freed. I'm surprised why the compiler did not through any warnings
struct node
{
int keys[2];
int *pkeys;
};
int main()
{
int temp[2] = {10,20}; // creates a temp array in stack
struct node* node = malloc(sizeof(struct node)); //allocates a block of memory on heap pointed by node
node->keys[0]=1;node->keys[1]=2; // assigns values for keys present in heap
node->pkeys = malloc(2*sizeof(int)); // creates a pointer pkeys in heap
node->pkeys = temp; // the pointer pkeys in heap points to the temp array in stack
free(node); // the block of memory on heap pointed by node is freed
node->keys[0] = 9; //**Why does the compiler ignore that I'm accessing freed memory?**
}

The compiler in C does not do that sort of checking. If gives enough rope to hang yourself.
It is up to you to do the checks. That is also true for bounds checking of arrays.
Also you need to note that malloc/free does not always have to beg/give to the OS. That means it may still be accessible by the process without seg fault.

The compiler does not check for illegal memory access and your program will cause undefined behaviour or may even crash (segmentation fault). The behaviour is unpredictable and next time you run your program, it may crash.
Few things about your code:
The signature of main should either be int main(void) or int main(int argc, char *argv[]).
The comment for this statement is wrong.
node->pkeys = malloc(2*sizeof(int)); // creates a pointer pkeys in heap
You created the pointer pkeys when you allocated memory and made node point to it. This statement is dynamically allocating memory for array of 2 ints and making pkeys point to it. So when you do node->pkeys = temp, you lose handle on the dynamically allocated array and will cause memory leak. So before reassigning pkeys, you must free the memory it points to.
free(node->pkeys);
// now reassign node->pkeys

The space allocated to node is freed but node still points to the same location. So it is still accessible. But if you are unlucky (that is the OS reused the memory for its own purposes) you will get a segmentation fault.

Related

Does freeing structures in C also delete its members? [duplicate]

This question already has answers here:
Will freeing a structure pointer also free the memory allocated inside of the structure in C?
(2 answers)
Closed 3 years ago.
I'm pretty much new to C and i have a question about allocating memory. So I tried this code below that should free the structure elem1.
struct elem{
char *data1;
char *data2;
};
int main()
{
struct elem *elem1 = malloc(sizeof(struct elem));
elem1->data1 = "abc";
elem1->data2 = "def";
char *a = elem1->data1;
char *b = elem1->data2;
free(elem1);
printf("%s\n%s\n",a,b);
return 0;
}
The code compiles just fine and it gives back,
abc
def
I expected it to fail since free should also free the memory of its members. But why does it work? And what should I do if I want to access the members of the structure after I free the structure?
The members are part of the structure. Freeing the structure deallocates all of its members.
However, in your example, the members are just pointers. You're copying a pointer into the structure (node->data1 = ...), then out of the structure (... = node->data1), then freeing the structure. None of this affects the memory that the pointer is pointing to.
In your example the actual strings are stored in static memory (they're string literals). That means they're never destroyed; they live as long as the program is running. That's why it's perfectly safe to print them. Your code is fine.
Finally, accessing freed memory has undefined behavior (meaning anything can happen, including a program crash or appearing to work correctly). If you want to access members of a structure that has been freed, just do that:
struct elem *p = malloc(sizeof *p);
free(p);
p->data1 = "boom!"; // Undefined behavior!
However, that would be a bug, so ... don't, please.
Every malloc has to be balanced with a corresponding free.
Your assignment node->data1 = "abc"; assigns a pointer to the read-only literal "abc", so there is no dynamic memory here, and therefore you must not use a free.
In your particular case, you are able to retain that pointer a having called free on the struct since you did not have to free that memory and it didn't ever belong to the struct. But that does not work in general: if you had used malloc to set node->data1 then (1) you would have to call free on that pointer before you attempt to call free on the struct, and (2) the behaviour of a subsequent deference of node->data1 would be undefined.

possible memory leak using pointers with malloc() and free(), and confusion with pointer notation

So I'm relatively new to C, and I was trying to write code for a singly linked list.
This is what I wrote for deleting a node from the beginning of the list.
int delete(struct node **head)
{
int x = -1;
if(*head != NULL) {
struct node *old = *head;
(*head) = (*head)->next;
x = old->data;
free(old);
}
return x;
}
and I'm confused at the free() function. Am I freeing the space allocated to the pointer old, or am I freeing it to the address at which old points? Maybe the correct way of doing it would be free(*old)? Will this code cause a memory leak?
Also, if this frees the memory allocated to old, what would be the effect of free(&old), in that case?
From what you show the memory management seems OK and does not seem to leak memory.
Am I freeing the space allocated to the pointer old
Yes, the code deallocates, frees to memory old points to, which is commonly referred to as the memory being allocated to a pointer.
free(*old) wouldn't work, as it wouldn't compile, because you tried to pass a struct into where a pointer is expected.
free(&old) wouldn't work, as it would provoke undefined behaviour, because the code tried to free memory being allocated on the stack, that is the memory for the pointer variable old itself.

Unable to understand Memory allocation of structure

Consider following C code -
typedef struct node
{
int data;
}node;
int main()
{
node *temp;
temp->data=100;
printf("%d",temp->data);
return 0;
}
It gives Segmentation fault on line containing temp->data=100; because (I think) I haven't allocate memory for it. So, there is nothing such as temp->data.But, when I try with -
int main()
{
node *temp,*n;
n=(node*)malloc(sizeof(node));
n->data=100;
temp->data=n->data;
printf("%d",temp->data);
retrun 0;
}
It gives proper output 100.
I haven't allocate memory where temp will point. But still I am copying n->data to temp->data. How ??
The temp pointer takes some garbage value as its not initialised. By chance temp has a garbage value which may happen to be legal address for your program so it runs. If garbage value has illegal adress it will generate segment fault.
You're lucky.
Local variables are not initialized automatically, so when the program begins, both temp and n contain whatever values happen to be on the stack. Next, memory is allocated and n is set to point to it. The value 100 is stored in the data member of the structure.
But temp is still uninitialized, so the value 100 is copied into an unspecified area of memory. Depending on where that memory happens to be, the program may segfault, or it may simply corrupt memory that it doesn't own.
That you haven't got a segfault in temp->data=n->data; is just coincidence. temp is not initialized and hence it points into the digital nirvana.
When you've called malloc you've allocated sizeof node bytes (in reality it may be even a little more) and then you have full memory access to the block pointed to by n.
In general you should call malloc in this way:
node *n;
n = malloc(sizeof *n);
without a cast
with sizeof *n instead of sizeof <datatype>. If you change the datatype (for example you have a typo and instead of typedef .... node you've writen typedef ... nhode. Then you only have to change the declarations of the variables and the rest of the code doesn't have to be changed at all.
Your first code is also right just "temp" is pointing to a garbage value so you have to initialized that.
temp=(node *)malloc(sizeof(node));
Your right on the first part, it segfaults because node* temp isn't pointing anywhere (well, somewhere, but not to allocated memory).
I don't know why the second one "works". I suspect it only appears to work, in that it's not crashing. But since temp was never initialized, who know where it's sticking that '100'. Maybe just hanging around to crash later. Either way, writing to unitialized memory isn't a good idea ;-0

Trouble with Malloc for Structs

I keep constantly getting a segmentation error with a small portion of code and I have no idea why, I'm using malloc and cant see any reason with that, just as soono as it hits the portion of data, its crashes.
The Data is:
listNode* node = (listNode*)malloc(sizeof(listNode)); <-This is the Line
strcpy(node->entry, string);
node->next = NULL;
Using the struct definition:
typedef struct
{
char* entry;
struct listNode* next;
}listNode;
The data does get freed at one point, however it cannot reach said point.
Thanks for the help!
Are you sure you're crashing on the malloc call? It's much more likely that you're crashing on the strcpy. In fact, the strcpy in this case is almost guaranteed to cause bad behavior, although to be precise the behavior is undefined.
The malloc should succeed as long as you haven't filled up your heap. However, because you called malloc and not calloc, you have no guarantees about the contents of node->entry. The C standard doesn't define what is stored in memory allocated with malloc, so node->entry is filled with garbage. By trying to copy to a bad pointer, your app is crashing for attempting to accessing an incorrect memory address.
Alexey Frunze is 100% correct on the fix - malloc space and change node->entry to point at the newly allocated memory, then copy string into node->entry. This avoids undefined behavior for using an uninitialized pointer, as I described in another SO answer.
You didn't allocate memory for the entry pointer. You're trying to copy your string to a bogus location specified by the uninitialized pointer entry. You might do this instead:
node->entry = malloc(strlen(string) + 1);
strcpy(node->entry, string);
You are not allocating allocate memory for the entry pointer. as while allocationg structure just 4 bytes allocated for *entry pointer
you should do
listNode* node = (listNode*)malloc(sizeof(listNode)); // allocate memory for structure
node->entry = malloc(strlen(string) + 1);// allocate memory for string
strcpy(node->entry, string); //copying strings
now it will run fine

allocating memory with same identifier

#include<stdio.h>
#include<stdlib.h>
int main()
{
char *temp;
while(1)
{
temp= malloc(sizeof(char)*10);
/*some code*/
}
}
My question is: I was allocating memory in every loop with same name. What will happen to previous memory allocated; and as we are creating variables with same identifier why we are not getting any errors?
PS: Don't ask what I'm doing in this code. I was doing some other code and by mistake did it. Just re modified it and asking my problem .
It's called a memory leak. You have no way of ever freeing the memory, so it's lost to you.
Your process will keep growing in size until you run out of available memory (or, if it's 64 bit, swap the box into oblivion at which point your local sysadmin will come over and trounce you. If it's a production machine, you're likely to find out what a performance improvement plan is from your boss and HR.)
what will happen to prev memory allocated.
Will be lost forever. That is what is called "memory leak".
and as we are creating variables with same identifier why we are not getting any errors
That's not a compilation error. The compiler doesn't follow your logic, only your syntax. Overwriting values is perfectly fine with the compiler.
The previos memory allocated will be leaked, since its not freed and its address gets lost to the program. You don't get any errors because you are not creating variables with the same identifier, you are allocating different chunks of memory and storing the pointer to them into the same temp variable.
Consider reading some basic C programming material as you seem to be confusing variables with memory.
The compiler will in most cases not detect logical errors, such as this, where the programmer allocates memory but never frees it.
This is what we call a "memory leak".
Here temp is a pointer not an identifier.
So temp POINTS to the memory allocated my malloc.
So when you allocate new memory and use the SAME pointer to point to the newly allocated memory, it NO LONGER points the the old allocated memory block and it is lost forever. So there you have a memory leak.
If you no longer need the memory pointed to by temp after the end of the current iteration of the loop, use following code instead.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *temp;
while(1)
{
temp= malloc(sizeof(char)*10);
/*some code*/
/* free the memory pointed by temp */
free(temp);
}
}
This way you do not have a memory leak as the memory pointed to my temp is freed at the end of the iteration before a new block is allocated at the start of the next loop.
Update:
Also you can use the same memory block pointed to by temp throughout your loop. No need to reallocate in each iteration.
And if you do not want to retain any old memory you can simply use memset, like this
#include<stdio.h>
#include<stdlib.h>
int main()
{
/* allocate memopry only once */
char *temp = malloc(sizeof(char)*10);
while(1){
/* zero out the memory so no old data is left */
memset((void*)temp, 0, sizeof(char)*10);
/* some code that uses temp */
}
/* free the allocated memory */
free(temp);
}

Resources