Freeing pointer after pointer arithmetic - c

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.

Related

Acessing beyond the allocated space and not getting segfault

I allocated some space for a char pointer and tried to access beyond the allocated space but still getting no segmentation fault. my code is like below:
char *src = malloc(4);
strcpy(src, "1234");
char *temp;
for(int i = 0 ; i<5 ; i++) {
temp = src;
src ++;
printf("ite ch %c\n",src[0]);
}
printf("Still no segfault %s\n",temp);
Now my question is: how can I go beyond the allocated space? Shouldn't I get segmentation fault?
When you write past the end of a memory block allocated by malloc as you've done here, you invoke undefined behavior.
Undefined behavior means the behavior of the program can't be predicted. It could crash, it could output strange results, or it could appear to work properly. Also, a seemingly unrelated change such as adding an unused local variable or a call to printf for debugging can change the way undefined behavior manifests itself.
To summarize, with undefined behavior, just because the program could crash doesn't mean it will.
The malloc() function implementation is system and library specific. One of the things that many memory allocation implementations have to deal with is memory fragmentation.
The question code allocates 4 bytes. In order to minimize memory fragmentation, many systems actually allocate more than 4; perhaps a minimum of 16 bytes. Doing so both satisfies the malloc(4) request, as well as keeps memory fragments (once the memory has been freed) to a minimum size of 16 bytes. Hence a "memory fragment pool" of 16 byte fragments can be used to satisfy malloc() request from 1 to 16 bytes.
Many memory management systems maintain "memory fragment pools" of 16,32,64,128, (etc) bytes each. For example, if a call of malloc(44) is made, a memory fragment from the 64 byte pool can satisfy the request.
On some systems, there is a provision to determine the actual size of the memory fragment returned by malloc(). On a Linux system, the function malloc_usable_size() performs this function. OS X systems can use malloc_size().

malloc(): memory corruption

Here is the simplified program that I think can lead to this error.
char *p = (char*)malloc(8192);
for(int i = 0; i < 9200; ++i){
p[i] = '1';
}
char *s = (char*)malloc(strlen(p));
The original project is rather complicated, so I simplified it. I assigned 8192 bytes using malloc. Then my program will write more than 8192 characters in to the array. Then I will allocate memory using malloc.
This mini program didn't crash. But in the original big project, it crashes with this error:
malloc(): memory corruption: 0x0000000007d20bd0 ***
What may cause this difference?
It is undefined behavior because you have allocated 8192 bytes memory but you are trying to write 9200 bytes. Which is out of bound.
What may cause this difference?
Basically, the memory allocator allocates pages of memory at once for use by programs, and it gives you a pointer within them (making sure the following space is free for use). Since these pages are usually bigger than 8KiB, you have no issue in your mini-program. But if a larger program is allocating larger amounts of memory and writing further and further past the end of your allocated space, then you'll end up attempting to write into unallocated memory (or memory used by another program!), thus corrupting memory.
Writing to memory which you have not allocated is undefined behaviour. That's because malloc() returns a section of memory which you may write to, so when you write past the end of that region, you are overwriting something which is not yours.
That could be a structure used by malloc itself, or something else entirely.
It is a matter of luck. Your operating system may reserve memory more than the 8kB you requested. Also what you have reserved before and after may have an effect on the behaviour.
It is not said that your program will crash on buffer overflow. In fact the behaviour is undefined or implementation defined.

C - Accessing data AFTER memory has been free()ed?

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.

malloc'd memory and sigsegv

help me in understanding the malloc behaviour.. my code is as follows::
int main()
{
int *ptr=NULL;
ptr=(int *)malloc(1);
//check for malloc
*ptr=1000;
printf("address of ptr is %p and value of ptr is %d\n",ptr,*ptr);
return 0;
}
the above program works fine(runs without error)...how?? as I have supplied a value of 1000 in 1 byte only!!
Am I overwriting the next memory addresss in heap?
if yes, then why not sigsgev is there?
Many implementations of malloc will allocate at a certain "resolution" for efficiency.
That means that, even though you asked for one byte, you may well have gotten 16 or 32.
However, it's not something you can rely on since it's undefined behaviour.
Undefined behaviour means that anything can happen, including the whole thing working despite the problematic code :-)
Using a debug heap you will definitely get a crash or some other notification when you freed the memory (but you didn't call free).
Segmentation faults are for page-level access violations, and a memory page is usually on the order of 4k, so an overrun by 3 bytes isn't likely to be detected until some finer grained check detects it or some other part of your code crashes because you overwrote some memory with 'garbage'

C code - malloc and free

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.

Resources