User-implemented memory management [closed] - c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am given a C project assignment in which I am asked to implement a simple memory management library. The way it works is that it has init function which takes a pointer(void*) to a chunk of memory allocated by another c program along with the size of the chunk and has two other functions to allocate a block of requested size from the said chunk and deallocate a block when passed back the pointer pointing to it.
Problem is that I am asked to keep my management structures inside the chunk itself and I have zero idea on how to do that. I thought about dividing the chunk into frames but how can I keep track of which frames are allocated without using anything from outside the chunk?
Edit: Init function is used like this. There is this program which will call the library I am going to write. It will allocate a chunk of memory using either malloc or calloc. Then it will call the init function from the library and pass the pointer to that memory chunk along with the size of the chunk to it.
What my library will do with that chunk is to allocate blocks from it on demand. So my library's allocate function actually is a call to request a block of memory(size is passed as an argument) from the chunk. And it will return a (void *) pointer pointing to the allocated memory block.
Edit2: To make the situation more clear, my library has to be able to allocate and deallocate which means holes will appear in the chunk it is managing and it will employ either first-fit, best-fit or worst-fit.
Edit3: Is there a way to convert memory addresses into long int?

Here's a rough idea of what you would need to do:
The memory segment should be structured as a linked list of blocks. Each block starts with a copy of your management structure followed by the memory that you allocate.
On initialization, point the head of the linked list to the start of the given memory segment. Set the size to the size of the segment minus the size of the management structure, and set the next pointer to NULL.
When the first allocation request is made, set the size of the head block to the requested size, then set the next pointer to the memory immediately after that. Set the size of the new block to the old head size minus the requested size and the size of the management struct.
For a deallocation, you would need to find the block prior to the one you're about to release. Change the size of the prior block to the size of the freed block plus the struct size, then change the next pointer to the freed block's next pointer.
That should be enough to get you started.

Related

How is malloc handled at compile time and run time? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
Is malloc used to specify at compile time - a maximum size of a buffer(array) pointed to by a pointer and then allocated that max sized buffer by default in run-time and later - only that part of the buffer is actually used (though full size was allocated) that we need (by taking data from user etc) ?
If the above is true - then that means malloc (used along pointers) essentially provides a way to model a (including higher dimensions - but for eg -2) 2-D array as a 1-d array of pointers, and then at compile time specify the size of buffer to be allocated to each individual pointer i.e. essentially accomplishing the same thing as declaring it as a 2-D array with max dimensions specified in declaration at compile time - but just allowing to model/visualize it differently. Both are allocated the default max size - array type declaration at the the run of the declaration statement, while pointer+ malloc type at the run of the malloc statement (I do think this size information is used in both cases to calculate the size of stack+heap sum required for run).
That is in pointer+malloc, once compiler sees that this information (max buffer size for each pointer using malloc) is available at compile time - compilation can go through as it has the information of how much memory to allocate by default and can (and does) also use that information to calculate the size of stack+heap sum required for the function run (if no malloc - then it points to a single element). Later at run-time - the max sized buffer is allocated after malloc statement is run, to be later used as input needs.
There is a reason why allocating memory using malloc, calloc and realloc is called dynamic memory management. Dynamic in this context means that which happens at run-time. This does not happen at compile time.
If the above is true...
Since it is not true, what follows is not derivable from it.
malloc is a function of the standard C library.
All functions are called at runtime.
The only thing that happens at compile time is creating a function call to malloc

Stack Implementations in C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Iā€™m stuck trying to figure out what, exactly, are the definitions of the following stack implementations and the advantages and disadvantages associated with each.
1.Array-based implementation
2.Linked implementation
3.Blocked implementation
Any help would be much appreciated.
A user of a stack implementation expects a dynamic data structure. C does not provide that directly in language terms. You have to allocate and administrate the memory your own.
Allocating an array, therefore a static sized structure, is very easy. However, you have the problem, that the number of maximum entries is limited. If you make the array too small, this will cause errors, if you make the array very big, you are waisting memory.
A solution for this is to dynamically reallocate the array, if the number of entries exceeds the array size. But this moves the whole memory to another place in memory, what has some disadvantages. (I. e. you have to copy the whole memroy and it is not possible to hold a pointer to a specific entry.)
Having a linked list is the contrary. You (dynamically) allocate memory for each entry. You can free the memory for a single entry on removing from stack. This sounds better, but has the caveat, that you spent a pointer size of memory for each entry. Typically this is the size for an entry. So you double the memory consumption. Beside this, allocating small pieces of memory over and over wastes memory, too.
So you can implement a compromise: A linked list of arrays: You allocate a block for a number of entries, let's say 256. Then you fill that block with entries, without reallocating or allocating memory. If the number of entries exceeds that value, you allocate a new block for additional 256 entries. The blocks are linked. So it is a linked list of arrays.
Esp. for a stack ā€“ you do not have removals in the middle of the structure ā€“ this is the best implementation in most cases.
Think about how much space each data structure takes, and whether you can do the stack operations on them efficiently; i.e., in O(1) time.
For a basic stack, you need to be able to push new elements onto the stack, and pop the most recently pushed (top) element off. You probably also want to peek at the top element, and check if the stack is empty.
A dynamically sized array (or block, if I understand the OP's comment correctly) is fine for a stack. It may be advantageous in certain situations if you will be accessing and changing the stack a lot, and want to avoid the small amount of extra work of allocating and destroying memory with each push or pop. It also gives you direct, indexed access to everything in the stack, for extended functionality. The disadvantage is that the stack will use some extra space.
You can use a singly-linked-list list for a stack as well, pushing and popping at the head. This is probably the most common type structure used if you don't need extended functionality like direct access to the elements besides the head, and if you aren't trying to implement something on the bleeding edge of time efficiency.

Why does invalid memset() after malloc() leads to free(): invalid next size (fast) [duplicate]

This question already has an answer here:
free char*: invalid next size (fast) [duplicate]
(1 answer)
Closed 8 years ago.
Code snippet, at the bottom, which I was trying lead to the following error
free(): invalid next size (fast)
Above error, was caused by declaration of integer variable mock after accidently calling memset() on pointer check with size more than what was originally allocated using malloc(). And when free() is called on pointer check it leads to a runtime error.
It would be helpful if somebody could explain how the internal memory is being manipulated or why this error actually occurred.
Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *check = (char *)malloc(sizeof(char) * 10);
memset(check, 0, 100);
memcpy(check, "memsetcpy", 10);
int mock = 9;
free(check);
return 1;
}
EDIT My intention of asking the question was to know/understand what happens to the book-keeping information in the heap memory when the program runs. And may be to have some information on data structures that are modified would be great.
OR I wanted to know from the design perspective.
Thanks everyone for chipping-in.
When the program writes outside defined memory space, anything could happen.
In this case, the program has damaged the heap.
This is the signature of memset:
void * memset ( void * ptr, int value, size_t num );
With malloc, you allocate 10 bytes of memory, and assign a pointer to that memory to check. (Not a solution, but you should not cast the return value of malloc)
Then with memset, you write 100 bytes of zeroes to the block of memory pointed to by check.
Your program writes correctly to the first ten bytes, then zeroes out whatever is in the 90 following the allocated space. Since you're writing outside of allocated memory, anything could happen, and in this case, I'd guess you're writing over memory that contains bookkeeping info for the malloc/free memory allocation system. Of course, since you're invoking undefined behavior, it would also be acceptable for it to cause your computer to grow legs and walk away.
A typical dynamic memory (heap) implementation stores a lot of household information right there, in the very same memory, interleaved with user data. Each block of memory you allocate typically includes a special header region and, possibly, a special footer region. These regions surround your user region from both ends. You are only allowed to manipulate memory inside your user region. But the moment you write anything outside the boundaries of that user region, you most certainly damage those internal header and footer regions. This completely destroys the integrity of dynamic memory management subsystem. The rest follows.
In your case you go outside your user region by 90 bytes. This is a lot. You probably destroyed a lot of internal household data that is critical for proper operation of dynamic memory.
The specific details of this (what gets damaged and how it affects free later) are very, very, very implementation-dependent. Different implementations can be wildly different in that regard. There's no way to provide a more specific description without at least knowing what specific implementation you are using.
In modern operating systems, allocated memory is managed in very large chunks from kernel space and then allocated in smaller chunks by user space code.
The user space code keeps track of the allocated and free memory typically through the use of a doubly linked list along with sentinel data before and after each allocated chunk. The sentinel data includes things like a magic number, chunk size, etc.
The sentinel data helps the memory manager detect when a user program writes past (or before) it's allocated size. The use of a doubly linked list helps the memory manager combine the freed smaller chunks into larger freed segments to help avoid fragmentation.
When you write beyond your allocated size, you not only destroy the sentinel data but also probably the linked-list data. Once the linked list gets destroyed, most memory managers fall apart thus the comments about things going off the reservation.
Hope this helps.

allocating memory sequencially in C [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I wanted to test malloc() to see if allocating to the same adress twice adds up to the memory, or just replaces it: int *ptr = malloc(sizeof(int)); ptr = malloc(2*sizeof(int)); Will this memory be 3 ints large or just 2 ?
When I test how many ints can fit in, I get about 200, after which I get errors during runtime. Can someone please explain the randomness of memory allocation ?
malloc() always allocates a new block of memory, of the size you request, assuming that memory is available. It returns a pointer to the first byte of the memory it allocated so that you can use it. When you do your second malloc() call, it overwrites the pointer to the memory you allocated in the first, so you can't access it anymore - but it's still there and it's still allocated to you. This is usually called a memory leak, because your process has grabbed memory and then not given it back despite no longer using it.
So after your second call, you've allocated enough memory to store three integers, in two separate blocks, the first of which can no longer be accessed because you don't have a pointer to it anymore.
There is no randomness in memory allocation.
I'm not sure why you're getting runtime errors when you get to 200 ints, unless your process has very constrained memory availability. It'd help to know what the errors you're getting actually are.
Will this memory be 3 ints large or just 2 ?
ptr will point to memory for two ints when you reassign to ptr the previous memory location is now lost and that memory is leaked.
malloc simply return void pointer to the allocated memory.2*sizeof(int) will allocate 2*sizeof(int) bytes means memory for two integers.
Initially you gave memory for one integer only then again on same pointer you assigned memory for two integer.So finally it will point for two integer size space.

How comes free() doesn't need a length parameter? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C programming : How does free know how much to free?
A random thought occured to me that how comes free(myPtr) doesn't need a length parameter? How does it know how much memory to free?
I can only guess that it keeps track of how much memory it allocates for each particular start address.
This is because malloc saves the information about the length of the allocated chunk, usually in a spot that precedes the address returned to your program. It is not unusual for implementations to allocate an extra storage for a size_t, put the size there, add sizeof(size_t), and return it to you as the malloc-ed pointer. The standard does not call for this implementation, thoug, so alternative implementations are possible, e.g. based on a hash table.
When C allocates memory, it records the length associated with the pointer it gives you. (Often in the area just before the block of memory. But that's an implementation detail.) It keeps some kind of table or list of memory blocks it's handed out, and when you free that memory, C looks up the length of that block based on the value of the pointer.
That's part of why the pointer you pass to free has to be exactly equal to the one you get back from malloc. If it's not, C gets confused and can't find the correct memory block (or its length), and may very well end up "freeing" some memory it was never meant to touch. (If it does that, you may end up with a condition called "heap corruption", which is really bad -- from then on, C might do all kinds of wacky stuff, like trying to allocate some memory in the middle of an existing block and mangling whatever's there.)

Resources