Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Testing buddy memory allocator for real-time system in C

I am trying to write Buddy memory allocator for FreeRTOS.

Structs:

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;

Here’s some of my code:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include <stdint.h>
#include <cstring>
#include "buddy_alloc.h"

#define BUDDY_MIN_BLOCK_SIZE 32
#define NULL 0


void buddy_init(buddy_allocator_t *allocator, void *memory, size_t *size) {
    // Initialize the allocator structure
    allocator->total_size = *size;
    allocator->min_block_size = BUDDY_MIN_BLOCK_SIZE;
    allocator->freelist = (buddy_block_t *) memory;
    allocator->freelist->next = NULL;
    allocator->freelist->size = *size;
    allocator->freelist->is_free = true;
}

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;

    // 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 (buddy < allocator->freelist ||
        buddy > (buddy_block_t *) ((uint8_t *) allocator->freelist + allocator->total_size)) {
        // The buddy is outside of the memory region managed by the allocator, so it 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;
    }
}

Now I need to test it, I wrote some tests in main.c:

// Test 1: Test with a single block in the free list
void test_buddy_init_1() {
    // Initialize the allocator
    buddy_allocator_t allocator;
    size_t size = 128;
    buddy_init(&allocator, NULL, &size);

    // Check the total size of the memory region
    assert(allocator.total_size == 16);

    // Check the size of the first block in the free list
    assert(allocator.freelist->size == 16);

    // Check the "is_free" flag of the first block
    assert(allocator.freelist->is_free == true);

    // Check the "next" pointer of the first block
    assert(allocator.freelist->next == NULL);
}

// Test 2: Test with a larger memory region
void test_buddy_init_2() {
    // Initialize the allocator
    buddy_allocator_t allocator;
    size_t size = 128;
    buddy_init(&allocator, NULL, &size);

    // Check the total size of the memory region
    assert(allocator.total_size == 128);

    // Check the size of the first block in the free list
    assert(allocator.freelist->size == 128);

    // Check the "is_free" flag of the first block
    assert(allocator.freelist->is_free == true);

    // Check the "next" pointer of the first block
    assert(allocator.freelist->next == NULL);
}

When I run these tests I get Segmentation Fault – Process finished with exit code -1073741819 (0xC0000005)

So, my question is, what’s the issue?
It’s because I run these tests on Windows?
Or am I doing something wrong in the code?

>Solution :

There’s a NULL pointer dereference in buddy_init in your tests.

void test_buddy_init_2() {
    // Initialize the allocator
    buddy_allocator_t allocator;
    size_t size = 128;
    buddy_init(&allocator, NULL, &size);
    ...

void buddy_init(buddy_allocator_t *allocator, void *memory, size_t *size) {
    // Initialize the allocator structure
    allocator->total_size = *size;
    allocator->min_block_size = BUDDY_MIN_BLOCK_SIZE;
    allocator->freelist = (buddy_block_t *) memory;
    allocator->freelist->next = NULL;
    ...

As can be seen memory is NULL, therefore allocator->freelist is NULL, therefore allocator->freelist->next is a NULL pointer dereference and therefore undefined behaviour. This is the cause of your crash.

I’m guessing that you should pass a suitably large block of memory to buddy_init instead of NULL.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading