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.
Related
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.
so I'm quite new in this, sorry if it sound like a dumb question
I'm trying to understand malloc, and create a very simple program which will print "ABC" using ASCII code
here is my code (what our professor taught us) so far
char *i;
i = malloc(sizeof(char)*4);
*i = 65;
*(i+1) = 66;
*(i+2) = 67;
*(i+3) = '\0';
what I don't understand is, why do I have to put malloc there?
the professor told us the program won't run without the malloc,
but when I tried and run it without the malloc, the program run just fine.
so what's the function of malloc there?
am I even using it right?
any help and or explanation would be really appreciated
the professor told us the program won't run without the malloc
This is not quite true, the correct wording would be: "The program's behavior is undefined without malloc()".
The reason for this is that
char *i;
just declares a pointer to a char, but there's no initialization -- this pointer points to some indeterminate location. You could be just lucky in that writing values to this "random" location works and won't result in a crash. I'd personally call it unlucky because this hides a bug in your program. undefined behavior just means anything can happen, including a "correct" program execution.
malloc() will dynamically request some usable memory and return a pointer to that memory, so after the malloc(), you know i points to 4 bytes of memory you can use. If malloc() fails for some reason (no more memory available), it returns NULL -- your program should test for it before writing to *i.
All that said, of course the program CAN work without malloc(). You could just write
char i[4];
and i would be a local variable with room for 4 characters.
Final side note: sizeof(char) is defined to be 1, so you can just write i = malloc(4);.
Unfortunately, "runs fine" criterion proves nothing about a C program. Great deal of C programs that run to completion have undefined behavior, which does not happen to manifest itself on your particular platform.
You need special tools to see this error. For example, you can run your code through valgrind, and see it access uninitialized pointer.
As for the malloc, you do not have to use dynamic buffer in your code. It would be perfectly fine to allocate the buffer in automatic memory, like this:
char buf[4], *i = buf;
You have to allocate space for memory. In the example below, I did not allocate for memory for i, which resulted in a segmentation fault (you are trying to access memory that you don't have access to)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *i;
strcpy(i, "hello");
printf("%s\n", i);
return (0);
}
Output: Segmentation fault (core dumped)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *i;
/*Allocated 6 spots with sizeof char +1 for \0 character*/
i = malloc(sizeof(char) * 6);
strcpy(i, "hello");
printf("%s\n", i);
return (0);
}
Result: hello
Malloc allows you to create space, so you can write to a spot in memory. In the first example, "It won't work without malloc" because i is pointing to a spot in memory that doesn't have space allocated yet.
How come I don't get any error using the following program?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
char *pStr = (char*) malloc(25);
free(pStr);
strcpy(pStr, "foo");
printf("%s\n", pStr);
return 0;
}
Shouldn't free(pStr) stop me from writing to that address? Don't I have to allocate the space again before I can use it?
free doesn't prevent you from doing anything as long as the thing is syntactically correct. So you are still more than welcome to copy to a char* just as you could do if you had never allocated the memory in the first place. But this is undefined behavior, and is liable (read: likely) to cause your program to crash or do something wrong without warning.
For example, if your compiler does some optimizations, it might reorder some instructions in order to save time. Since you have freed the memory, the compiler might think that it is safe to allocate memory in that location for some other data that will be created later. If the optimizer moves that allocation and write to before your strcpy here, you could overwrite the object that is stored there.
Consider this code:
int main(int arc, char *argv[]){
char* pStr = (char*) malloc(25);
free(pStr);
strcpy(pStr, "foo");
printf("%s\n", pStr);
int* a = (int*) malloc(sizeof(int));
*a = 36;
printf("%d\n", *a);
}
Since you wrote to unallocated memory, you can't be sure what either of the printfs will display. The 36 might possibly have overwritten some of the "foo" string. The "foo" string might have overwritten the value 36 that a points to. Or maybe neither of them affects the other and your program runs seemingly just fine until you change the name of some variable and recompile and for some reason everything is messed up even though you didn't change anything.
Moral of the story: you are correct that you should not write to freed memory; however, you are incorrect that you cannot write to freed memory. C does not check this condition and assumes that you are trying to do something fancy. If you know exactly how your compiler optimizes and where it allocates memory when malloc is called, you might know that writing to unallocated memory is safe in a particular case, and C does not prevent you from doing that. But for the 99.999% of the time that you don't know everything, just don't do it.
It is an undefined behavior. And what really happens is implementation specific.
In practice, free very often mark the freed memory block as reusable for future malloc-s.
See also this ...
As other answers pointed it's undefined behavior, thus compiler is not obligated for any diagnostics. However if you have modern version of gcc (>= 4.8) or clang, then AddressSanitizer might be helpful in case of this "use-after-free" bug:
$ gcc -ansi -pedantic -fsanitize=address check.c
$ ./a.out
=================================================================
==2193== ERROR: AddressSanitizer: heap-use-after-free on address 0x60060000efe0 at pc 0x4009a8 bp 0x7fff62e22bc0 sp 0x7fff62e22bb8
...
The common defensive programming "trick" is to assign NULL right after free() call:
free(pStr), pStr = NULL;
With it It's likely to get "Segmentation fault" with pStr dereference on GNU/Linux, but there is no guarantee on that.
Understand the answer to your question you need to understand the process of memory allocation. In a generic sense, malloc/free are library functions. They manage a memory pool that is allocated from operating system services.
[at the risk of oversimplification]
Your first malloc finds an empty pool. It then calls an operating system system service to add pages to the process that get added to the pool. Malloc then returns a block of memory from that pool.
Calling free returns the block to the pool. It remains a valid block of memory in the pool.
If you access the free'd address, the memory is still there. However, you are #$#$ing up malloc's pool of memory. That kind of access is going to eventually byte you in the #$#$.
I am just learning C (reading Sam's Teach Yourself C in 24 hours). I've gotten through pointers and memory allocation, but now I'm wondering about them inside a structure.
I wrote the little program below to play around, but I'm not sure if it is OK or not. Compiled on a Linux system with gcc with the -Wall flag compiled with nothing amiss, but I'm not sure that is 100% trustworthy.
Is it ok to change the allocation size of a pointer as I have done below or am I possibly stepping on adjacent memory? I did a little before/after variable in the structure to try to check this, but don't know if that works and if structure elements are stored contiguously in memory (I'm guessing so since a pointer to a structure can be passed to a function and the structure manipulated via the pointer location). Also, how can I access the contents of the pointer location and iterate through it so I can make sure nothing got overwritten if it is contiguous? I guess one thing I'm asking is how can I debug messing with memory this way to know it isn't breaking anything?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct hello {
char *before;
char *message;
char *after;
};
int main (){
struct hello there= {
"Before",
"Hello",
"After",
};
printf("%ld\n", strlen(there.message));
printf("%s\n", there.message);
printf("%d\n", sizeof(there));
there.message = malloc(20 * sizeof(char));
there.message = "Hello, there!";
printf("%ld\n", strlen(there.message));
printf("%s\n", there.message);
printf("%s %s\n", there.before, there.after);
printf("%d\n", sizeof(there));
return 0;
}
I'm thinking something is not right because the size of my there didn't change.kj
Kind regards,
Not really ok, you have a memory leak, you could use valgrind to detect it at runtime (on Linux).
You are coding:
there.message = malloc(20 * sizeof(char));
there.message = "Hello, there!";
The first assignment call malloc(3). First, when calling malloc you should always test if it fails. But indeed it usually succeeds. So better code at least:
there.message = malloc(20 * sizeof(char));
if (!there.message)
{ perror("malloc of 20 failed"); exit (EXIT_FAILURE); }
The second assignment put the address of the constant literal string "Hello, there!" into the same pointer there.message, and you have lost the first value. You probably want to copy that constant string
strncpy (there.message, "Hello, there!", 20*sizeof(char));
(you could use just strcpy(3) but beware of buffer overflows)
You could get a fresh copy (in heap) of some string using strdup(3) (and GNU libc has also asprintf(3) ...)
there.message = strdup("Hello, There");
if (!there.message)
{ perror("strdup failed"); exit (EXIT_FAILURE); };
At last, it is good taste to free at program end the heap memory.
(But the operating system would supress the process space at _exit(2) time.
Read more about C programming, memory management, garbage collection. Perhaps consider using Boehm's conservative GC
A C pointer is just a memory address zone. Applications need to know their size.
PS. manual memory management in C is tricky, even for seasoned veteran programmers.
there.message = "Hello, there!" does not copy the string into the buffer. It sets the pointer to a new (generally static) buffer holding the string "Hello, there!". Thus, the code as written has a memory leak (allocated memory that never gets freed until the program exits).
But, yes, the malloc is fine in its own right. You'd generally use a strncpy, sprintf, or similar function to copy content into the buffer thus allocated.
Is it ok to change the allocation size of a pointer [...] ?
Huh? What do you mean by "changing the allocation size of a pointer"? Currently all your code does is leaking the 20 bytes you malloc()ated by assigning a different address to the pointer.
#inlcude <stdio.h>
#inlcude <stdlib.h>
#inlcude <string.h>
int main() {
char *buff = (char*)malloc(sizeof(char) * 5);
char *str = "abcdefghijklmnopqrstuvwxyz";
memcpy (buff, str, strlen(str));
while(*buff) {
printf("%c" , *buff++);
}
printf("\n");
return 0;
}
this code prints the whole string "abc...xyz". but "buff" has no enough memory to hold that string. how memcpy() works? does it use realloc() ?
Your code has Undefined Behavior. To answer your question, NO, memcpy doesn't use realloc.
sizeof(buf) should be adequate to accomodate strlen(str). Anything less is a crash.
The output might be printed as it's a small program, but in real big code it will cause hard to debug errors. Change your code to,
const char* const str = "abcdefghijklmnopqrstuvwxyz";
char* const buff = (char*)malloc(strlen(str) + 1);
Also, don't do *buff++ because you will loose the memory record (what you allocated). After malloc() one should do free(buff) once the memory usage is over, else it's a memory leak.
You might be getting the whole string printed out, but it is not safe and you are writing to and reading from unallocated memory. This produces Undefined Behavior.
memcpy does not do any memory allocation. It simply reads from and writes to the locations you provide. It doesn't check that it is alright to do so, and in this case you're lucky if your program doesn't crash.
how memcpy() works?
Because you've invoked undefined behavior. Undefined behavior may work exactly as you expect, and it may do something completely different. It may even differ between different runs of the same program. It could also format your hard disk and still be compliant with the standard (Though of course that's unlikely :P )
Undefined behavior means that the behavior is literally not defined to do anything. Anything is valid, including the behavior you're seeing. Note that if you try to free that memory the C runtime of your target platform will probably complain. ;)
No memcpy does not use malloc. As you suspected, you are writing off the end of of buff. In your simple example, that does no apparent harm, but it is bad. Here are some of the things that could go wrong in a "real" program:
You might scribble on something allocated in the memory following your buff leading to subtle (or not so subtle) bugs later on.
You might scribble on headers used internally by malloc and free, leading to crashes or other problems on your next call to those functions.
You might end up writing to an address that has not been allocated to your process, in which case your program will immediately crash. (I suspect this is what you were expecting.)
There are malloc implementations that put unmapped guard pages around allocated memory to (usually) cause the program to crash in cases like this. Other implementations will detect this, but only on your next call to malloc or free (or when you call a special function to check the heap).