Implementing malloc in multithreaded environment - c

I want to implement malloc in a multithreaded environment, and I got the code from here.
After adding in mutex:
typedef struct free_block {
size_t size;
struct free_block* next;
pthread_mutex_t lock;
} free_block;
void free_block_init(free_block *FB){
pthread_mutex_init(&FB->lock, NULL);
}
static free_block free_block_list_head = { 0, 0 };
static const size_t overhead = sizeof(size_t);
static const size_t align_to = 8;
void* mymalloc(unsigned int size) {
size = (size + sizeof(size_t) + (align_to - 1)) & ~ (align_to - 1);
free_block* block = free_block_list_head.next;
pthread_mutex_lock(&block->lock);
free_block** head = &(free_block_list_head.next);
while (block != 0) {
if (block->size >= size) {
*head = block->next;
pthread_mutex_unlock(&block->lock);
return ((char*)block) + sizeof(size_t);
}
head = &(block->next);
block = block->next;
}
block = (free_block*)sbrk(size);
block->size = size;
pthread_mutex_unlock(&block->lock);
return ((char*)block) + sizeof(size_t);
}
unsigned int myfree(void* ptr) {
free_block* block = (free_block*)(((char*)ptr) - sizeof(size_t));
pthread_mutex_lock(&block->lock);
block->next = free_block_list_head.next;
free_block_list_head.next = block;
pthread_mutex_unlock(&block->lock);
}
I'm only able to allocated memory to the first block, then a segmentation fault error. I don't know where my error is and I'm very new to threads and locks, so any sort of help would be great! Thanks.

In this line:
pthread_mutex_lock(&block->lock);
you haven't checked yet whether block is NULL. You would need to do the locking inside the loop.
Easier still, why not have just one mutex for your whole malloc - make it a static next to free_block_list_head then you can just lock it at the start of your function and unlock it after.
If you do stick with a per block mutex, remember to add space for the mutex to your calculations. You also need to make sure the pointer you pass back is pointing to memeory after your mutex in the data structure.
Edit: Also note: You also haven't called free_block_init anywhere.

Related

Why does this code segfault on one machine but run fine on another?

This code segfaults on line 97 (according to gdb) on one machine (Linode) yet runs just fine on a different machine (personal) and I haven't really been able to figure out why. I tried ensuring that the heap was extended properly via sbrk but that still didn't seem to fix the issue. If anyone wouldn't mind explaining what I did wrong, I'd really appreciate it.
`
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#include <stdio.h>
#include <math.h>
typedef struct block // This is a node in a linked list representing various sections of memory
{
int size; // size of the block of allocated memory
int free; // whether the block is free and can be reallocated
struct block* next; // pointer to the next block in the linked list
char end[1]; // end represents the end of the header block struct
} block_t;
#define STRUCT_SIZE sizeof(block_t)
// --- Global variables
block_t* head = NULL; // Pointer to head of the linked list
block_t* lastVisited = NULL; // Pointer to the last visited node
void* brkPoint = NULL; // This is a pointer to the empty space on heap
// findBlock: Iterates through all blocks of memory until it is able to return a block able to contain a node of size size.
// headptr: Head of the linked list of blocks
// size: Size of the memory section being claimed
block_t* findBlock(block_t* headptr, unsigned int size) {
block_t* ptr = headptr;
while (ptr != NULL) {
if (ptr->size >= (size + STRUCT_SIZE) && ptr->free == 1) {
return ptr;
}
lastVisited = ptr;
ptr = ptr->next;
}
return ptr;
}
// splitBlock: Given a block ptr, split it into two blocks of size of size and ptr->size - size
// ptr: Pointer to the block being split
// size: Size of the first one of the two blocks
void splitBlock(block_t* ptr, unsigned int size) {
block_t* newBlock;
newBlock = ptr->end + size;
newBlock->size = ptr->size - size - STRUCT_SIZE;
newBlock->free = 1;
newBlock->next = ptr->next;
ptr->size = size;
ptr->free = 0;
ptr->next = newBlock;
}
// Increase amount of memory the program uses from the heap
// lastVisitedPtr: Pointer to the beginning of free heap (end of the program heap)
// size: The amount that you want to increase
block_t* increaseAllocation(block_t* lastVisitedPtr, unsigned int size) {
brkPoint = sbrk(0);
block_t* curBreak = brkPoint; //Current breakpoint of the heap
if (sbrk(size + STRUCT_SIZE) == (void*)-1) {
return NULL;
}
curBreak->size = (size + STRUCT_SIZE) - STRUCT_SIZE;
curBreak->free = 0;
curBreak->next = NULL;
lastVisitedPtr->next = curBreak;
if (curBreak->size > size)
splitBlock(curBreak, size);
return curBreak;
}
// malloc: A custom implementation of malloc, behaves exactly as expected
// _size: the amount of memory to be allocated into a block
// returns void*, a pointer to the block
void* mymalloc(size_t _size) {
void* brkPoint1; // New heap breakpoint
unsigned int size = _size;
int memoryNeed = size + STRUCT_SIZE; // Total size needed, including metadata
block_t* ptr; // ptr to new block
brkPoint = sbrk(0); // Set breakpoint to heap
if (head == NULL) { // If being run for the first time
if (sbrk(memoryNeed) == (void*)-1) { // If you cannot allocate enough memory, return null
return NULL;
}
brkPoint1 = sbrk(0); // Set new breakpoint to heap
head = brkPoint; // Head is at heap
head->size = memoryNeed - STRUCT_SIZE;
head->free = 0; // Head is no longer free
head->next = NULL; // No next
ptr = head; // Return pointer is head
printf("Malloc %zu bytes\n", size);
return ptr->end; // Return end of the metadata pointer (AKA beginning of allocated memory)
}
else { // Head exists
block_t* freeBlock = NULL;
freeBlock = findBlock(head, size); // Find a block that can fit size
if (freeBlock == NULL) {
freeBlock = increaseAllocation(lastVisited, size); // Increase heap and create new block
if (freeBlock == NULL) {
return NULL;
}
printf("Malloc %zu bytes\n", size);
return freeBlock->end;
}
else { // Free block with size > _size exists, claim it
if (freeBlock->size > size) { // If block's size is > size, split it down to size
splitBlock(freeBlock, size);
}
}
printf("Malloc %zu bytes\n", size);
return freeBlock->end;
}
}
// myfree: Sets block referenced by pointer to be free and merges consecutive blocks
void myfree(void* ptr) {
block_t* toFree;
toFree = ptr - STRUCT_SIZE;
if (toFree >= head && toFree <= brkPoint) {
toFree->free = 1;
printf("Freed %zu bytes\n", toFree->size);
}
}
#define ARRAY_ELEMENTS 1024
int main() {
// Allocate some data
int *data = (int *) mymalloc(ARRAY_ELEMENTS * sizeof(int));
// Do something with the data
int i = 0;
for (i = 0; i < ARRAY_ELEMENTS; i++) {
data[i] = i;
}
// Free the data
myfree(data);
return 0;
}
`
As mentioned above, I tried debugging with gdb and expanding the heap with sbrk, but that didn't fix the issue. I have no idea why it would run fine on my personal machine but not on a machine hosted elsewhere. Thanks a lot for checking this out
There is a ton of warnings which you should fix.
This one in particular is likely to cause crashes:
t.c:61:16: warning: implicit declaration of function ‘sbrk’.
Why is this likely to cause a crash?
Without a prototype, the C compiler is required (by the standard) to assume that the function returns an int.
On 32-bit platforms, this typically doesn't cause a problem because sizeof(int) == sizeof(void*) == 4.
But on 64-bit platforms sizeof(int) == 4 and sizeof(void*) == 8. Thus assigning void *p = sbrk(0); without a prototype may result in the pointer having only the low 4 bytes of the returned address; and that is likely to produce a crash when that pointer is dereferenced.
When I add missing #include <unistd.h> (where the prototype for sbrk is), the crash goes away.
In general you should always compile with -Wall -Wextra and fix resulting warnings. The compiler will often tell you about bugs, and save you a lot of debugging time.

Why this Lua program that limits memory usage crashes?

I'm working on Exercise 27.4 from the 4th edition of Programming in Lua. I am using Lua 5.4.4, and my solution is the following.
/*
Exercise 27.4: Write a library that allows a script to limit the total amount of memory used
by its Lua state. It may offer a single function, `setlimit`, to set that limit.
The library should set its own allocation function. This function, before calling the
original allocator, checks the total memory in use and returns NULL if the requested memory
exceeds the limit.
(Hint: the library can use the user data of the allocation function to keep its state:
the byte count, the current memory limit, etc.; remember to use the original user data
when calling the original allocation function.)
*/
#include "lauxlib.h"
#include <stdlib.h>
typedef struct {
void *o_ud;
lua_Alloc o_alloc;
size_t mem;
size_t limit;
} memlimit_ud;
static void *memlimit_alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
memlimit_ud *m_ud = ud;
size_t mem = m_ud->mem;
if (mem + nsize - osize > m_ud->limit) {
return NULL;
}
void *res = m_ud->o_alloc(m_ud->o_ud, ptr, osize, nsize);
if (res) m_ud->mem += nsize - osize;
return res;
}
static int l_setlimit(lua_State *L) {
int n = luaL_checkinteger(L, 1) * 1024;
memlimit_ud *ud;
lua_getallocf(L, (void **) &ud);
ud->limit = n;
return 0;
}
static const struct luaL_Reg memlimit[] = {
{"setlimit", l_setlimit},
{ NULL, NULL},
};
int luaopen_memlimit(lua_State *L) {
memlimit_ud *ud = lua_newuserdata(L, sizeof(memlimit_ud));
luaL_ref(L, LUA_REGISTRYINDEX);
ud->o_alloc = lua_getallocf(L, &ud->o_ud);
ud->mem = 0;
ud->limit = -1;
lua_setallocf(L, memlimit_alloc, ud);
luaL_newlib(L, memlimit);
return 1;
}
However, it throws a segment fault when the script ends. I found this question, and have tried to change lua_newuserdata to malloc, but it still doesn't work. While debugging, I noticed that it was trying to call memlimit_alloc before it crashed, but the function seemed like didn't exist (the former calls to this function were successful).
How can I fix this?

how to use a static struc into a static function ? ( like a global )

for the need of my project i need to handle a global (representing the heap ). It's a C project, i don't have any errors at the compilation.
but when i try to use a member of struct -> segfault.
if someone could tell me where is the point ?
thanks
static t_meta *init_get_meta()
{
static t_meta *allineed = NULL;
int i;
i = 0;
if (allineed == NULL)
{
//allineed->pagesize = getpagesize();
//allineed->pagesize = 4096;
allineed->pagesize = 0; --> segfault right here
printf("LOVE\n");
while (i < 8)
{
allineed->listfree[i++] = NULL;
}
allineed->last = extend_heap(allineed);
}
return (allineed);
}
You are de-referencing a NULL pointer.
Here in this line of code you check for NULL and go ahead and access that memory which is illegal.
if (allineed == NULL)
allineed->pagesize = 0; // incorrect at this time allineed is pointing to 0x0
What you need to do is malloc the structure and than check if malloc returned with not a NULL value. something on the lines of
static t_meta *allineed = malloc(sizeof(t_meta));
if (allineed)
{
//do something
}
else
//return error
You might want to look at these questions if you are trying to implement a basic malloc yourself
How do malloc() and free() work?
How is malloc() implemented internally?
A very basic malloc would do these basic steps
void * my_malloc(size_t size)
{
size_t headersize = 1; // 1 byte header
uint8_t alignment = 8; // 8 byte alignment
// the block should be 8 bytes align
size_t alloc_size = ((size+1)+(alignment-1))&~(alignment-1);
//use system call
void *head = sbrk(alloc_size );
if(head == (void *)(-1))
return NULL;
//update the header here to mark the size and other bits depending upon req
char *header_val = (char *)head;
*header_val = (alloc_size/2) | ( 1 << 7);//only support power 2 sizes
//return updated pointer location to point to ahead of header
// after changing the pointer to char type as pointer arithmetic is not allowed on void pointers
//printf("allocated size is %d with first byte %p\n",alloc_size,header_val);
//printf(" %02x\n",(unsigned char)*(char *)header_val);
return (char *)head + headersize;
}

C - (C99) , how to create a stack struct, without using stdlib.h (without malloc) [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have a homework for tomorrow, and am asked to make a dynamic (resizable) stack, that saves chars.
This thing have been driving me crazy, been on it all day. I did it using the stdlib and it was done. But can't seem to figure out how to allocate memory without malloc.. help would be really appreciated. These are some code snippets that I have used (with stdlib):
struct STACK
{
int size;
int capacity;
char *memory;
int folder_number;
};
typedef struct STACK stack;
My main starts like this:
int main()
{
stack mystack;
stack_init(&mystack);
Initializing the stack function:
void stack_init(stack *s)
{
s->size=1;
s->capacity=INITIAL_CAPACITY;
s->memory=malloc(s->capacity);
s->memory[0]='\0';
s->folder_number=1;
}
I have all kind of functions for my program, and when I insert new char into the stack, I check if I have reached the max capacity, if so , I call the following func:
void double_memory(stack* s)
{
char *tmp = malloc((s->capacity)*2);
for (int i=0; i<(s->capacity); i++)
tmp[i]=s->memory[i];
free(s->memory);
s->capacity *= 2;
s->memory=tmp;
}
Now, I have been trying for at least 6 hours in a row, to try and figure out how to do it otherwise (without using stdlib.h), searched a lot on google, with no success. any help or advice would be really!! appreciated.
Thank you very much in advance.
EDIT: I have started at university around 2 months ago, I don't know about platforms..etc, the last 2 things we learned were pointers, and small information about malloc, b4 that we simply learned about functions hhh..., and before that, VERRY basic coding..
Use a file:
#include <stdio.h>
struct stack {
FILE * fp;
} stack = {NULL} ;
#define ZENAME "zestack"
void stack_init (struct stack *sp);
void stack_exit (struct stack *sp);
void stack_push (struct stack *sp, int ch);
int stack_pop (struct stack *sp);
void stack_init (struct stack *sp)
{
if (sp->fp) fclose(sp->fp);
sp->fp = fopen(ZENAME , "wb+" );
if (!sp->fp) fprintf(stderr, "Fopen(%s) failed\n", ZENAME );
}
void stack_exit (struct stack *sp)
{
if (sp->fp) fclose(sp->fp);
sp->fp = NULL;
}
void stack_push (struct stack *sp, int ch)
{
fputc(ch, sp->fp);
}
int stack_pop (struct stack *sp)
{
int ch;
long int oldpos, newpos;
if (!sp->fp) return -1;
oldpos = fseek(sp->fp, -1, SEEK_CUR);
if (oldpos < 0) { stack_exit (sp); return EOF; }
ch = fgetc(sp->fp);
newpos = fseek(sp->fp, -1, SEEK_CUR);
fprintf(stderr, "Oldpos = %ld Newpos = %ld\n", oldpos, newpos );
return ch;
}
int main(void)
{
int ch;
stack_init ( & stack);
stack_push ( & stack, '1');
stack_push ( & stack, '2');
stack_push ( & stack, '3');
stack_push ( & stack, '4');
while(1) {
ch = stack_pop( &stack);
fprintf(stdout, "Pop = '%c' (0x%x)\n" , ch, (unsigned) ch) ;
if (ch < 0) break;
}
return 0;
}
malloc on most POSIX-compliant platforms simply uses mmap with anonymous mapping under the hood ... so you could call that function instead using the MAP_ANONYMOUS flag to allocate memory into a memory pool for use by your stack implementation. Here is a link to the LINUX man-page for mmap: http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html
For efficient use of your allocated memory pool, I would suggest setting up some type of simple linked-list memory manager ... in other words you want to call mmap once to allocate a large chunk of memory, and then use your own user-defined malloc and free calls to manage the memory pool.
UPDATE: From your comments you're now saying that you can't use any external libraries. Therefore your only other option is to designate a static array for your memory pool since allocating memory dynamically from the heap at runtime requires intervention from the OS, and that can't be done without a system call.
Here is a simple linked-list memory manager system you could use (note: I haven't debugged it, but since it's homework, that's your job :-)
static unsigned char heap[MEMORY_POOL_SIZE];
typedef struct memory_block
{
unsigned long size_bytes;
unsigned char block[];
} memory_block;
typedef struct free_block
{
unsigned long size_bytes;
struct free_block* next;
} free_block;
//initialize our memory pool free-store
static char free_list_initialized = 0;
static free_block* free_list_head = NULL;
void* malloc(unsigned long size_bytes)
{
//initialize the free-store if it's never been used before
if (!free_list_initialized)
{
free_list_head = (free_block*)&heap[0];
free_list_head->size_bytes = MEMORY_POOL_SIZE - sizeof(memory_block);
free_list_head->next = NULL;
free_list_initialized = 1;
}
//search the free-list for a memory block that is at least size_bytes
free_block* current = free_list_head;
free_block* prev = NULL;
while (current != NULL)
{
if (current->size_bytes >= (size_bytes + sizeof(free_block)))
break;
prev = current;
current = current->next;
}
//did we reach the end of the list without finding anything?
if (current == NULL)
return NULL; //out-of-memory!
memory_block* temp = NULL;
//trim the block of memory if the one we found is larger than the requested size
if (current->size_bytes > (size_bytes + sizeof(free_block)))
{
temp = (memory_block*)current;
current = (free_block*)((unsigned char*)current + size_bytes + sizeof(memory_block));
current->size_bytes = current->size_bytes - (size_bytes + sizeof(memory_block));
temp->size_bytes = size_bytes;
if (prev != NULL)
prev->next = current;
}
else
{
prev->next = current->next;
temp = (memory_block*)current;
}
return (void*)&temp->block;
}
void free(void* ptr)
{
free_block* temp = (free_block*)((unsigned char*)ptr - sizeof(unsigned long));
temp->next = free_list_head;
free_list_head = temp;
return;
}

malloc implementation?

I'm trying to implement malloc and free for C, and I am not sure how to reuse memory. I currently have a struct that looks like this:
typedef struct _mem_dictionary {
void *addr;
size_t size;
int freed;
} mem_dictionary;
My malloc looks like this:
void *malloc(size_t size) {
void *return_ptr = sbrk(size);
if (dictionary == NULL)
dictionary = sbrk(1024 * sizeof(mem_dictionary));
dictionary[dictionary_ct].addr = return_ptr;
dictionary[dictionary_ct].size = size;
dictionary[dictionary_ct].freed = 1;
dictionary_ct++;
return return_ptr;
}
When I free memory, I would just mark the address as 0 (that would indicate that it is free). In my malloc, I would then use a for loop to look for any value in the array to equal 0 and then allocate memory to that address. I'm kind of confused how to implement this.
The easiest way to do it is to keep a linked list of free block. In malloc, if the list is not empty, you search for a block large enough to satisfy the request and return it. If the list is empty or if no such block can be found, you call sbrk to allocate some memory from the operating system. in free, you simply add the memory chunk to the list of free block. As bonus, you can try to merge contiguous freed block, and you can change the policy for choosing the block to return (first fit, best fit, ...). You can also choose to split the block if it is larger than the request.
Some sample implementation (it is not tested, and is obviously not thread-safe, use at your own risk):
typedef struct free_block {
size_t size;
struct free_block* next;
} free_block;
static free_block free_block_list_head = { 0, 0 };
static const size_t overhead = sizeof(size_t);
static const size_t align_to = 16;
void* malloc(size_t size) {
size = (size + sizeof(size_t) + (align_to - 1)) & ~ (align_to - 1);
free_block* block = free_block_list_head.next;
free_block** head = &(free_block_list_head.next);
while (block != 0) {
if (block->size >= size) {
*head = block->next;
return ((char*)block) + sizeof(size_t);
}
head = &(block->next);
block = block->next;
}
block = (free_block*)sbrk(size);
block->size = size;
return ((char*)block) + sizeof(size_t);
}
void free(void* ptr) {
free_block* block = (free_block*)(((char*)ptr) - sizeof(size_t));
block->next = free_block_list_head.next;
free_block_list_head.next = block;
}
Note: (n + align_to - 1) & ~ (align_to - 1) is a trick to round n to the nearest multiple of align_to that is larger than n. This only works when align_to is a power of two and depends on the binary representation of numbers.
When align_to is a power of two, it only has one bit set, and thus align_to - 1 has all the lowest bit sets (ie. align_to is of the form 000...010...0, and align_to - 1 is of the form 000...001...1). This means that ~ (align_to - 1) has all the high bit set, and the low bit unset (ie. it is of the form 111...110...0). So x & ~ (align_to - 1) will set to zero all the low bits of x and round it down to the nearest multiple of align_to.
Finally, adding align_to - 1 to size ensure that we round-up to the nearest multiple of align_to (unless size is already a multiple of align_to in which case we want to get size).
You don't want to set the size field of the dictionary entry to zero -- you will need that information for re-use. Instead, set freed=1 only when the block is freed.
You cannot coalesce adjacent blocks because there may have been intervening calls to sbrk(), so that makes this easier. You just need a for loop which searches for a large enough freed block:
typedef struct _mem_dictionary
{
void *addr;
size_t size;
int freed;
} mem_dictionary;
void *malloc(size_t size)
{
void *return_ptr = NULL;
int i;
if (dictionary == NULL) {
dictionary = sbrk(1024 * sizeof(mem_dictionary));
memset(dictionary, 0, 1024 * sizeof(mem_dictionary));
}
for (i = 0; i < dictionary_ct; i++)
if (dictionary[i].size >= size
&& dictionary[i].freed)
{
dictionary[i].freed = 0;
return dictionary[i].addr;
}
return_ptr = sbrk(size);
dictionary[dictionary_ct].addr = return_ptr;
dictionary[dictionary_ct].size = size;
dictionary[dictionary_ct].freed = 0;
dictionary_ct++;
return return_ptr;
}
void free(void *ptr)
{
int i;
if (!dictionary)
return;
for (i = 0; i < dictionary_ct; i++ )
{
if (dictionary[i].addr == ptr)
{
dictionary[i].freed = 1;
return;
}
}
}
This is not a great malloc() implementation. In fact, most malloc/free implementations will allocate a small header for each block returned by malloc. The header might start at the address eight (8) bytes less than the returned pointer, for example. In those bytes you can store a pointer to the mem_dictionary entry owning the block. This avoids the O(N) operation in free. You can avoid the O(N) in malloc() by implementing a priority queue of freed blocks. Consider using a binomial heap, with block size as the index.
I am borrowing code from Sylvain's response. He seems to have missed calculating the size of the free_block* ini calculating the overhead.
In overall the code works by prepending this free_block as a header to the allocated memory.
1. When user calls malloc, malloc returns the address of the payload, right after this header.
2. when free is called, the address of the starting of the header for the block is calculated (by subtracting the header size from the block address) and that is added to the free block pool.
typedef struct free_block {
size_t size;
struct free_block* next;
} free_block;
static free_block free_block_list_head = { 0, 0 };
// static const size_t overhead = sizeof(size_t);
static const size_t align_to = 16;
void* malloc(size_t size) {
size = (size + sizeof(free_block) + (align_to - 1)) & ~ (align_to - 1);
free_block* block = free_block_list_head.next;
free_block** head = &(free_block_list_head.next);
while (block != 0) {
if (block->size >= size) {
*head = block->next;
return ((char*)block) + sizeof(free_block);
}
head = &(block->next);
block = block->next;
}
block = (free_block*)sbrk(size);
block->size = size;
return ((char*)block) + sizeof(free_block);
}
void free(void* ptr) {
free_block* block = (free_block*)(((char*)ptr) - sizeof(free_block ));
block->next = free_block_list_head.next;
free_block_list_head.next = block;
}

Resources