custom malloc function for c - c

I try to write my own custom malloc and free function in c. I worked around 12 hours on this and tried lots of things. But it doesn't work.
Maybe you guys can figure out the error. Allocated memory gets removed from the list with a next pointer to a specific address to identify it later in the free function. The current error is a segmentation fault 11 in the split method.
C-File:
Head:
#define MAGIC ((void*)0xbaadf00d)
#define SIZE (1024*1024*1)
typedef struct mblock {
struct mblock *next;
size_t size;
char memory[];
}mblock;
char memory[SIZE];
static struct mblock *head;
malloc:
void *halde_malloc (size_t size) {
printf("Starting\n");
printf("%zu\n",size);
if(size <= 0) {return NULL;}
if(head == NULL){
initializeBlock();
printf("Memory initialized\n");
}
mblock *temp_block = head;
while(temp_block != NULL) {
printf("IN\n");
if(temp_block->size == size) {
list_remove(temp_block);
temp_block->next = MAGIC;
return (void*)(temp_block);
} else if(temp_block->size > size) {
size_t temp_size = temp_block->size;
printf("size IS more than equal\n");
list_split_AND_Remove(temp_size - size, temp_block);
temp_block->size = size;
temp_block->next = MAGIC;
return (void*)(temp_block);
}
temp_block = temp_block->next;
printf("One block checked\n");
}
errno = ENOMEM;
return NULL;
}
Initialize:
void initializeBlock(){
printf("Initializing\n");
head = (mblock*)memory;
head->size=sizeof(memory)-sizeof(mblock);
head->next=NULL;
}
Split:
void list_split_AND_Remove(size_t size, mblock *lastBlock) {
printf("Split\n");
mblock *new = (void*)((mblock*)lastBlock+size+sizeof(mblock));
new->size = size - sizeof(mblock);
new->next = lastBlock->next;
lastBlock->next = new;
printf("START REMOVE");
list_remove(lastBlock);
}
Remove:
void list_remove(mblock *p) {
printf("Remove\n");
mblock *temp_block = head;
if(p == head) {
if(head->next == NULL) {
head = NULL;
return;
} else {
head = p->next;
return;
}
}
while(temp_block->next != NULL) {
if(temp_block->next == p) {
printf("Found P:");
temp_block = p->next;
return;
}
temp_block = temp_block->next;
}
}
Free:
void halde_free (void *ptr) {
printf("FREE\n");
mblock *new_block = ptr;
if(new_block->next == MAGIC) {
new_block->next = head;
head = new_block;
} else {abort();}
}

Issues with your code include, but are not necessarily limited to:
list_remove() does not actually remove the specified block from the list unless it happens to be the current list head. In every other case, therefore, halde_malloc() corrupts the list after calling list_remove() when it modifies the node's next pointer.
list_split_AND_Remove() performs incorrect pointer arithmetic. Specifically, mblock *new = (void*)((mblock*)lastBlock+size+sizeof(mblock)); does not do what you appear to want to do, because pointer arithmetic operates in units the size of the pointed-to type, whereas the size argument and the result of the sizeof operator have units of individual bytes. (Also, both casts are useless, albeit not harmful in themselves.)
Your allocator returns a pointer to the block header, not to its data. As a result, the user will very likely overwrite the block header's contents, leading to havoc when you later try to free that block.
You seem to assume that mblock objects have an alignment requirement of 1. That might not be true.

Related

Unexpect behaviour with pointer array

im currently implementing a basic linked list structure on C.
Basically im parsing a txt file, and I buffer each line into a Node which contains a pointer to an array of integers. The problem is, that my data (the array of integers) doesn't save correctly / i don't know how to iterate through it correctly.
These are the structures that I use:
typedef struct Node
{
struct Node* next;
struct Node* prev;
int* data;
int len;
} Node;
typedef struct LinkedList
{
Node* head;
Node* tail;
} LinkedList;
and I use this method to create a new node from a buffered string:
int nodeManager(FILE* filePointer, char* buffer, char* token, LinkedList* linkedList)
{
token = strtok(buffer, DELIMITER);
int* data = (int*)malloc(sizeof(int));
int dataIndex = 0;
if (data == NULL)
{
fprintf(stderr, DATA_ALLOCATION_ERROR);
freeLinkedList(linkedList);
fclose(filePointer);
return EXIT_FAILURE;
}
const char* insertPosition = token;
while ((token = strtok(NULL, DELIMITER)))
{
data = realloc(data, dataIndex + 1);
if (data == NULL) {
fprintf(stderr, DATA_ALLOCATION_ERROR);
freeLinkedList(linkedList);
fclose(filePointer);
return EXIT_FAILURE;
}
char *res;
int num = (int) strtol(token, &res, 10);
data[dataIndex] = num;
dataIndex++;
}
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode == NULL)
{
freeLinkedList(linkedList);
free(data);
fclose(filePointer);
return EXIT_FAILURE;
}
newNode -> prev = NULL; newNode -> next = NULL;
newNode -> len = dataIndex; newNode -> data = data;
if(strcmp(insertPosition, INSERT_TO_START) == 0)
{
addToStartLinkedList(linkedList, newNode);
}
else
{
addToEndLinkedList(linkedList, newNode);
}
return EXIT_SUCCESS; // TODO - Change
}
A line of input looks like this:
start,1,2,3,4,5,6,7,10,22,44,55,66,66,77
for some reason, node -> data doesn't get all the values that I assign in this method and I can't really tell why.
I tried to print the values like this:
for (int i = 0; i < newNode -> len; i++)
{
printf("%d,", (newNode -> data)[i]);
}
However, as I said, something quite doesn't work with my assigment, or I just don't know how to access the values correctly.
Would love to get some insight - thanks.
This part is wrong:
data = realloc(data, dataIndex + 1);
You have forgotten to multiply with sizeof(int) or better sizeof *p
BTW: Be careful about doing realloc directly into data. On failure realloc may return NULL and then you have a memory leak. You should use a temporary pointer like:
int * temp = realloc(data, SOME_SIZE);
if (temp == NULL)
{
// oh dear, add error handling here - maybe a return or whatever fits
}
else
{
// All good
data = temp;
}
OT: Passing the file pointer to the function in order to be able to close the file is (IMO) a rather strange design. Instead, the caller should check the return value and close the file (if desired).

Different behaviour for malloc(sizeof(struct Node)) vs malloc(sizeof(nodeptr))

I was trying to allocate memory using malloc, I am not able to understand why I am getting a different result for these two malloc calls.
The line below gives me wrong result even though with gdb I see the
data is getting the correct value assigned.
nodeptr n = malloc(sizeof(nodeptr));
Value head->data: '!'
Value head->eq->data: ''
And when I do this get the correct result:
nodeptr n = malloc(sizeof(struct Node));
Value head->data: 'w'
Value head->eq->data: 'X'
I followed this post, I think I am doing it correctly.
In both ways, while allocation I get the same amount of memory, just I see the different results in the end.
typedef struct Node
{
struct Node *left, *right, *eq;
char data;
bool isEnd;
} *nodeptr;
nodeptr newNode(const char c) {
nodeptr n = malloc(sizeof(nodeptr));
// nodeptr n = malloc(sizeof(struct Node));
n->data = c;
n->left = NULL;
n->right = NULL;
n->left = NULL;
n->isEnd = false;
return n;
}
void insert(nodeptr *node, const char *str) {
if (*node == NULL) {
*node = newNode(*str);
}
nodeptr pCrawl = *node;
if(pCrawl->data < *str) {
insert(&pCrawl->right, str);
} else if (pCrawl->data > *str) {
insert(&pCrawl->left, str);
} else {
if(*(str+1)) {
insert(&pCrawl->eq, str + 1);
} else {
pCrawl->isEnd = true;
}
}
}
int main(int argc, char const *argv[])
{
const char* const strs[5]= {
"w.",
};
nodeptr head = NULL;
for(int i = 0; i<1; i++) {
insert(&head, strs[i]);
}
return 0;
printf("Value head->data: \'%c\'\n", head->data);
printf("Value head->eq->data: \'%c\'\n", head->eq->data);
}
sizeof(nodeptr) == sizeof(struct Node*) != sizeof(struct Node) == sizeof(*nodeptr)
sizeof(nodeptr) will always be the size of a pointer (like 8 bytes on a 64-bit CPU)
sizeof(struct Node) refers to the struct contents
sizeof(*nodeptr) is equivalent to sizeof(struct Node) with the extra dereference operator in there.
The reason it may appear to "work" (not segfault) is that malloc suballocates from a larger block of heap memory. However, the code is writing out-of-bounds of the requested allocation, which can eventually lead to heap corruption or segfaults at some point.
The two different versions aren't allocating the same amount of memory. sizeof(nodeptr) is the size of a pointer and sizeof(struct Node) is the size of your struct. These are not the same things and they're not the same size. On my computer these values are 8 and 32.
You want to use:
nodeptr n = malloc(sizeof(struct Node));
or perhaps:
nodeptr n = malloc(sizeof(*n)); // size of the type that n points too

Free generic linked list in C - segfault

I am writing a generic linked list in C (following Kyle Loudon's book),
but when it comes to free it, I got a segfault.
Data types used for the list definition:
typedef struct list_elem_
{
void *data;
struct list_elem_ *next;
} list_elem;
typedef struct link_list_
{
int size;
int (*match)(const void *key1, const void *key2);
void (*destroy)(void *data);
list_elem *head;
list_elem *tail;
} link_list;
Function that is used to destroy caller's data:
void destroy_data(void *data)
{
if(data)
free(data);
return;
}
Destroy passed by a function pointer:
void list_init(link_list *list, void (*destroy)(void *data))
{
list->size = 0;
list->destroy = destroy;
list->head = NULL;
list->tail = NULL;
return;
}
Free the list:
void list_destroy(link_list *list)
{
void* data;
while(list_size(list) > 0)
if(list_rem_next(list, NULL, (void**)&data) == 0 && list->destroy != NULL)
list->destroy(data);
memset(list,0,sizeof(link_list));
return;
}
The segfault is triggered by the free in the destroy_data.
============== EDIT ====================
Remove a list element
int list_rem_next(link_list *list, list_elem *element, void **data)
{
list_elem *OldElement;
if(list_size(list) ==0)
return -1;
/* Remove the head */
if(element == NULL)
{
*data = list->head->data;
OldElement = list->head;
list->head = list->head->next;
if(list_size(list) == 1)
list->tail = NULL;
/* Remove other than head */
} else {
if(element->next == NULL)
return -1;
*data = element->data;
OldElement = element->next;
element->next = element->next->next;
if(element->next == NULL)
list->tail = element;
}
free(OldElement);
list->size--;
return 0;
}
=================== EDIT 2 ==========================
Inside main
link_list myList;
int i;
int *iptr;
char *chrPtr;
list_init(&myList, destroy_data);
for(i = 0; i < 4; i++)
{
iptr = malloc(sizeof(int));
*iptr = i;
list_ins_next(&myList, NULL, iptr);
}
chrPtr = malloc(sizeof("uno\0"));
chrPtr = "uno\0";
list_ins_next(&myList,NULL,chrPtr);
chrPtr = malloc(sizeof("stringa numero due\0"));
chrPtr = "stringa numero due\0";
list_ins_next(&myList,NULL,chrPtr);
chrPtr = NULL;
iptr = NULL;
getchar();
list_destroy(&myList);
In your code from main() you have:
chrPtr = malloc(sizeof("uno\0"));
chrPtr = "uno\0";
Why the explicit \0 when C adds one after it automatically?
Can you say 'memory leak'? You allocate memory; you immediately overwrite the only pointer to that allocated memory by assigning the address of the string literal to the same pointer.
What happened to strcpy()?
As a result of this abuse, you are passing unallocated memory pointers to free(); in fact, you're passing pointers to string constants to free(). That's undefined behaviour and can very easily lead to crashes!
The problem wasn't in the code you showed at first; it was in the other code. That's also why the MCVE (Minimal, Complete, Verifiable Example) — aka SSCCE (Short, Self-Contained, Correct Example) mentioned by Greg Hewgill — is so important. There's no way for us to debug code you don't show — and it is unnecessarily hard work establishing that the problem isn't in the code you do show.
You could probably use:
chrPtr = strdup("uno"));
list_ins_next(&myList, NULL, chrPtr);
chrPtr = strdup("stringa numero due");
list_ins_next(&myList,NULL,chrPtr);
to avoid the trouble. Failing that, you could use:
chrPtr = malloc(sizeof("uno"));
strcpy(chrPtr, "uno");
list_ins_next(&myList, NULL, chrPtr);
chrPtr = malloc(sizeof("stringa numero due"));
strcpy(chrPtr, "stringa numero due");
list_ins_next(&myList,NULL,chrPtr);
Neither of these checks that the memory allocation succeeded; that too should be done in production code, and arguably in school assignments.
Note that sizeof("string literal") counts the null byte, so the length is correct. Note equally that strlen("string literal") does not count the null byte — be careful!
There could still be other problems in the code; I've not verified that everything is clean. But this part will be cleaner and more likely to work correctly.
The functions list_size() and list_ins_next() are not shown. The size can be guessed; the list_ins_next() is not so easy.
I also observe that the code inserts 4 integers and then 2 strings into the list. There's no way to know that's what was inserted after the fact. The code in main() is dreadfully non-general. The support code can handle it — but heterogeneous lists are tricky; don't try it until you don't run into this sort of problem. One list of integers; fine. One list of strings; fine. One list of integers and strings — dodgy!

freeing allocated memory generates segmentation fault

I tried reading from text file, and then put every word in list node(and print it afterwards in reverse order).
The program works good, but when trying to free the allocated list nodes, the program crash.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <math.h>
typedef struct node{
char* word;
struct node* next;
}; typedef struct node* list;
void freeall(list lst){
list temp = NULL;
while (lst)
{
temp = lst->next;
free(lst);
lst = temp;
}
#if 0
if (lst == NULL){ return; }
freeall(lst->next);
free(lst->word);
free(lst);
#endif // 0
}
void deleteAllNodes(list start)
{
while (start != NULL)
{
list temp = start;
free(temp);
start = start->next;
}
}
list createNode(char* buff){
list newnode = (list)malloc(sizeof(list));
assert(newnode);
newnode->next = NULL;
newnode->word = (char*)calloc(strlen(buff), sizeof(char));
assert(newnode->word);
strcpy(newnode->word, buff);
return newnode;
}
void reverse(const char *str) //you don't need to modify your string
{
if (*str != '\0'){ //if the first character is not '\O'
reverse((str + 1)); // call again the function but with +1 in the pointer addr
printf("%c", *str); // then print the character
}
}
void print_reverse(list lst){
if (lst == NULL) return;
print_reverse(lst->next);
reverse(lst->word);
//free(lst->word);
}
list createList(FILE* ifp){
struct node *loop = NULL;
list curr = NULL;
list lst = NULL;
char *word = NULL;
size_t size = 2;
long fpos = 0;
char format[32];
if (ifp == NULL) // open file
perror("Failed to open file \n");
if ((word = malloc(size)) == NULL) // word memory
perror("Failed to allocate memory");
sprintf(format, "%%%us", (unsigned)size - 1); // format for fscanf
while (fscanf(ifp, format, word) == 1) {
while (strlen(word) >= size - 1) { // is buffer full?
size *= 2; // double buff size
printf("** doubling to %u **\n", (unsigned)size);
if ((word = realloc(word, size)) == NULL)
perror("Failed to reallocate memory");
sprintf(format, "%%%us", (unsigned)size - 1);// new format spec
fseek(ifp, fpos, SEEK_SET); // re-read the line
if (fscanf(ifp, format, word) == 0)
perror("Failed to re-read file");
}
curr = createNode(word);
if (lst == NULL){lst = curr;}
else{
loop = lst;
while (loop->next != NULL) {//loop to last structure
loop = loop->next;//add structure to end
}
loop->next = curr;
}
fpos = ftell(ifp); // mark file pos
}
free(word);
return lst;
}
int main(int argc, char* argv[]){
assert(argc == 2);
FILE *ifp = fopen(argv[1], "r");
assert(ifp);
list lst = NULL;
lst = (list)malloc(sizeof(list));
lst = createList(ifp);
print_reverse(lst);
fclose(ifp);
//freeall(lst);
//deleteAllNodes(lst);
return 1;
}
your delete all nodes has a bug in it. You freed a pointer and tried accessing it immediately. So the program crashes You can try this
void deleteAllNodes(list head)
{
list ptr = head;
while ((ptr = head) != NULL)
{
head = head->next;
free (ptr);
}
}
point the current ptr to the head and point head to next element. Delete the current pointer.
In your deleteAllNodes function you are free-ing a pointer and then accessing it. You could try deleting nodes in reverse order, starting from the last one, for instance with a recursive function.
void deleteAllNodes(list start)
{
if (start != NULL)
{
deleteAllNodes(start->next);
free(start);
}
}
Or you can stick to the iterative forward deletion with something like (untested):
void deleteAllNodes(list start)
{
list previous = NULL;
while (start != NULL)
{
if (previous != NULL)
free(previous);
previous = start;
start = start->next;
}
if (previous != NULL)
free(previous);
}
The problem , as I see it is with
list newnode = (list)malloc(sizeof(list));
your list is a typedef to struct node*, so this statement is essentially
list newnode = (list)malloc(sizeof(struct node*));
which is wrong. You're allocating memory for a pointer to structure variable, whereas, you should be allocating memory equal to the size of the structure variable itself.
Two things to mention here
Please see why not to cast the return value of malloc() and family in C.
Never use a typedef for a pointer type. It's not a "rule", but better to stick to it.
Your allocation statement, at least, shall look like
list = malloc(sizeof*list);
Apart from this, in your main() function,
First, you're allocating memory to lst using malloc() [Same issue with the allocation as above]
Then, you assign another pointer, the return value of createList() to lst.
This way, you're overwriting the allocated mekory through malloc(), creating memory leak. You don't need malloc() there, at all.

Allocating recently freed memory

I have a struct that I use to build a linked list as below;
struct my_struct{
char a[16];
struct my_struct *next;
}
I free that linked list by below function;
void free_my_list(struct my_struct* recv) {
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}
In my program, I use a struct _my_list over and over but free and malloc it every time as below:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
Every time I fill the list, I print char arrays and then reset _my_struct by above code.
Above code works fine on Ubuntu pc, but on Cent OS after printing first list(after first malloc _my_struct) correctly, following list are printed as corrupted data.
When I don't free and malloc memory during whole program execution it works fine in Cent OS too but I should reset list _my_list between printf() calls.
_my_list is filled and printed via below functions;
/*prints every item in my_list*/
void print_my_list(struct my_struct *recv, FILE *fd) {
my_list *tmp;
tmp = recv;
while (tmp != NULL) {
if (fwrite(tmp->a, 1, strlen(tmp->a), fd) == -1) {
pritnf("error\n");
}
tmp = tmp->next;
}
}
/*Add 'a' string to _my_list*/
void add_recv_to_list(struct my_struct **recv_list, char *recv) {
struct my_struct *tmp;
tmp = *recv_list;
if (*recv_list == NULL) {
*recv_list = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = *recv_list;
} else {
while ((tmp->next) != NULL) {
tmp = tmp->next;
}
tmp->next = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = tmp->next;
}
strncpy(tmp->a, recv, MAX_NAME_LEN);
tmp->next = NULL;
}
What can be the reason, any ideas?
I think that your problem may start here:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
When you initialize the struc: struct my_struct *_my_list; you don't assign it any value, so it holds whatever garbage data was in memory beforehand. When you free() that in free_my_list, the behavior is undefined (you are freeing something that you never malloc()ed - so the result may very well be corruption of something or other later on. Try changing your declaration to: struct my_struct *_my_list = NULL; (always a good practice to initialize pointers to NULL, anyway) and changing your free_my_list function to:
void free_my_list(struct my_struct* recv) {
if (recv == NULL)
return;
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}

Resources