Segmentation Fault When Trying to Change Values at Memory Address [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have spotted down an error of seg fault, which occurred to be in my divideBlock() function. When I dereferenced newBlock to access info, i.e. without assigning value to it but just dereferencing it, it was alright, but when I change its value, I received a set fault. Any idea why this would happen? Could it be because of the address manipulation and non-standard pointer access? If so, what should I do if I want to break one block into two?
typedef struct freeBlock
{
size_t info;
struct freeBlock *next;
} freeBlock;
freeBlock *divideBlock(freeBlock *block, size_t reqSize)
{
// Declaration of variables.
freeBlock *newBlock;
size_t blockSize;
blockSize = block->info >> 1;
newBlock = block + reqSize;
newBlock->info = (blockSize - reqSize) << 1; // new block marked as unused. seg fault happens here!!!
block->info = (reqSize << 1) | 1; // old block marked as used.
return newBlock;
}
void *malloc(size_t size)
{
if (size == 0)
return NULL;
// Declaration of variables.
size_t blockSize, occpd, poccpd, reqSize;
freeBlock *curr, *prev, *newBlock, *allocd, *combined;
printf("%d", __LINE__);
reqSize = (size + sizeof(size_t) + sizeof(char*) + padding + (align - 1)) & ~ (align - 1);
printf("%d", __LINE__);
curr = head;
prev = NULL;
while (curr != NULL)
{
printf("%d", __LINE__);
occpd = curr->info & 1;
if (prev != NULL)
{
printf("%d", __LINE__);
poccpd = prev->info & 1;
if (!poccpd && !occpd)
{
combined = combineBlock(prev, curr);
if (combined)
curr = combined;
}
}
blockSize = curr->info >> 1;
printf("%d", __LINE__);
if (blockSize >= reqSize && !occpd)
{
if (blockSize >= 2 * reqSize)
{
newBlock = divideBlock(curr, reqSize);
if (newBlock != NULL)
{
newBlock->next = curr->next;
curr->next = newBlock;
}
}
curr->info |= 1;
return curr + sizeof(char*) + sizeof(size_t);
}
prev = curr;
curr = curr->next;
}
printf("%d", __LINE__);
allocd = sbrk(reqSize * 3);
if (allocd == (void*)-1)
return NULL;
allocd->info = ((reqSize * 3) << 1) | 1;
newBlock = divideBlock(allocd, reqSize);
newBlock->next = NULL;
allocd->next = newBlock;
if (head == NULL)
head = allocd;
else
curr = allocd;
return allocd + sizeof(char *) + sizeof(size_t);
}

The problem seems to be the line:
newBlock = block + reqSize;
newBlock will point to a location (address) which is "location-of-block + reqSize*sizeof(freeBlock)"
Probably the intention is simply that newBlock shall point to the location reqSize bytes after block.
To increment a pointer by 1 you can cast it to char* before adding reqSize.
Maybe something like this for the divide:
freeBlock *divideBlock(freeBlock *block, size_t reqSize)
{
// Declaration of variables.
freeBlock *newBlock;
size_t blockSize;
blockSize = block->info >> 1;
newBlock = (freeBlock*)(((char*)block) + reqSize);
newBlock->info = (blockSize - reqSize) << 1;
block->info = (reqSize << 1) | 1; // old block marked as used.
return newBlock;
}
but you also have problems in malloc function where you add numbers to pointers of freeBlock type. Probably not what you want.
BTW:
Why do you use
sizeof(char *) + sizeof(size_t)
Shouldn't that be
sizeof(freeBlock)

Related

Buddy allocator, blocks of memory and FreeRTOS

I am trying to implement buddy allocator in C for FreeRTOS.
I made a function buddy_free for memory management.
I am using struct _buddy_block and function for allocation and memory management, but things don't go well and I need your help.
Here's my sources and problems below:
typedef struct _buddy_block {
struct _buddy_block *next;
size_t size;
bool is_free;
} buddy_block_t;
typedef struct {
buddy_block_t *freelist;
size_t total_size;
size_t min_block_size;
} buddy_allocator_t;
Allocation:
void *buddy_alloc(buddy_allocator_t *allocator, size_t size) {
// Find the first free block that is large enough to satisfy the request
buddy_block_t *block = allocator->freelist;
while (block != NULL && (block->size < size || !block->is_free)) {
block = block->next;
}
// If no suitable block was found, return NULL
if (block == NULL) {
return NULL;
}
// Split the block into two blocks if the block is larger than needed
if (block->size > size) {
// Create a new block for the remainder
buddy_block_t *remainder = (buddy_block_t *) ((uint8_t *) block + size);
remainder->size = block->size - size;
remainder->is_free = true;
remainder->next = block->next;
// Update the current block
block->size = size;
block->next = remainder;
}
// Mark the block as allocated and return a pointer to the memory
block->is_free = false;
return (void *) (block + 1);
}
void buddy_free(buddy_allocator_t *allocator, void *ptr) {
// Get a pointer to the block header
buddy_block_t *block = (buddy_block_t *) ptr - 1;
if (block->is_free) {
return;
}
// Mark the block as free
block->is_free = true;
// Try to merge the block with its buddy (if it has one and the buddy is free)
size_t block_size = block->size;
buddy_block_t *buddy = (buddy_block_t *) ((uint8_t *) block + block_size);
// Check if the buddy block is within the memory region managed by the allocator
if (block < allocator->freelist ||
block > (buddy_block_t *) ((uint8_t *) allocator->freelist + allocator->total_size) ||
buddy < allocator->freelist ||
buddy > (buddy_block_t *) ((uint8_t *) allocator->freelist + allocator->total_size)) {
// One of the blocks is outside of the memory region managed by the allocator, so they cannot be merged
return;
}
// Check if the buddy block is free and has the same size as the current block
if (buddy->is_free && buddy->size == block_size) {
// The buddy is free and has the same size as the current block, so they can be merged
if (buddy < block) {
// The buddy comes before the current block in memory, so it should be the new block
buddy->size *= 2;
buddy->next = block->next;
block = buddy;
} else {
// The current block comes before the buddy in memory, so it should be the new block
block->size *= 2;
block->next = buddy->next;
}
}
// Insert the merged block back into the free list
buddy_block_t *prev = NULL;
buddy_block_t *curr = allocator->freelist;
while (curr != NULL && curr < block) {
prev = curr;
curr = curr->next;
}
block->next = curr;
if (prev == NULL) {
allocator->freelist = block;
} else {
prev->next = block;
}
}
First problem is that in the line:
while (block != NULL && (block->size < size || !block->is_free))
I get Segmentation fault with test_buddy_alloc_insufficient_memory test:
// Test the behavior of the buddy_alloc function when it is unable to fulfill an allocation request due to insufficient free memory
void test_buddy_alloc_insufficient_memory() {
// Allocate all of the available memory
buddy_allocator_t allocator;
void *ptr = buddy_alloc(&allocator, allocator.total_size);
assert(ptr != NULL);
// Attempt to allocate more memory
ptr = buddy_alloc(&allocator, 1);
assert(ptr == NULL);
}
// Test the behavior of the buddy_alloc function when it is called with a size of 0
void test_buddy_alloc_size_zero() {
buddy_allocator_t allocator;
// Attempt to allocate a block of size 0
void *ptr = buddy_alloc(&allocator, 0);
assert(ptr == NULL);
}
Can someone help me to fix or improve my code?
You have UB (undefined behavior).
In your test_* functions, you have:
buddy_allocator_t allocator;
This is on the stack and is uninitialized.
You need:
buddy_allocator_t allocator = { 0 };
With -Wall, the compiler flags:
orig.c: In function ‘test_buddy_alloc_insufficient_memory’:
orig.c:114:14: warning: ‘allocator.total_size’ is used uninitialized in this function [-Wuninitialized]
void *ptr = buddy_alloc(&allocator, allocator.total_size);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Also, in buddy_alloc, the first thing it does is:
buddy_block_t *block = allocator->freelist;
while (block != NULL && (block->size < size || !block->is_free))
The block != NULL is insufficient. It does not guard against dereferencing a non-null but random/invalid pointer value.
UPDATE:
From the discussion and further review, I didn't see any code to set up the allocator struct with a valid block. So, the allocator started without any memory.
Normally, we'd call brk/sbrk to get more memory from the system, but, for testing, we can use a static/persistent fixed array.
Here is the restructured code:
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
typedef struct _buddy_block {
struct _buddy_block *next;
size_t size;
bool is_free;
} buddy_block_t;
typedef struct {
buddy_block_t *freelist;
size_t total_size;
size_t min_block_size;
} buddy_allocator_t;
void *
buddy_alloc(buddy_allocator_t * allocator, size_t size)
{
// Find the first free block that is large enough to satisfy the request
buddy_block_t *block = allocator->freelist;
while (block != NULL && (block->size < size || !block->is_free)) {
block = block->next;
}
// If no suitable block was found, return NULL
if (block == NULL) {
return NULL;
}
// Split the block into two blocks if the block is larger than needed
if (block->size > size) {
// Create a new block for the remainder
buddy_block_t *remainder = (buddy_block_t *) ((uint8_t *) block + size);
remainder->size = block->size - size;
remainder->is_free = true;
remainder->next = block->next;
// Update the current block
block->size = size;
block->next = remainder;
}
// Mark the block as allocated and return a pointer to the memory
block->is_free = false;
return (void *) (block + 1);
}
void
buddy_free(buddy_allocator_t * allocator, void *ptr)
{
// Get a pointer to the block header
buddy_block_t *block = (buddy_block_t *) ptr - 1;
if (block->is_free) {
return;
}
// Mark the block as free
block->is_free = true;
// Try to merge the block with its buddy (if it has one and the buddy is free)
size_t block_size = block->size;
buddy_block_t *buddy = (buddy_block_t *) ((uint8_t *) block + block_size);
// Check if the buddy block is within the memory region managed by the allocator
if (block < allocator->freelist || block > (buddy_block_t *) ((uint8_t *) allocator->freelist + allocator->total_size) || buddy < allocator->freelist || buddy > (buddy_block_t *) ((uint8_t *) allocator->freelist + allocator->total_size)) {
// One of the blocks is outside of the memory region managed by the allocator, so they cannot be merged
return;
}
// Check if the buddy block is free and has the same size as the current block
if (buddy->is_free && buddy->size == block_size) {
// The buddy is free and has the same size as the current block, so they can be merged
if (buddy < block) {
// The buddy comes before the current block in memory, so it should be the new block
buddy->size *= 2;
buddy->next = block->next;
block = buddy;
}
else {
// The current block comes before the buddy in memory, so it should be the new block
block->size *= 2;
block->next = buddy->next;
}
}
// Insert the merged block back into the free list
buddy_block_t *prev = NULL;
buddy_block_t *curr = allocator->freelist;
while (curr != NULL && curr < block) {
prev = curr;
curr = curr->next;
}
block->next = curr;
if (prev == NULL) {
allocator->freelist = block;
}
else {
prev->next = block;
}
}
void
initme(buddy_allocator_t *ctl)
{
#if 0
static buddy_block_t block;
static char mem[1024 * 1024];
memset(&block,0,sizeof(block));
block.size = sizeof(mem);
block.is_free = 1;
ctl->total_size = block.size;
ctl->freelist = &block;
ctl->min_block_size = 128;
#else
static char mem[1024 * 1024];
buddy_block_t *block = (void *) mem;
memset(block,0,sizeof(*block));
block->size = sizeof(mem) - sizeof(*block);
block->is_free = 1;
ctl->total_size = block->size;
ctl->freelist = block;
ctl->min_block_size = 128;
#endif
}
// Test the behavior of the buddy_alloc function when it is unable to fulfill an allocation request due to insufficient free memory
void
test_buddy_alloc_insufficient_memory()
{
// Allocate all of the available memory
buddy_allocator_t allocator = { 0 };
initme(&allocator);
void *ptr = buddy_alloc(&allocator, allocator.total_size);
assert(ptr != NULL);
// Attempt to allocate more memory
ptr = buddy_alloc(&allocator, 1);
assert(ptr == NULL);
}
// Test the behavior of the buddy_alloc function when it is called with a size of 0
void
test_buddy_alloc_size_zero()
{
buddy_allocator_t allocator = { 0 };
initme(&allocator);
// Attempt to allocate a block of size 0
void *ptr = buddy_alloc(&allocator, 0);
assert(ptr == NULL);
}
int
main(void)
{
test_buddy_alloc_insufficient_memory();
test_buddy_alloc_size_zero();
return 0;
}

Allocator failing with higher numbers

I have school project to create memory allocator. I´ve been debugging it over 3 days now with no reasonable outcome. It is suddenly failing when higher number is ment to be allocated for example i have an array of 65000Bytes and I want to allocate 12000, it fails. Lower numbers up to 800 work great tho.
Let´s say we have static array consisting of 65000Bytes.
We call init, which creates linked list which has pointer to next list and size of list. We also are allowed to have one global variable for pointer to start of array I named mine "start".
Looks like this:
typedef struct mallocstr head;
char* start;
struct mallocstr
{
head* next; //For moving through list
int size; //If allocated then value is <0
};
And here is my allocator function:
void* memory_alloc(unsigned int size)
{
head* p = start;
char* endd= end();
while (p != NULL)
{
if (p->size > 0 && p->size >= size + sizeof(p) && size != 0)
{
int newsize = p->size - size - sizeof(p);
//If head is smaller than newsize create next block and allocate this one
if (sizeof(p) < newsize)
{
hlavicka* var;
p->size = (p->size - newsize) * (-1);
int point = p->size;
point*= -1;
p->next= p + sizeof(p) + point;
var= p;
p = p->next;
p->size= newsize;
p->next = NULL;
return (void*)var + 2*(sizeof(int));
}
//If head is greater or same as newsize
else if (sizeof(p) >= newsize)
{
p->size= p->size* (-1);
p->next = NULL;
return (void*)p + 2*(sizeof(int));
}
}
//If we are unable to alocate this block because size is too small or it is allocated we move to
//next one
else if (p->size< size + sizeof(p) && p != endd|| p->size< 0)
{
p = p->next;
}
//When we cannot allocate any block
else if (p->size < size + sizeof(p) && p == endd|| size == 0)
{
return NULL;
}
}
}
Function end is for getting pointer to the end of list. Here it is:
void* end()
{
head* p = start;
while (p != NULL)
{
if (p->next== NULL)
{
break;
}
else
p = p->next;
}
return (void*)p;
}

Fibonacci Sequence using Linked List crashes after linked list is destroyed. How can I trace the error?

I'm working on a program that calculates any number in the Fibonacci Sequence without using the int data type since it would overflow. Instead I am using linked lists to hold the digits that represent each number. My current issue is with freeing memory allocated to linked lists that I no longer need. If I'm calculating F(10000), I'd like the thousands of previous lists to be freed. The program as is produces each value up to "F(7) = 13" before crashing and showing "exit status -1". I'd really just like to know what's causing this error and go from there. Any help is appreciated. Thank you and I apologize for the large amount of code.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int digit;
struct Node *next;
} Node;
typedef struct ListyInt
{
Node *head;
int length;
} ListyInt;
Node *create_node(unsigned int digit, ListyInt *listy);
Node *removeNode(Node *node, ListyInt *listy);
void listyPrintHelper(Node *current);
ListyInt *destroyListyInt(ListyInt *listy);
ListyInt *fib(unsigned int n);
void listyPrint(ListyInt *p)
{
if (p == NULL || p->head == NULL)
{
printf("(null pointer)\n");
return;
}
listyPrintHelper(p->head);
printf("\n");
}
void listyPrintHelper(Node *current)
{
if (current == NULL)
return;
listyPrintHelper(current->next);
printf("%d", current->digit);
}
int main()
{
int i;
ListyInt *p;
for (i = 0; i <= 1000; i++)
{
printf("F(%d) = ", i);
listyPrint(p = fib(i));
destroyListyInt(p);
}
return 0;
}
ListyInt *listyAdd(ListyInt *p, ListyInt *q)
{
ListyInt *listy = NULL;
Node *ptemp = NULL;
Node *qtemp = NULL;
Node *temp = NULL;
ListyInt *temp_list = NULL;
unsigned int x = 0;
unsigned int count = 0;
if (p == NULL || q == NULL)
{
return NULL;
}
listy = malloc(sizeof(ListyInt));
if (listy == NULL)
{
return NULL;
}
listy->length = 0;
if (q->length > p->length)
{
temp_list = q;
q = p;
p = temp_list;
}
while (count < p->length)
{
if (count == 0)
{
x = p->head->digit + q->head->digit;
ptemp = p->head->next;
qtemp = q->head->next;
listy->head = create_node(x, listy);
temp = listy->head;
temp->next = create_node(0, listy);
if (temp->digit > 9)
{
temp->digit = temp->digit - 10;
temp->next->digit = temp->next->digit + 1;
}
}
else
{
temp->next->next = create_node(0, listy);
if (qtemp == NULL)
{
temp->next->digit += ptemp->digit;
ptemp = ptemp->next;
temp = temp->next;
}
else
{
x = ptemp->digit + qtemp->digit;
temp->next->digit += x;
if (temp->next->digit > 9)
{
temp->next->digit = temp->next->digit - 10;
temp->next->next->digit = temp->next->next->digit + 1;
}
qtemp = qtemp->next;
ptemp = ptemp->next;
temp = temp->next;
}
}
if (count == p->length - 1 && temp->next->digit == 0)
{
temp->next = removeNode(temp->next, listy);
}
count++;
}
return listy;
}
ListyInt *destroyListyInt(ListyInt *listy)
{
if (listy == NULL)
{
return NULL;
}
Node *current = listy->head;
Node *temp;
while (current != NULL)
{
temp = current->next;
free(current);
current = temp;
}
free(listy);
return NULL;
}
ListyInt *fib(unsigned int n)
{
ListyInt *spiral = malloc(sizeof(ListyInt));
ListyInt *p = NULL;
ListyInt *q = NULL;
unsigned int count = 2;
if (spiral == NULL)
{
return NULL;
}
if (n == 0)
{
spiral->head = create_node(0, spiral);
return spiral;
}
if (n == 1)
{
spiral->head = create_node(1, spiral);
return spiral;
}
p = malloc(sizeof(ListyInt));
p->head = create_node(0, p);
q = malloc(sizeof(ListyInt));
q->head = create_node(1, q);
while (count <= n)
{
spiral = listyAdd(p, q);
destroyListyInt(p);
p = q;
q = spiral;
count++;
}
return spiral;
}
Node *create_node(unsigned int digit, ListyInt *listy)
{
if (listy == NULL)
{
return NULL;
}
Node *new_node = malloc(sizeof(Node));
new_node->digit = digit;
new_node->next = NULL;
listy->length++;
return new_node;
}
Node *removeNode(Node *node, ListyInt *listy)
{
if (node == NULL)
{
return NULL;
}
if (listy == NULL)
{
return NULL;
}
free(node);
node = NULL;
listy->length--;
return NULL;
}
I'd really just like to know what's causing this error and go from there.
Long story short, C's equivalent of a NullPointerException, as far as I can tell.
Long story longer, I haven't had time to fully examine your code or debug it, but I have had time to run it through gdb, which is included with most Linux installations. If you're using Visual Studio, I vaguely remember there being a debug mode, which should show you roughly the same information, just in a different place. This is GDB's output:
Starting program: /home/ubuntu/C/a.out
F(0) = 0
F(1) = 1
F(2) = 1
F(3) = 2
F(4) = 3
F(5) = 5
F(6) = 8
F(7) = 13
Program received signal SIGSEGV, Segmentation fault.
0x00000000004008db in listyAdd (p=0x6036a0, q=0x6036e0) at main.c:117
117 temp->next->digit += ptemp->digit;
(Okay, that's not all of it, but that's the relevant bit.)
What those last three lines mean is that you got a segfault. There are a bunch of things that can cause it, but based on that line, it looks like it's been caused by trying to dereference an invalid pointer. That's either a NULL pointer (a value of 0x0) or a pointer you've already freed.
If you're on Linux, you can then run Valgrind on it to figure out what, exactly, happened. It'll tell you if it's using a freed pointer or a NULL one, and that'll give you a good starting point to find the actual bug. You can also use your IDE's debugger (or GDB, if you want to try playing with the command-line version, but I wouldn't recommend it) to step through your program and see what the values of the variables involved are, which you can walk backwards from to see where they're being changed and invalidated.
If I had to guess, though, I'd say 0andriy's comments hit it on the nose -- you seem to be freeing things twice, and you probably meant to free them once, at the end.
I'm somewhat intentionally leaving this vague. Segfaults are common and (as you've noticed) difficult to debug, and you can only really learn how through experience. I think being shown the answer would honestly be less helpful than working through it yourself, and with tools like Valgrind and your debugger, that's not actually that hard, just tedious.
I found the issue. It was because the length of my linked lists weren't being reset when fib() was called. Thanks for your help everyone.

Memory Allocator implementation segfault

I am currently developing a memory allocator, I have come with this code a the moment but this code below segfault on almost every commands when i do a LD_PRELOAD of my implementation.
#include <pthread.h>
#include "malloc.h"
t_mem_map g_map;
int g_empty_map = TRUE;
static t_ctrl *get_free_block(size_t size)
{
t_ctrl *tmp;
tmp = g_map.head;
while (tmp != NULL)
{
if (tmp->is_free == TRUE && tmp->size < size)
{
tmp->is_free = FALSE;
return (tmp);
}
tmp = tmp->next;
}
return (NULL);
}
static void *init_map(size_t size)
{
t_ctrl *tmp;
g_map.map_size = DEFAULT_MAP_SIZE;
while (g_map.map_size < size + sizeof(t_ctrl))
g_map.map_size += DEFAULT_MAP_SIZE;
if ((g_map.head = (t_ctrl *)sbrk(g_map.map_size)) == (void *)-1)
return (NULL);
tmp = g_map.head;
tmp->next = NULL;
tmp->prev = NULL;
tmp->size = size;
tmp->is_free = FALSE;
g_map.free_space = g_map.map_size - size - sizeof(t_ctrl);
g_empty_map = FALSE;
unlock_thread();
return ((void *)((char *)tmp + sizeof(t_ctrl)));
}
static void *add_block(size_t size)
{
t_ctrl *tmp;
t_ctrl *new;
tmp = get_free_block(size);
if (tmp != NULL)
return ((void *)((char *)tmp + sizeof(t_ctrl)));
tmp = g_map.head;
while (tmp->next != NULL)
tmp = tmp->next;
new = (t_ctrl *)((char *)tmp + sizeof(t_ctrl) + tmp->size);
new->prev = tmp;
new->next = NULL;
tmp->next = new;
new->size = size;
new->is_free = FALSE;
g_map.free_space -= (new->size + sizeof(t_ctrl));
unlock_thread();
return ((void *)((char *)new + sizeof(t_ctrl)));
}
static void *resize_map(size_t size)
{
size_t size_shift;
size_shift = 0;
while (g_map.free_space < size + sizeof(t_ctrl))
{
g_map.map_size += DEFAULT_MAP_SIZE;
g_map.free_space += DEFAULT_MAP_SIZE;
size_shift += DEFAULT_MAP_SIZE;
}
if (sbrk(size_shift) == (void *)-1)
return (NULL);
return (add_block(size));
}
void *malloc(size_t size)
{
size_t a_size;
lock_thread();
a_size = ALIGN(size);
if (g_empty_map == TRUE)
return (init_map(a_size));
else
{
if ((a_size + sizeof(t_ctrl)) <= g_map.free_space)
return (add_block(a_size));
else
return (resize_map(a_size));
}
return (NULL);
}
Here is the malloc.h :
# include <stdio.h>
# include <stddef.h>
# include <unistd.h>
# define TRUE 0
# define FALSE 1
# define SUCCESS 0
# define FAILURE 1
# ifndef __X86_64__
# define ALIGNMENT (16)
# else
# define ALIGNMENT (8)
# endif
# define ALIGN(size) (((size) + (ALIGNMENT - 1)) &~ (ALIGNMENT - 1))
# define DEFAULT_MAP_SIZE (ALIGN(sysconf(_SC_PAGESIZE)))
typedef struct s_ctrl
{
size_t is_free;
size_t size;
struct s_ctrl *next;
struct s_ctrl *prev;
} t_ctrl;
typedef struct s_mem_map
{
size_t map_size;
size_t free_space;
// int free_blocks;
//int nb_blocks;
t_ctrl *head;
} t_mem_map;
With some research I found out that the segfault is likely coming from the while loop in the get_free_block() function but i can't understand why.
static t_ctrl *get_free_block(size_t size)
{
t_ctrl *tmp;
tmp = g_map.head;
while (tmp != NULL)
{
if (tmp->is_free == TRUE && tmp->size < size)
{
tmp->is_free = FALSE;
return (tmp);
}
tmp = tmp->next;
}
return (NULL);
}
Can't verify that this is the only problem, but you are checking tmp->size < size, when you probably should check tmp->size >= size instead.

Segmentation fault for a weird unknown reason

I get a segmentation fault (core dumped) in the following peace of code (I'm implementing malloc(), free() and realloc()):
void free(void* ptr)
{
void* curr = head;
void* before = NULL;
int isLegal = 0;
/*Line X*/printf("curr is %p and ptr is %p\n", curr, ptr);
if(curr == ptr)
{
printf("aaa");
}
else
{
printf("bbb");
}
/*Some more code that actually frees the pointer and not relevant here*/
}
Now, you'd assume that it'd print aaa or bbb, it just announces a segmentation fault right after performing the printf() in line X. If I type "printf("a")" instead of the current printf() it won't print 'a' at all. That is really weird.
It prints:
curr is 0x86be000 and ptr is 0x86be000
and yet it would just exit and throw a segmentation fault right after.
The variable head is a static variable in that file. I really want to know where the problem is, it's really weird. Here's the statement from the header file:
void free(void* ptr);
As simple as that, do you see any problem in here?
The full code is available here but I doubt it's related, the program should, at least, print either 'aaa' or 'bbb', and it doesn't do that.
Any idea? I'm really desperate.
Following code complied with warnings but did execute perfectly
#include <unistd.h>
typedef struct metadata_block* p_block;
typedef struct metadata_block
{
size_t size;
p_block next;
int free;
}metadata_block;
void* malloc(size_t size);
void free(void* ptr);
void* realloc(void* ptr, size_t size);
//THE MAIN CODE IS AT THE BOTTOM//
#include <stdio.h>
static p_block head = NULL;
void* malloc(size_t size)
{
void* ptr;
int isOk = 1;
int temp = 0;
p_block curr = head;
if(size <= 0)
{
return NULL;
}
if(curr)
{
while(curr->next && isOk)
{
if(curr->free && size <= curr->size)
{
isOk = 0;
}
if(isOk)
{
curr = curr->next;
}
}
if(isOk) //what will happen if there isn't one free and big enough
{
ptr = sbrk(size + sizeof(metadata_block));
if((int)ptr <= 0)
return NULL;
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL; //next run it's the real next.
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
else
{
if(curr->next)
{
ptr = curr;
if(curr->size == size || size > (curr->size - sizeof(metadata_block) - 1)) //not enough room for another block of memory
{
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
temp = curr->size;
((p_block)(ptr))->size = size;
((p_block)(ptr))->free = 0;
((p_block)(ptr + sizeof(metadata_block) + size))->next = curr->next;
((p_block)(ptr))->next = ptr + sizeof(metadata_block) + size;
((p_block)(ptr + sizeof(metadata_block) + size))->size = temp - size;
((p_block)(ptr + sizeof(metadata_block) + size))->free = 1;
return (ptr + sizeof(metadata_block));
}
else
{
ptr = curr;
if((int)sbrk(size - curr->size) > 0)
{
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL; //next run it's the real next.
((p_block)(ptr))->free = 0;
return (ptr + sizeof(metadata_block));
}
return NULL;
}
}
}
else
{
ptr = sbrk(size + sizeof(metadata_block));
if((int)ptr <= 0)
return NULL;
head = ptr;
((p_block)(ptr))->size = size;
((p_block)(ptr))->next = NULL;
((p_block)(ptr))->free = 0;
}
return ptr;
}
void free(void* ptr)
{
void* curr = head;
void* before = NULL;
int isLegal = 0;
printf("curr is %p and ptr is %p\n", curr, ptr);
if(curr == ptr)
{
printf("aaa\n");
}
else
{
printf("bbb\n");
}
if(curr && ptr)
{
while(curr && !isLegal)
{
if(((p_block)(ptr)) == ((p_block)(curr))->next)
{
before = curr;
isLegal = 1;
curr = ((p_block)(curr))->next;
}
else
{
curr = ((p_block)(curr))->next;
}
}
if(isLegal)
{
curr = curr - sizeof(metadata_block);
if(((p_block)(curr))->next)
{
((p_block)(curr))->free = 1;
}
else
{
sbrk(0-(((p_block)(curr))->size + sizeof(metadata_block)));
((p_block)(before))->next = NULL;
}
}
}
}
void* realloc(void* ptr, size_t size)
{
void* ptr2 = malloc(size);
int i;
for(i = 0 ; i < size ; i++)
{
*((char*)(ptr2 + i)) = *((char*)(ptr + i));
}
free(ptr);
return ptr2;
}
int main()
{
printf("I'm in.\n");
char * str = malloc(10);
printf("After Malloc()\n");
void * ptr = (void *) str;
void * ptr2;
if(!str)
{
printf("Fail.\n");
}
strcpy(str,"TEST!\0");
printf("About to free\n");
free(str);
printf("free: OK!\n");
}
Output :
I'm in.
After Malloc()
About to free
curr is 0x1049000 and ptr is 0x1049000
aaafree: OK!
note - Instaed of your mm.h include I included codes in same file

Resources