I am currently working on implementing my own malloc() function. The one thing that seems to not be working is that I'm unable to correctly return the memory address of the beginning of my current block. My block struct looks like this and is of size 16:
typedef struct block {
size_t size;
struct block* next;
struct block* prev;
int free;
} block_t;
My malloc looks like this currently:
void *bmalloc(size_t size)
{
void * mem=0;
size_t alloc=size;
if (freelist==0)
{
freelist=&heap[0];
freelist->free=0;
freelist->prev=0;
freelist->size=MAX_HEAP_SIZE;
freelist->next=0;
//printf("is this happening?");
}
for (curr=freelist;curr!=NULL;curr=curr->next)
{
if (alloc<=curr->size && curr->free==0)
{
block_t *tmp=curr->next;
curr->free=1;
curr>size=MAX_HEAP_SIZE;
curr>next=curr+alloc+sizeof(block_t);
//curr->next->next=tmp;
curr->next->size=curr->size-alloc;
curr->next->free=0;
curr->next->prev=curr;
mem=curr+sizeof(block_t)
return mem;
}
}
}
Curr and Freelist are both block_t structs. I know the issue must lie in the step where I set mem=curr+sizeof(block_t), but I'm not really sure how to fix it. Upon some checking I noticed that the first allocation of memory returns an address 276 bytes away from the beginning of the array the blocks live on top of, and after the first allocation the blocks memory addresses are 512 bytes away.
Whenever you do pointer arithmetic, the values are always scaled by the size of the type the pointer points at. So when you do
mem = cur + sizeof(block_t);
since cur is a block_t *, the addition is scaled by sizeof(block_t) automatically. Which means that if sizeof(block_t) is 16, this will add 256 bytes to the pointer, which is not what you want. You probably just want
mem = cur + 1;
here, and similar changes elsewhere.
Related
I was wondering if it was possible to over allocate and free excess that you have allocated? I was thinking something along the lines of
/*
This is a pseudo program, just to show what I am talking about, there should be more
checks to prevent overflow.
*/
typedef struct {
struct Node *neighbor
int value
} Node;
...
Node create_tree(char* content, int size) {
int mem_index = 0
Node *last_node;
// size > sizeof(Node)
void base* = malloc(size);
while( mem_index < size) {
Node nptr* = (Node)(base + mem_index);
if(last_node != NULL) nptr->neighbor = last_node;
last_node = nptr;
mem_index += sizeof(Node);
nptr->value = (int)(base + mem_index)
(nptr->value)* = get_some_content(content);
mem_index += sizeof(int);
}
free((base + mem_index));
}
Basically this program over allocates and begins casting the memory into structures and then writes to those structures. It points the pointers within the structure to further points in the memory. It then writes another structure past all of that unit it is done with writing. I am wondering if this is possible, and if it is, is it good practice? I have heard under allocating is an issue, and I am not a fan of allocating every time I want to create a new structure if I am going to be creating them dynamically.
You can use realloc to shrink the memory block to the desired size:
base2 = realloc(base, mem_index);
If the call is successful, then the memory after base + mem_index will be freed.
BTW. Using pointer of type void* for arithmetic is GCC extension. You should use char*.
Note that returned base2 may not be same as the original base. You update all existing references to base with base2.
I am writing an early kernel heap to manage some memory allocations before the final heap is operational. When I assign an address(not used by anything else) to my struct pointer it works, the problem comes when I try to assign values to the struct members.
Before you answer, take in mind that I do not have any kind of C library which I can use. Debugging was done with QEMU and gdb through remote.
//The struct
typedef struct mem_block{
mblock_t *prev;
boolean used;
size_t size;
mblock_t *next;
} mblock_t;
//The file-local pointer(before its init)
mblock_t *eheap=NULL;
//Function that assigns the values
mblock_t *init_early_heap(address_t start, size_t size){
if(eheap==NULL){
if(size < sizeof(mblock_t)){
PANIC("Available memory below EHEAP requirement");
}
eheap = (mblock_t*)HEAP_START_ADDRESS;
eheap->prev = NULL;
eheap->next = NULL;
eheap->size = (size_t)(size - sizeof(mblock_t));
eheap->used = false;
print("\nCreated Early Heap at ");
print_hex_long(eheap);
print("\nSize in bytes: ");
print(itos(eheap->size));NL;
}
return eheap;
}
After the function returns, I get a pointer pointing at address 0xC0000000 and untouched members as eheap->size is 0(size parameter in the function is NOT 0).
Problem found: Cannot read whole address space (A20 on) in QEMU, works correctly with bit lower addresses.
The C code above is correct, now the problem remains with QEMU/GRUB.
So I am working on a project in C where we need to implement malloc and free (meaning, we CANNOT use any C memory management functions such as malloc() or free()). This is only a code snippet, but it includes all relevant parts.
struct block_header
{
int size;
};
typedef struct FList_elem
{
struct block_header * header;
struct list_elem elem;
} FLelem;
void * manual_malloc(size_t size)
{
freeBlock = (FLelem *) mem_sbrk(newsize);
freeBlock->header = (struct block_header *) freeBlock;
freeBlock->header->size = newsize;
}
When allocating a new "block" of memory, we represent it via a structure FList_elem. In order to "allocate memory" for the struct, we point it at a memory address returned by mem_sbrk (works just like sbrk()). My question is, how do we establish memory for variables like size? Initially it's address is 0x0, and so assignments or references to it cause seg faults. Does it need to be a pointer so that we can set it's address, and then the value?
Instead of your original code, which stores a pointer to block_header inside the FList_elem structure, you can just embed the whole block_header structure inside the FList_elem structure:
struct block_header
{
int size;
};
typedef struct FList_elem
{
/* OLD code: struct block_header * header; */
/* Better code: block_header is embedded inside FList_elem structure */
struct block_header header;
struct list_elem elem;
} FLelem;
In this way, you don't need to allocate block_header separately: it's just there with the rest of FList_elem bytes.
And to set the size field (and any other attribute you may add to your block header) you can just do:
freeBlock->header.size = newsize;
When allocating the requested size, you need to add the header elements - and the pointer to the next block (eventually - the size can be computed with pointer difference as a space optimization... if this is embedded staff they are 4 bytes per block saved).
Since I think there are some incongruences, I have reported here my interpretation (not tested) of what you are trying to do:
struct block_header
{
int size;
};
typedef struct FList_elem
{
struct block_header header; // removed a * here: size is in place
struct Flist_elem *elem; // added a * here: that's the pointer to the next block.
} FLelem;
FLelem *memory_list = 0; // added a pointer for the global list - right?
void * manual_malloc(size_t newsize) // renamed as newsize here
{
freeBlock = (FLelem *) mem_sbrk(newsize + sizeof(FLelem));
freeBlock->header.size = newsize;
freeBlock->header.elem = memory_list;
memory_list = freeBlock;
// inserted freeBlock at the head of memory_list;
return (void*)(freeBlock+1); // +1 to skip the header as a return address
}
The caller of the function will have returned the space after the header.
Your manual_free() function will take as an argument this returned memory pointer, and it will need to subtract and go back a freeblock in memory in order to find the header and to release the block, and than you will need some sort of tree (bit tree) to keep of track of the holes left free... If you need to handle dynamic memory - and that's where it start being interesting.
Hope I have not done errors and that it's clear enough!
#include <stdlib.h>
struct st *x = malloc(sizeof *x);
Note that:
x must be a pointer
no cast is required
include appropriate header
I have a unsigned char* head that is pointing to a certain addess in memory and now I have to create a typedef struct that I've declared starting at the location of that pointer...I am confused on how to do that!
Here is the declaration of the typedef
typedef struct {
struct block *next;
struct block *prev;
int size;
unsigned char *buffer;
} block;
My assignment involves implementing malloc, so I can't use malloc. A block is part of a free_list which contains all chunks of free memory blocks that I have in my program heap. Hence, the previous and next pointers that point to the previous and next free blocks of memory.
Head points to the start of the free_list. When I have to split say the first block of free memory to satisfy a malloc() request that needs less space then that free block has I need to move my head and create a new block struct there.
Hope this makes sense. If not, the assignment looks something like this
Your struct has no tag, so you need to give it one in order for it to point to itself:
typedef struct block {
struct block *next;
struct block *prev;
int size;
unsigned char *buffer;
} block;
If you're using C99 you can initialise the memory at head directly, if necessary, without declaring a temporary struct block:
*(block *)head = (block){NULL, NULL, 0, NULL};
You now have a struct block at the address head, as long as you cast it properly.
e.g.
((block *)head)->size = 5;
Or you assign a cast pointer to it:
block *p = (block *)head;
p->size = 5;
unsigned char* head = /* whatever you have assuming that it has a sufficient size. */;
/* Create a block in memory */
block* b = (block*)malloc(sizeof(block));
/*
* modify data in b here as you wish.
*/
b->next = 0;
b->prev = 0;
/* etc... */
/* copy b to head */
memcpy(head, b, sizeof(block));
/* free block */
free(b);
The above assumes that head has enough space to store an instance of block.
What it does is create a block, and copy the memory to the position of head, then free the allocated block.
From comments:
head points to the start of a place in memory where I can overwrite data...You may assume that I have enough space!
Then to obtain a properly typed pointer:
struct block *p = (struct block *)head;
and to have a copy of the block:
struct block b = *(struct block *)head;
The operating system will provide an API call to allocate blocks of memory that your malloc can carve up and provide to callers. In Linux/unix look at sbrk. In Windows look at the Win32 heap API. Your records will point into this block. Making sure no two allocated sections of the block overlap is the job of your allocator code.
It looks like your records are implementing a free list. So how are you going to allocate list nodes when you don't have an allocator (yet)? The usual solution is to do it in the free blocks themselves. So a free block has the structure:
typedef struct free_block {
struct free_block *next, *prev;
size_t size;
unsigned char buffer[1];
} FREE_BLOCK;
Now this data structure actually lies at the start of a free block. Its buffer has only 1 byte in the declaration, but the actual buffer is size bytes. Initially you'd have something like:
static FREE_BLOCK *free_list = sbrk(ARENA_SIZE);
free_list->next = free_list->prev = free_list;
free_list->size = ARENA_SIZE - offsetof(FREEBLOCK, buffer);
This places the whole arena on the free list as a single block. Your allocator will search free_list to find a block that's big enough, carve out the piece it needs, put the remaining small block (if any) back on the free list. For freeing, it will add the freed block to the list and coalesce adjacent blocks.
Simple free list allocators differ in how they choose the free block to allocate from: first fit, rotating first fit, best fit, worst fit, etc. In practice rotating first fit seems to work as well as or better than any of the others.
Incidentally, all of the common algorithms implemented with free lists don't need double links. Single ones will do.
Since this is an academic assignment, it should be fine to just call malloc (instead of an operating system API) to establish the big block (often called the "arena") your allocator will manage. You could also declare a big array of bytes.
Having trouble with my task here. I need to create a global block of free memory and malloc it. Having some trouble initialising it due to typecast and handling errors.
Like arrays in C where the first array is actually a pointer to the first element, my memory block needs to be similar where i can use pointer arithmetic to locate blocks of memory.
//global variable
static byte *memory = NULL;
void allocator_init(u_int32_t size){
*memory = (byte*) malloc(size);
}
The addresses/pointers to these memory addresses will be stored via structs/links as headers of the memory block.
typedef struct _header {
int signiture;
int size;
header* next;
header* prev;
} header;
Drop the *:
*memory = (byte*) malloc(size);
^
You might also want to drop the cast but that's your call.
You need to assign the return value of malloc to the pointer itself, not to the byte pointed to by the pointer. (Anyway, if you dereference the initially NULL pointer, your program will segfault.)
memory = malloc(size);
Also, don't caat the return value of malloc.
*memory = (byte*) malloc(size); - This statement means you are trying to assign the address of the heap memory block as a value to *memory. Here memory is having NULL, so it will crash.
You have to assign the addres to the variable like, memory = (byte*) malloc(size);
In your header struct, since the struct references itself, declare the internal header pointers as "struct _header * name;". I think other people have hit all the other points :)