Implementing Malloc: case for splitting a block - c

The heap is a linked list of structs of the following definition:
struct block
{
/*header + block*/
bool freeSpace;
block * prev;
block * next;
size_t size;
char block_part[];
};
I'm working on the following case:
If the first block of memory I find is so big that it can accommodate both the newly allocated
block and another block in addition, then the block is split in two; one block to hold the newly
allocated block, and a residual free block.
(Note that if it’s a bit larger than what I need, but not big
enough for a new block (i.e. it’s not big enough to hold the metadata of a new block), I will have unused space at the end of the block.)
My code is the following. When I test specifically this case, my program crashes with a segfault. Could someone see what the problem is? Thanks.
do{
if (ptr -> freeSpace && ptr -> size >= size){
/*first suffient free block is found*/
ptr -> freeSpace = false;
if (ptr -> size > size + sizeof(struct block)){
/*if big enought for 'size' AND metadata of a new block, split the block*/
struct block * returnPtr = memset((ptr -> block_part), 0, size);
struct block * added = returnPtr + size;
added -> size = ptr -> size - size - sizeof(struct block);
added -> freeSpace = true;
added -> prev = ptr;
added -> next = ptr -> next;
(ptr -> next) -> prev = added;
ptr -> next = added;
ptr -> size = size;
return returnPtr;
}
ptr -> size = size;
return memset((ptr -> block_part), 0, size);
}
prevPtr = ptr;
ptr = ptr -> next;
}while (ptr);

Memset returns a void *. It doesn't give warning because void pointers are automatically casted by the Compiler (e.g. malloc (non-)cast).
struct block *returnPtr = memset((ptr->block_part), 0, size);
Why would you waste memory for a whole struct with multiple members to store a void pointer pointing to character?
After that you use the address of the now void pointer and move it size-number forwards. Afterwards treat it like an allocated struct. That results in added not being allocated at all (if size is bigger than strlen(ptr->block_part)+1 you are already at someone other's memory) or at least violating memory. Accessing such memory gives so an erroneous program.
Hence, you observe segmentation fault and you program crashes.
Note: So far, I haven't seen someone use in such way the memset return value.

Related

Reallocation of memory to empty reference

I was watching a lesson on malloc and while they were doing a specific example, it made no sense for why such code to print out the entire pointer.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *list = malloc(3 * sizeof(int));
if (list == NULL)
return 1;
list[0] = 1;
list[1] = 2;
list[2] = 3;
int *tmp = malloc(4 * sizeof(int));
if (tmp == NULL)
return 1;
for (int i = 0; i < 3; i++)
tmp[i] = list[i];
tmp[3] = 4;
free(list);
//From this line and below is the thing in question.
list = tmp;
for (int i = 0; i < 4; i++)
printf("%i\n", list[i]);
}
OUTPUT:
~/test/ $ ./malloc_test
1
2
3
4
From my understanding of free(), it de-allocates the memory allocated by allocation functions and free() will 'free' up the memory of the pointer.
If I were to go by this definition:
*list was allocated 12 bytes (3 * sizeof(int), sizeof(int) = 4
Hard code list with numbers
*tmp was allocated 16 bytes
Copy the numbers in list to tmp
Free up list making it have no allocated bytes
List is now equal to tmp
How can list now be equal to tmp when list doesn't have any allocated memory?
Is list pointing to the address of tmp? If yes, why do we need to not allocate memory for list since earlier in the code, we did this int *tmp = malloc(4 * sizeof(int));
*list was allocated 12 bytes (3 * sizeof(int), sizeof(int) = 4
To be precise, you allocated 12 bytes of memory and set list to point to that memory.
Hard code list with numbers
*tmp was allocated 16 bytes
Again, to be precise, you allocated 16 bytes of memory and set the pointer variable tmp to point to it.
Copy the numbers in list to tmp
Free up list making it have no allocated bytes
To be precise, you freed the object that list pointed to so now list points to garbage and must not be dereferenced.
list is now equal to tmp
To be precise, list now points to the same thing tmp points to, those 16 bytes you allocated that previous was pointed to only by tmp.
How can list now be equal to tmp when list doesn't have any allocated memory?
Previously, list didn't point to allocated memory. But you changed it to point to the 16 bytes you allocated second. The value of a pointer is what it points to, list and tmp now point to the same thing so they have the same value. So they're now equal.
Is list pointing to the address of tmp? If yes, why do we need to not allocate memory for list since earlier in the code, we did this int *tmp = malloc(4 * sizeof(int));
The code frees the first allocated block of memory. If it didn't allocate a second block of memory, there would be nothing valid for either pointer to point to!
When you copy a pointer you're just copying the pointer's value1:
list = tmp;
This means that list now contains a copy of the tmp pointer, or in other words, they both point to the same memory address. In this case that address is an allocation.
Once they're made identical you can reference either of them interchangeably.
1 Of course this presumes the pointers are of the same type, like int* to int*, and not int to int**. You could also assign to void* and convert back again later, that works as well.
a pointer is a data type that is only assigned memory addresses of the corresponding data type, in your case in list = tmp; you assign the first position of that memory block that you created with int * tmp = malloc (4 * sizeof (int)); , when you make the assignment to list it will point to that memory address. (in your case at the beginning of that memory block).

C11 - Realloc on array of structs fails when doing realloc twice

I'm trying to use malloc and realloc to hold an array of structs. The array should dynamically grow, size should increase by 10 struct elements every time.
Struct:
typedef struct
{
unsigned char foreign_word_[100] = {0};
unsigned char native_word_[100] = {0};
} VocabularyCouple;
In my main, I initialize the array with malloc:
VocabularyCouple* VocStruct = (VocabularyCouple*)malloc(sizeof(*VocStruct) * 10);
Increasing the size of the struct-array seems to work fine in main...
VocabularyCouple* temp = (VocabularyCouple*)realloc(VocStruct, (sizeof(VocabularyCouple) * 20));
if (temp == NULL)
{
printf("ERROR: Out of Memory\n");
return 4;
}
else
{
VocStruct = temp;
free(temp);
temp = NULL;
}
However, if I put the realloc-part into a function like this:
uint8_t resizeVoc(uint32_t new_size, VocabularyCouple **VocStruct)
{
VocabularyCouple *temp = (VocabularyCouple*)realloc(*VocStruct, (sizeof(VocabularyCouple) * new_size));
...
}
I can only call the function once. Every other call will result in this error:
HEAP[VocTest.exe]: Invalid address specified to RtlValidateHeap( 01300000, 01308500 )
Unless I'm missing something, this should be the same problem as c - Realloc an array of Structs, but I just can't get it to work.
Thank you for your help!
VocStruct = temp;
free(temp);
This is wrong, you free all memory as soon as you have allocated it. VocStruct and temp point at the same memory area. Just remove the free().
To clarify, the temp pointer is just there in case realloc fails. Had you written VocStruct = realloc(VocStruct, ... and realloc fails, then you would have overwritten the only pointer to the allocated memory with NULL and created a memory leak. But you only ever have 1 chunk of memory - even though 2 pointers point at it at the same time.

My custom malloc function crashes when the remaining memory surpasses certain size [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I tried to create my own malloc function in C, using array as the memory i'll be working with. But when the remaining memory size surpasses a certain number of bits, the program crashes saying " Exception thrown: write access violation."
I divide the memory to a blocks. Each block will have a little metadata block that preserves the size of the block and whether is it free or taken (at the beginning, the entire memory array is one big block).
Then my malloc finds the first memory block with sufficient size and uses it (or part of it).
The problem is:
If i initialize an array of size 20000 bytes for example, my malloc will only work if the remaining free bytes in array would be 17708 or more.
#include <stdio.h>
char memory[20000];
struct block {
unsigned int size;
int free;
struct block* next;
};
struct block* freeList = (void*)memory;
void initialize() { /
freeList->size = 20000 - sizeof(struct block);
freeList->free = 1;
freeList->next = NULL;
}
void split(struct block* fitting_slot, unsigned int size) {
struct block* new = (void*)(fitting_slot + size + sizeof(struct block));
unsigned int temp = (fitting_slot->size) - size - sizeof(struct block);
printf("Remaining memory size is %d\n", temp);
new->size = temp; // this is where program crashes
new->free = 1;
new->next = fitting_slot->next;
fitting_slot->size = size;
fitting_slot->free = 0;
fitting_slot->next = new;
}
void* MyMalloc(unsigned int noOfBytes) {
struct block* curr;
void* result;
if (!(freeList->size)) {
initialize();
}
curr = freeList;
while ((((curr->size) < (noOfBytes + sizeof(struct block))) || ((curr->free) == 0)) && (curr->next != NULL)) {
curr = curr->next;
}
printf("From the free memory of size : %d\n", curr->size);
printf("We will occupy this size : %d\n", noOfBytes + sizeof(struct block));
if ((curr->size) == (noOfBytes + sizeof(struct block))) {
curr->free = 0;
result = (void*)(++curr);
printf("Exact fitting block allocated\n\n");
}
else if ((curr->size) > (noOfBytes + sizeof(struct block))) {
split(curr, noOfBytes);
result = (void*)(++curr);
printf("Fitting block allocated with a split\n\n");
}
else {
result = NULL;
printf("Sorry. No sufficient memory to allocate\n\n");
}
return result;
}
int main(){
unsigned int size = 2270 * sizeof(char);
char* k = (char)MyMalloc(size);
printf("Success\n");
}
If the number of "size" is 2269 or lower, program works correctly.
If the number of "size" in main is 2270 or higher, program crashes on the line
new->size = temp in function split() saying "Exception thrown: write access violation."
OK, so I think you are offsetting by the wrong amount. Pointers in C have an indication of the size of thing they are pointing to, so if you want a byte offset you need to cast the pointer to char*, or I think void* should also work fine. (see the edit below, this was mistaken)
I have not done a detailed debug, however changing line 20 from
struct block* new = (void*)(fitting_slot + size + sizeof(struct block));
to:
struct block* new = (void*)(fitting_slot) + size + sizeof(struct block);
seemed to at least stop the errors.
I can set size right up to 19968 (the max) and all seems well.
EDIT
So, as #R.. correctly pointed out below, arithmatic on void pointers is not allowed (although gcc and probably other compilers let you get away with it) - see this answer, for example, on the topic.
The most appropriate thing would seem to be casting to char*. Given that the fitting_slot variable is also already in units of the block size, rather than adding sizeof(struct block) it is simpler to just add 1 to that, then the size once case to char:
struct block* new = (void*)((char*)(fitting_slot+1) + size);
I've tested this and it seems to work the same in gcc as the previous edit, but legally now.
In the line where new is assigned pointer arithmetic is done on a struct block*.
When you do pinter arithmetic on a typed pointer, c semantics assumes, that an array is being manipulated. For example ptr++ on a struct block* increases the value of the pointer by sizeof(struct block).
You should cast your pointer to char* before performing arithmetic on it this way. I am not sure I got everything, but I hope this can get you started.
I used my debugger.I assume that you forgot a malloc in split function.
struct block* new = (void*)malloc(fitting_slot + size + sizeof(struct block));
If you use a debbuger you'll find out that new->size was unreachable address.
**this would be line 20, if the include is in line 1.

My fav Segfault!! why?

why this,causes a segfault??
#include<stdio.h>
#include<stdlib.h>
struct node
{
double d;
int *array;
char c;
};
void allocator(struct node *ptr)
{
int *tmp;
tmp = (int*)realloc(ptr, 10);
if(!tmp)
{
ptr->array=tmp;
ptr->array[0] = 23;
}
}
int
main()
{
struct node *ptr = (struct node*)malloc(sizeof(struct node));
ptr->c = 'y';
allocator(ptr);
printf(" %c\n", ptr->c);
printf(" %d\n", ptr->array[0]);
return 0;
}
i got an impression as if the realloc() in the allocator function allocates memory which also maps to the memory allocated by malloc() in the main..
but how does this could happen?? Doesn't the memory manager(i guess the lib(stdlib) here) keeps track of free and allocated spaces in a process??
You're allocating space enough for a struct node then reallocating it to 10 bytes, then accessing the member c which, due to the structure of node, is probably past the 10th byte. This causes a segfault.
Also, if whoever's business it is to decide decides that it needs to move the memory block, realloc returns a pointer to the new location but the pointer back in main still points to the old block which has been reclaimed. This could also cause a segfault.
Also, in this code:
int *tmp;
tmp = (int*)realloc(ptr, 10);
if(!tmp)
{
ptr->array=tmp;
ptr->array[0] = 23;
}
if !tmp, you're accessing a NULL pointer because you're assigning tmp to ptr->array then accessing the 0th element. This could also cause a segfault.
There are many problems in your code. You may need to rewrite much of it.
The problem with this is the attempt to access an unallocated pointer, which happens in main:
printf(" %d\n", ptr->array[0]);
Your allocation function assigns space for ptr, which is a structure, but not for the array within that structure. Possibly this is not what you intended to do (comment your code!).

initializing a data structure in C to manage a pool of memory

i am writing a simple function for a library, that will take in as a parameter the size of memory to be managed by my other functions.
i have a data structure that holds the information of this large memory pool initialized by the user.
typedef struct memBlock{
struct memBlock* next;
unsigned int size; // Size of this block
unsigned int is_used; // bool 0 = not used 1 = used
} memBlock;
I also have this function that i am trying to figure out how to initialize this data structure as well as allocate enough space to be managed initially?
int initialize_memory(unsigned long size){
memBlock *ptr; // the beginning of our whole memory to be handled
ptr = malloc(size); // this is the ptr to the original memory first allocated.
ptr->next = NULL;
ptr->size = NULL;
ptr->is_used = 0;
has_initialized = 1; // the memory has been initialized
}
please help
Change ptr->size = NULL; to ptr->size = size;. You also need to return ptr, or store it somewhere. Your function returns int, but you don't return anything. has_initialized seems unnecessary -- you know you've initialized because your memory pool (the ptr value you will return) isn't NULL. If you need more help than that, you're going to have to explain more.
Addendum: You need to decide whether memBlock.size is the size of the allocated space or the size of the memory block represented by the memBlock ... if the latter, then you need to account for the space occupied by the memblock itself by subtracting that off the amount of space you allocated: ptr->size = size - sizeof(struct memBlock); You also need a way to address your memory pool ... since that immediately follows the memBlock, its address is (ptr + 1) or &ptr[1] (if you don't understand that, look up "pointer arithmetic in C").
P.S. You wrote in a comment "Essentially i also have another function that will act like 'malloc' to reserve a number of bytes but will first check this data structure to see if any memory is available from my pool"
Why do you want to do that? malloc already manages memory far better than your function will, considering the skill level and time invested, and there's no point in layering another memory allocator on top of it. Unless this is a school project to write a memory allocator, in which case you should say that up front.
typedef struct memBlock {
unsigned int size;
unsigned int initialized;
void* block;
} memBlock;
memBlock* new_memBlock(unsigned int size)
{
memBlock* memblock;
memblock = malloc(sizeof(memBlock));
if (memblock)
{
memblock->size = size;
memblock->block = malloc(size);
if (memblock->block)
memblock->initialized = 1;
}
return memblock;
}
void free_memBlock(memBlock** memblock)
{
if (*memblock)
{
free(*memblock->block)
*memblock->block = 0;
}
free(*memblock);
*memblock = 0;
}
void main()
{
memBlock* memblock = new_memBlock(1024);
if (memblock && memblock->initialized)
printf("Initialized\n");
else
printf("Not initialized\n");
free_memBlock(&memblock);
}

Resources