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.
Related
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.
I'm reading a lot about malloc() and free() in Standard C. As I understand it, you malloc() for some memory exactly once and then you free() that same memory exactly once. It may be bad practice, but I understand that after you malloc() memory, you can define multiple pointers to it. And once you free() any of those pointers, the allocated memory is de-allocated?
Consider this toy example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
char* p = (char*)malloc(10 * sizeof(char)); // allocate memory
int* q = (int*)p; // pointer to the same block of memory
*p = 'A'; // Input some data
printf("TEST:: %c %d\n", *p, *q); // Everything's ok so far...
free(p); // free() my allocated memory?
sleep(10); // wait
printf("%c\n", *q); // q now points to de-allocated memory
// shouldn't this segfault?
free(q); // *** SEGFAULTS HERE ***
return 0;
}
Output is:
[Linux]$ ./a.out
TEST:: A 65
*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001ac4010 ***
======= Backtrace: =========
...lots of backtrack info...
So I assume that when I free() the first pointer, the memory is considered free()ed, but the data value(s) I wrote in this block of memory are still "there", which is why I can access them via the second pointer?
(I'm not proposing that this is a good idea, I'm trying to understand the logic of the system.)
When you malloc memory, you're given a pointer to some space, and when you free it, you're giving it back to the system. Often, you can still access this memory, but using memory after you have freed it is VERY BAD.
The exact behavior is undefined, but on most systems you can either continue to access the memory, or you get a segfault.
One interesting experiment you can try is to try and malloc more memory after you free'd that pointer. On most systems I've tried, you get the same block back (which is a problem, if you were relying on the data being there in the freed block). Your program would end up using both pointers, but since they point to the same physical data, you'll be overwriting your own data!
The reason for this is that when you malloc data (depending on the malloc implementation of course), malloc first requests a block of data from the operating system (typically much larger than the malloc request), and malloc will give you a segment of that memory. You'll be able to access any part of the memory malloc originally got from the operating system though, since to the operating system, it's all memory your program is internally using. When you make a free, you're telling the malloc system that the memory is free, and can be given back to the program later on.
Writing outside of the malloc area is very dangerous because
It can segfault, depending on your c implementation
You can overwrite metadata structures malloc is relying on, which causes VERY BAD PROBLEMS when you free/malloc more data later on
If you are interested in learning more, I would recommend running your program through valgrind, a leak detector, to get a better picture of what's freed/not freed.
PS: On systems without an OS, you most likely wont get a segfault at all, and you'll be able to wite anywhere willy nilly. The OS is responsible for triggering a segfault (when you write/read to memory you don't have access to, like kernel or protected memory)
If you are interested in learning more, you should try to write your own malloc, and/or read/learn about the memory management operating systems do.
The crash in your code is due to double free. Appendix J.2 of C11 says that behaviour is undefined for example when:
The pointer argument to the free or realloc function does not match a pointer earlier returned by a memory management function, or the space has been deallocated by a call to free or realloc (7.22.3.3, 7.22.3.5).
However it is possible to write code that will crash on Linux just by reading a value from memory that was just freed.
In glibc + Linux there are two different mechanisms of memory allocations. One uses the brk/sbrk to resize the data segment, and the other uses the mmap system call to ask the operating system to give large chunks of memory. The former is used for small allocations, like your 10 characters above, and mmap for large chunks. So you might get a crash by even accessing the memory just after free:
#include <stdio.h>
#include <stdlib.h>
int main(){
char* p = malloc(1024 * 1024);
printf("%d\n", *p);
free(p);
printf("%d\n", *p);
}
And finally, the C11 standard says that the behaviour is undefined even when
The value of a pointer that refers to space deallocated by a call to the free or realloc function is used (7.22.3).
This means that after not only that dereferencing the pointer (*p) has undefined behaviour, but also that it is not safe to use the pointer in any other way, even doing p == NULL has UB. This follows from C11 6.2.4p2 that says:
The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.
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...
My question is very simple one. Say we have:
char* ptr = (char*) malloc(sizeof(char)*SIZE);
ptr+= SIZE/2;
free(ptr);
What happens when we free the pointer? Is it undefined operation?
Does it free all of SIZE buffer or only the remaining SIZE/2?
Thanks in advance for disambiguating this for me.
Your program will probably crash: the free() operation is actually quite simple in C, but works only on the original allocated address.
The typical memory allocator works like this pseudo code:
ask to alloc 64 bytes
allocator allocs 70 bytes (6 bytes more)
the first 2 bytes is set to a "signature", a pattern recognized by the allocator to identify the memory allocated by him
the next 4 bytes denote the allocated size
return a pointer to the start of the 7th byte
So when you call free(ptr), the allocator goes 6 bytes before your pointer to check for the signature. If it doesn't find the signature, it crashes :)
If the argument to free() does not match a pointer previously allocated by means of malloc() and friends, the behaviour is undefined. You will most likely encounter a segmentation fault or a failed assertion in your version of libc.
Offtopic: it's better you didn't cast the result of malloc() in C.
The behavior is undefined and will most likely result in a segmentation fault - and that's the good case. In the worst case, it will corrupt your program's memory and induce all kind of weird bugs and wrong outputs.
On most implementations this should result in some sort of fatal error. You can only free the begining of an allocated buffer.
They typical error you would get on windows (with the visual studio compilers) would be something like "not a valid heap pointer". On linux, as said above by phihag, it would usually result in a segmentation fault. In both cases, it is a runtime error that would usually terminate the execution of the program.
The behaviour is undefined. I guess you'd get a segfault ... that's what I got when I tried in my system.
free() requires the caller to pass an address that was returned by a memory allocator function like malloc(). Anything else results in undefined behaviour.
I am studying for a test, and I was wondering if any of these are equivalent to free(ptr):
malloc(NULL);
calloc(ptr);
realloc(NULL, ptr);
calloc(ptr, 0);
realloc(ptr, 0);
From what I understand, none of these will work because the free() function actually tells C that the memory after ptr is available again for it to use. Sorry that this is kind of a noob question, but help would be appreciated.
Actually, the last of those is equivalent to a call to free(). Read the specification of realloc() very carefully, and you will find it can allocate data anew, or change the size of an allocation (which, especially if the new size is larger than the old, might move the data around), and it can release memory too. In fact, you don't need the other functions; they can all be written in terms of realloc(). Not that anyone in their right mind would do so...but it could be done.
See Steve Maguire's "Writing Solid Code" for a complete dissection of the perils of the malloc() family of functions. See the ACCU web site for a complete dissection of the perils of reading "Writing Solid Code". I'm not convinced it is as bad as the reviews make it out to be - though its complete lack of a treatment of const does date it (back to the early 90s, when C89 was still new and not widely implemented in full).
D McKee's notes about MacOS X 10.5 (BSD) are interesting...
The C99 standard says:
7.20.3.3 The malloc function
Synopsis
#include <stdlib.h>
void *malloc(size_t size);
Description
The malloc function allocates space for an object whose size is specified by size and
whose value is indeterminate.
Returns
The malloc function returns either a null pointer or a pointer to the allocated space.
7.20.3.4 The realloc function
Synopsis
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
Description
The realloc function deallocates the old object pointed to by ptr and returns a
pointer to a new object that has the size specified by size. The contents of the new
object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.
If ptr is a null pointer, the realloc function behaves like the malloc function for the
specified size. Otherwise, if ptr 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 the free or realloc function, the behavior is undefined. If memory for the new
object cannot be allocated, the old object is not deallocated and its value is unchanged.
Returns
The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
Apart from editorial changes because of extra headers and functions, the ISO/IEC 9899:2011 standard says the same as C99, but in section 7.22.3 instead of 7.20.3.
The Solaris 10 (SPARC) man page for realloc says:
The realloc() function changes the size of the block pointer to by ptr to size bytes and returns a pointer to the (possibly moved) block. The contents will be unchanged up to the lesser of the new and old sizes. If the new size of the block requires movement of the block, the space for the previous instantiation of the block is freed. If the new size is larger, the contents of the newly allocated portion of the block are unspecified. If ptr is NULL, realloc() behaves like malloc() for the specified size. If size is 0 and ptr is not a null pointer, the space pointed to is freed.
That's a pretty explicit 'it works like free()' statement.
However, that MacOS X 10.5 or BSD says anything different reaffirms the "No-one in their right mind" part of my first paragraph.
There is, of course, the C99 Rationale...It says:
7.20.3 Memory management functions
The treatment of null pointers and zero-length allocation requests in the definition of these
functions was in part guided by a desire to support this paradigm:
OBJ * p; // pointer to a variable list of OBJs
/* initial allocation */
p = (OBJ *) calloc(0, sizeof(OBJ));
/* ... */
/* reallocations until size settles */
while(1) {
p = (OBJ *) realloc((void *)p, c * sizeof(OBJ));
/* change value of c or break out of loop */
}
This coding style, not necessarily endorsed by the Committee, is reported to be in widespread
use.
Some implementations have returned non-null values for allocation requests of zero bytes.
Although this strategy has the theoretical advantage of distinguishing between “nothing” and “zero” (an unallocated pointer vs. a pointer to zero-length space), it has the more compelling
theoretical disadvantage of requiring the concept of a zero-length object. Since such objects
cannot be declared, the only way they could come into existence would be through such
allocation requests.
The C89 Committee decided not to accept the idea of zero-length objects. The allocation
functions may therefore return a null pointer for an allocation request of zero bytes. Note that this treatment does not preclude the paradigm outlined above.
QUIET CHANGE IN C89
A program which relies on size-zero allocation requests returning a non-null pointer
will behave differently.
[...]
7.20.3.4 The realloc function
A null first argument is permissible. If the first argument is not null, and the second argument is 0, then the call frees the memory pointed to by the first argument, and a null argument may be
returned; C99 is consistent with the policy of not allowing zero-sized objects.
A new feature of C99: the realloc function was changed to make it clear that the pointed-to
object is deallocated, a new object is allocated, and the content of the new object is the same as
that of the old object up to the lesser of the two sizes. C89 attempted to specify that the new object was the same object as the old object but might have a different address. This conflicts
with other parts of the Standard that assume that the address of an object is constant during its
lifetime. Also, implementations that support an actual allocation when the size is zero do not
necessarily return a null pointer for this case. C89 appeared to require a null return value, and
the Committee felt that this was too restrictive.
Thomas Padron-McCarthy observed:
C89 explicitly says: "If size is zero and ptr is not a null pointer, the object it points to is freed." So they seem to have removed that sentence in C99?
Yes, they have removed that sentence because it is subsumed by the opening sentence:
The realloc function deallocates the old object pointed to by ptr
There's no wriggle room there; the old object is deallocated. If the requested size is zero, then you get back whatever malloc(0) might return, which is often (usually) a null pointer but might be a non-null pointer that can also be returned to free() but which cannot legitimately be dereferenced.
realloc(ptr, 0);
is equivalent to free(ptr); (although I wouldn't recommended its use as such!)
Also: these two calls are equivalent to each other (but not to free):
realloc(NULL,size)
malloc(size)
The last one--realloc(ptr, 0)--comes close. It will free any allocated block and replace it with a minimal allocation (says my Mac OS X 10.5 manpage). Check your local manpage to see what it does on your system.
That is, if ptr pointed at a substantial object, you'll get back most of its memory.
The man page on Debian Lenny agrees with Mitch and Jonathan...does BSD really diverge from Linux on this?
From the offending man page:
The realloc() function tries to change the size of the allocation pointed
to by ptr to size, and returns ptr. [...]
If size is zero and ptr is not NULL, a new,
minimum sized object is allocated and the original object is freed.
The linux and solaris man pages are very clean, and the '89 standard: realloc(ptr,0) works like free(ptr). The Mac OS manpage above, and the standard as quoted by Jonathan are less clear but seems to leave room to break the equivalence.
I've been wondering why the difference: the "act like free" interpretation seems very natural to me. Both of the implementations I have access to include some environment variable driven tunablity, but the BSD version accepts many more options Some examples:
MallocGuardEdges If set, add a guard page before and after
each large block.
MallocDoNotProtectPrelude If set, do not add a guard page before large
blocks, even if the MallocGuardEdges envi-
ronment variable is set.
MallocDoNotProtectPostlude If set, do not add a guard page after large
blocks, even if the MallocGuardEdges envi-
ronment variable is set.
and
MallocPreScribble If set, fill memory that has been allocated
with 0xaa bytes. This increases the likeli-
hood that a program making assumptions about
the contents of freshly allocated memory
will fail.
MallocScribble If set, fill memory that has been deallo-
cated with 0x55 bytes. This increases the
likelihood that a program will fail due to
accessing memory that is no longer allo-
cated.
Possibly the "minimum sized object" is nothing (i.e. equivalent to free) in the normal modes, but something with some of the guards in place. Take that for what it's worth.