I am learning and testing memory allocation in C and I want to test what happens if free() is called.
I expected there could be a segmentation fault or pointer is NULL after I run the program below. However, I can still successfully print the string as in Output. I also tried to free str twice, then an error as Output 2 occurred.
It seems the previously allocated memory is successfully deallocated, but the data on the memory is not cleaned up. Is that correct? If that is the case, when will the program clean up those deallocated memory space? Is that safe if the data is deallocated but not cleaned up?
Answers to any question above will be helpful! Thanks!
Code
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Hello, World!\n");
char *str = (char *)malloc(24);
char *str2 = "tutorialspoint";
strcpy(str, str2);
free(str);
printf("[str] %s\n", str);
return 0;
}
Output
Hello, World!
[str] tutorialspoint
Output 2
main(83218,0x7fff9d2aa3c0) malloc: *** error for object 0x7fb0b2d00000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
Edit
Thank you all for helpful replies. Now I understand that there are some undefined behaviors (UB) in C and this helped me understand something else confused me before such as writing to a string beyond the scope of allocated(like what's in the code snippet below). This caused UB according to wiki, but the program will not crash.
Feel free to correct me if I got it wrong!
char *str = (char *)malloc(0);
char *str2 = "tutorialspoint";
strcat(str, str2);
printf("[str] %s, [addr] %p\n", str, str);
You need to learn the concept of undefined behavior.
Even if you print the string after you free it and it "works", it doesn't mean it worked. It's just one of the things that can happen when the behavior is said to be undefined, which in this case it is.
Also, the pointer will not be NULL except if you do this
free(ptr);
ptr = NULL;
and free(), doesn't set all bytes to 0 either.
The free() function just does exactly what it's name suggests. It allows malloc() to use the free()d chunk again. The data the pointer pointed to might still be there unchanged and that is the reason why you can still print the previous content after free(). But there is absolutely no guarantee of what will happen if you do dereference a pointer after free() or whether the data still exists or, was completely or partially overwritten.
If you do dereference the pointer after having free()d it, there is one thing you do know, the behavior is undefined.
When you call free, it allows the pointed-to memory to be used for other purposes. Attempting to read or write memory that has been freed invokes undefined behavior.
Just because the memory has been given up doesn't necessarily mean it's been physically wiped.
An analogy: Suppose you left a book on your hotel room table. You check out of the hotel, but you still have the key card. If you go back to the room the book might be there, or it might not.
Related
I don't get why the free here is not working and i still get 5 in the printf.
Should i just point the p value to NULL?
I've searched many threads but didn't find any helpful informations about this.
#include<stdio.h>
void main(){
int *p = malloc(sizeof(int));
*p = 5;
free(p);
printf("%d\n",*p);
}
The function is called free not erase, it does not "erase" the memory pointed by the pointer, it merely allows that area of memory to be used for something else. printf printed the previous value, meaning that nothing else happened to use the memory that has been just freed.
Regardless, you are still attempting to access a memory that no longer belongs to you, and hence invoking undefined behaviour. The code may crash, or print the previous value, or print garbage, or it might as well draw a unicorn to the console, this is what makes undefined behaviour ...undefined.
This question already has answers here:
C - Accessing data AFTER memory has been free()ed?
(2 answers)
Closed 2 years ago.
I am new to C. I have below codes. After free, the first freed pointer give 0 length but not null, the second and third still have length > 0. Not sure if it is normal? Thanks.
Here is the output:
enter image description here
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *str[3];
char *aa = "helloworld0";
char *bb = "helloworld1";
char *cc = "helloworld2";
str[0] = (char *)malloc(strlen(aa) + 1);
strcpy(str[0], aa);
str[1] = (char *)malloc(strlen(bb) + 1);
strcpy(str[1], bb);
str[2] = (char *)malloc(strlen(cc) + 1);
strcpy(str[2], cc);
char **strr = str;
printf("Before free----Length:%ld,Content:%s,Address:%p\n",
strlen(strr[1]), strr[1], strr[1]);
free(strr[1]);
if (strr[1]) printf("not NULL 1\n");
printf("After free----Length:%ld,Content:%s,Address:%p\n\n",
strlen(strr[1]), strr[1], strr[1]);
printf("Before free----Length:%ld,Content:%s,Address:%p\n",
strlen(strr[0]), strr[0], strr[0]);
free(strr[0]);
if (strr[0] == NULL) printf("not NULL 0\n");
printf("After free----Length:%ld,Content:%s,Address:%p\n\n",
strlen(strr[0]), strr[0], strr[0]);
printf("Before free----Length:%ld,Content:%s,Address:%p\n",
strlen(strr[2]), strr[2], strr[2]);
free(strr[2]);
if (strr[2]) printf("not NULL 2\n");
printf("After free----Length:%ld,Content:%s,Address:%p\n\n",
strlen(strr[2]), strr[2], strr[2]);
}
After passing a pointer value to free, any further use of that value has undefined behavior. Even if (strr[1]) is invalid and does not have a meaningful result, even if in practice it normally reflects that the last time the value was meaningful, it was non-null.
The subsequent operation is even worse:
printf("After free----Length:%ld,Content:%s,Address:%p\n\n",strlen(strr[1]),strr[1],strr[1]);
Here you're not only using the value strr[1] (a pointer), but passing a function that will use it to access an object at that address (strlen). This also has undefined behavior, and mechanically it ends up accessing memory that no longer belongs to your program. What this results in is a matter of how the compiler implementation handles undefined behavior it can see (note: it could even trap before letting you get this far, but it doesn't have to) and possibly on what the C library implementation (free) does with memory you've relinquished to it. It's possible that the address will no longer work and that accesses to it will fault and cause your program to crash. It's also possible that it ends up accessing memory that now belongs to the implementation, possibly with new contents stored there to track it for reuse. It's also possible that entirely different and unexpected results are produced.
In C you simply can't do this. After you free memory obtained by malloc, you're done with it. You can't process the pointer or the memory it pointed to before in any way. There is no way to "check if it was freed". Once it's freed, that's it.
Many programmers like to assign a null pointer value to any pointer object as soon as they free the memory it points to, to prevent inadvertently trying to access it later:
strr[1] = NULL; // or = 0;
Free memory actually means freeing ownership of specified place in the memory. The idea is that in the process of freeing it the variable it self can't write anymore off the given location but only read. In order to actually make the code safe after every free you should set the variable to NULL. It will redirect the variable off the last memory's sell it was pointing to and make the data unreadable from the variable it self. Instead the pointer will hold a NULL which is pre known state of a pointer free of ownership and thus may be used.
free means you are telling system:
I do not need this memory anymore, you can use this memory anytime if you want.
But system does not guarantee when will it clean and re-use these memory.
Next time when you access this memory, maybe system has not cleaned it yet, or maybe it does. You just can not make sure whether it does. It is a undefined behavior.
You should add strr[1]=NULL; to prevent you accidentally access the space which you have already returned to system.
In the below program, as far as in my knowledge once we allocate some memory then if we are chaging the address from
ptr to ptr++, then when we are calling free with ptr i.e free(ptr).
Then the program should crash.
But in this program works fine.
How it works?
I am using Code::Bocks in Windows XP.
Please help me.
int main()
{
int *ptr;
ptr = malloc(1);
*ptr = 6;
printf("The value at *ptr = %d \n", *ptr);
ptr++; //Now ptr is address has been changed
free(ptr); // Program should crash here
ptr = NULL;
/* *ptr = 5;*/ // This statement is crashing
return 0;
}
The behavior of this program is undefined from the very moment that you store a value through an int* pointing to a single byte. There's no guarantee of a crash.
Specifically, it seems like your free doesn't (maybe can't) check its argument properly. Try running this program with a malloc debugging library.
Absence of a crash does not necessarily mean your code is fine. On another platform, it will probably crash.
BTW: you should rather malloc(sizeof(int))
The program should not necessarily crash, the behavior is undefined.
It works only due to luck; the code is still wrong.
To understand why, one first needs to be familiar with the implementation of the malloc library itself. malloc not only allocates the space it returned for you to use, it also allocates space for its own metadata that it uses to manage the heap (what we call the region of memory managed by malloc). By changing ptr and passing the wrong value to free, the metadata is no longer where free expected it, so the data it's using now is essentially garbage and the heap is corrupted.
This doesn't necessarily mean it'll crash due to say, a segfault, because it doesn't necessarily dereference a bad pointer. The bug still exists and will likely manifest itself in a longer program with more heap usage.
I have a problem with memory allocation using malloc.
Here is a fragment from my code:
printf("DEBUG %d\n",L);
char *s=(char*)malloc(L+2);
if(s==0)
{
printf("DEBUGO1");
}
printf("DEBUGO2\n");
It outputs "DEBUG 3",and then a error msgbox appears with this message:
The instruction at 0x7c9369aa referenced memory at "0x0000000". The
memory could not be read
For me such behavior is very strange.
What can be wrong here?
The application is single threaded.
I'm using mingw C compiler that is built in code::blocks 10.05
I can provide all the code if it is needed.
Thanks.
UPD1:
There is more code:
char *concat3(char *str1,char *str2,char *str3)
{
/*concatenate three strings and frees the memory allocated for substrings before*/
/* returns a pointer to the new string*/
int L=strlen(str1)+strlen(str2)+strlen(str3);
printf("DEBUG %d\n",L);
char *s=(char*)malloc(L+2);
if(s==0)
{
printf("DEBUGO1");
}
printf("DEBUGO2\n");
sprintf(s,"%s%s%s",str1,str2,str3);
free(str1);
free(str2);
free(str3);
return s;
}
UPD2:
It seems the problem is more complicated than i thought. Just if somebody has enough time for helping me out:
Here is all the code
Proj
(it is code::blocks 10.05 project,but you may compile the sources without an ide ,it is pure C without any libraries):
call the program as
"cbproj.exe s.pl" (the s.pl file is in the root of the arhive)
and you may see it crashes when it calls the function "malloc" that is on the 113th line of "parser.tab.c"(where the function concat3 is written).
I do the project in educational purpouses,you may use the source code without any restrictions.
UPD3:
The problem was that it was allocated not enough memory for one of the strings in program ,but the it seemed to work until the next malloc.. Oh,I hate C now:)
I agree with the comments about bad coding style,need to improve myself in this.
The problem with this exact code is that when malloc fails, you don't return from the function but use this NULL-pointer further in sprintf call as a buffer.
I'd also suggest you to free memory allocated for str1, str2 and str3 outside this function, or else you might put yourself into trouble somewhere else.
EDIT: after running your program under valgrind, two real problems revealed (in parser.tab.c):
In yyuserAction,
char *applR=(char*)malloc(strlen(ruleName)+7);
sprintf(applR,"appl(%s).",ruleName);
+7 is insufficient since you also need space for \0 char at the end of string. Making it +8 helped.
In SplitList,
char *curstr=(char*)malloc(leng);
there's a possibility of allocating zero bytes. leng + 1 helps.
After aforementioned changes, everything runs fine (if one could say so, since I'm not going to count memory leaks).
From the error message it actually looks like your if statement is not quite what you have posted here. It suggests that your if statement might be something like this:
if(s=0) {
}
Note the single = (assignment) instead of == (equality).
You cannot use free on pointers that were not created by malloc, calloc or realloc. From the Manpage:
free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
I have seen some differences in the result of the following code:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
int main(void)
{
char* ptr;
ptr = (char*)malloc(sizeof(char) * 12);
strcpy(ptr, "Hello World");
printf("%s\n", ptr);
printf("FREEING ?\n");
free(ptr);
printf("%s\n", ptr);
}
Let me explain:
In the third call to printf depending the OS I get different results, gargabge caracters in Windows, nothing in Linux and in A Unix system "Hello World" is printed.
Is there a way to check the status of the pointer to know when memory has been freed?
I think this mechanism of print can not be trusted all the times.
Thnaks.
Greetings.
Using a pointer after it has been freed results in undefined behavior.
That means the program may print garbage, print the former contents of the string, erase your hard drive, or make monkeys fly out of your bottom, and still be in compliance with the C standard.
There's no way to look at a pointer and "know when memory has been freed". It's up to you as a programmer to keep track.
If you call free(), the memory will have been freed when that function returns. That doesn't mean that the memory will be overwritten immediately, but it's nevertheless unsafe to use any pointer on which you've called free().
It's a good idea to always assign nil to a pointer variable once you've freed it. That way, you know that non-nil pointers are safe to use.
Simple ansewr: you can't check if a pointer has been freed already in C. Different behaviors are probably due to different compilers, as using a pointer after freeing it is undefined you can get all sorts of behavior (including a SEGFAULT and program termination).
If you want to check if you use free property and your program is memory leak free, then use a tool like Valgrind.