Page 1 of 1

Strange memory allocation bug

Posted: Thu Jul 03, 2025 3:58 pm
by torii
Hello all!
I am experiencing a strange bug when using the liballoc implementation of malloc.
When first accessing allocated memory, the next write to memory seems to be ignored completely, leaving the memory uninitialised. I have added some example screenshots below:

Code: Select all

    int *n = malloc(sizeof(int));

    *n = 10;
    char buf[10] = {0};
    utos(*n, 10, buf);
    fputs(1, buf);
    fputs(1, "\n");

    *n = 12;
    utos(*n, 10, buf);
    fputs(1, buf);
malloc bug 2.png
malloc bug 2.png (452 Bytes) Viewed 1366 times
By moving the declaration of `buf` before assigning to *n:

Code: Select all

    int *n = malloc(sizeof(int));
    char buf[10] = {0};

    *n = 10;
    utos(*n, 10, buf);
    fputs(1, buf);
    fputs(1, "\n");

    *n = 12;
    utos(*n, 10, buf);
    fputs(1, buf);
malloc bug 3.png
malloc bug 3.png (351 Bytes) Viewed 1366 times
Edit: forgot to upload the github link https://github.com/Toriiiiiiiiii/Solkern

Re: Strange memory allocation bug

Posted: Thu Jul 03, 2025 7:48 pm
by Octocontrabass
Have you tried disassembling this function? I suspect your code isn't doing what you think it's doing. I'm especially interested in the parameters being passed to utos().

Re: Strange memory allocation bug

Posted: Fri Jul 04, 2025 10:45 am
by torii
Octocontrabass wrote: Thu Jul 03, 2025 7:48 pm I'm especially interested in the parameters being passed to utos().
My implementation of utos() takes the value, number base and output buffer, and the code itself is as follows:

Code: Select all

void utos(uint32_t val, uint8_t base, char *buf) {
    uint32_t n = 0;
    uint32_t temp = val;

    if(val == 0) {
        return "0";
    }
    else {
        while(temp > 0) {
            n++;
            temp /= base;
        }
    }

    buf[n] = '\0';

    char charmap[32] = "0123456789abcdefghijklmnopqrstu";

    unsigned int strptr = n-1;
    while(val > 0) {
        char digit = charmap[val % base];
        val /= base;

        buf[strptr] = digit;
        strptr--;
    }
}
I do not believe the behaviour of this function is relevant to the issue, as the issue still occurs in other scenarios, such as dynamically allocated strings.

Interestingly, moving the testing code to before reading the multiboot information structure makes the numbers appear properly in the serial terminal, however it causes a page fault.
Is it possible that my page allocation code may be faulty? I have the source for that below:

Code: Select all

uint8_t get_frame_status(int frameid) {
    uint32_t index = frameid / 8;
    uint32_t shift = frameid % 8;
    uint8_t  byte  = framemap[index];

    return (byte & (1 << shift)) >> shift;
}

void set_frame_status(int frameid, uint8_t s) {
    uint32_t index = frameid / 8;
    uint32_t shift = frameid % 8;

    framemap[index] |= (s & 1) << shift;
}

void* kalloc_alloc(int n) {
    uint32_t first_frame = (end_kernel) / 4096 + 1;
    uint32_t index = 0;
    while(index < NPAGES) {
        
        uint8_t success = 1;
        for(int i = 0; i < n; ++i) {
            if(get_frame_status(index + i)) { 
                success = 0;
                break;
            }
        }

        if(success) {
            for(int i = 0; i < n; ++i) {
                set_frame_status(index + i, 1);
            }

            return (void*)(first_frame + (index * 4096));
        }

        index++;
    }

    return (void*)0;
}

void kalloc_free(void* ptr, int n) {
    uint32_t first_frame = (end_kernel + 4096) / 4096;
    uint32_t index = ((uint32_t)ptr - first_frame) / 4096;

    for(int i = 0; i < n/8; ++i) {
        for(int j = 0; j < 8; ++j) {
            set_frame_status(index+8*i+j, 0);
        }
    }
}

Re: Strange memory allocation bug

Posted: Fri Jul 04, 2025 7:19 pm
by Octocontrabass
torii wrote: Fri Jul 04, 2025 10:45 amMy implementation of utos() takes the value, number base and output buffer, and the code itself is as follows:
I'm sure utos() works fine. What I'd like to know is whether the caller is actually passing the parameters you expect. You wrote code to read back the value you just wrote to memory, but the compiler has no reason to believe you'd ever read a different value than what you just wrote, so the compiler might generate code that always passes the "correct" value to utos().
torii wrote: Fri Jul 04, 2025 10:45 amIs it possible that my page allocation code may be faulty?
Either that or you're interpreting the memory map wrong and trying to allocate non-memory addresses as if they were memory.

Re: Strange memory allocation bug

Posted: Sat Jul 05, 2025 5:18 am
by nullplan
Your set_frame_status function is definitely faulty, because it cannot set a bit to zero. I would write it like this:

Code: Select all

void set_frame_status(int frameid, uint8_t s) {
    uint32_t index = frameid / 8;
    uint32_t shift = frameid % 8;

    framemap[index] = (framemap[index] & ~(1 << shift)) | ((s&1) << shift);
}
However, that would only explain you slowly running out of memory. It does not explain the weird behavior you are seeing. That can be explained by aliasing objects that ought not be aliased. I would start looking at the addresses malloc() returns and comparing them to stack addresses. As far as I can tell, you are not actually parsing the memory map, you are just assuming that the first 4MB behind your kernel image (which is linked to the 2MB line) is going to be free RAM. That may be a bad assumption to make.