Tarferi icon

Memory management implementation

Tarferi | PRO | 11/05/20 08:08:22 PM UTC | 0 ⭐ | 2866 👁️ | Never ⏰ | []
C |

11.98 KB

|

None

|

0 👍

/

0 👎

#include <stdio.h>
#include <stdlib.h>
 
// Declare the functions so they can be defined later and are linked to their correct identifiers
#define malloc malloc_%RANDOM%
#define aligned_alloc aligned_alloc_%RANDOM%
#define calloc calloc_%RANDOM%
#define realloc realloc_%RANDOM%
#define free free_%RANDOM%
 
void* malloc(unsigned int sz);
void* aligned_alloc(unsigned int alignment, unsigned int sz);
void* calloc(unsigned int num, unsigned int sz);
void* realloc(void* ptr, unsigned int sz);
void free(void* ptr);
 
 
#define main user_main_%RANDOM%
 
 
// User code
int main(int argc, char** argv) {
    return 0;
}
 
 
 
// End of user code
 
 
#define MALLOC_MEM_BLOCK_SIZE_%RANDOM% 1024
#define MALLOC_MEM_BLOCK_COUNT_%RANDOM% 1024
#define MALLOC_MEM_BLOCK_COUNT_PRE_%RANDOM% 1024
#define MALLOC_MEM_BLOCK_COUNT_POST_%RANDOM% 1024
 
struct t_memory_%RANDOM%{
    struct {
        void(*init_memory)();
        void(*check_memory_after_end)();
        void*(*malloc_init_block)(int, unsigned int);
        void*(*malloc)(unsigned int);
        void(*free)(void*);
        void*(*realloc)(void* ptr, unsigned int sz);
        void*(*calloc)(unsigned int num, unsigned int sz);
        void*(*aligned_alloc)(unsigned int alignment, unsigned int sz);
    } functions;
    int(*userMain)(int, char**);
    struct {
        char used;
        unsigned int sz;
        char memoryPre[MALLOC_MEM_BLOCK_COUNT_PRE_%RANDOM%];
        char memory[MALLOC_MEM_BLOCK_SIZE_%RANDOM%];
        char memoryPost[MALLOC_MEM_BLOCK_COUNT_POST_%RANDOM%];
    } mallocated_memory[MALLOC_MEM_BLOCK_COUNT_%RANDOM%];
    int MALLOC_MEM_BLOCK_COUNT;
    int MALLOC_MEM_BLOCK_SIZE;
    int MALLOC_MEM_BLOCK_COUNT_PRE;
    int MALLOC_MEM_BLOCK_COUNT_POST;
 
    struct {
        int used_blocks;
        int available_blocks;
        int last_init_block;
        int available_allocations;
    } config;
    struct {
        int mem_leaks;
        int invalid_frees;
        int invalid_realloc;
        int zero_allocs;
        int negative_allocs;
        int big_allocs;
        int too_many_allocs;
        int writes_before;
        int writes_beyond;
    } stats;
} memory_%RANDOM%;
 
void check_memory_after_end_%RANDOM%() {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
 
    for(int i = 0; i < mem->config.last_init_block; i++) {
        if(mem->mallocated_memory[i].used){
            mem->stats.mem_leaks++;
        }
    }
    if (
        mem->stats.mem_leaks > 0 ||
        mem->stats.invalid_frees > 0 ||
        mem->stats.zero_allocs > 0 ||
        mem->stats.negative_allocs > 0 ||
        mem->stats.big_allocs > 0 ||
        mem->stats.too_many_allocs > 0 ||
        mem->stats.writes_before > 0 ||
        mem->stats.writes_beyond > 0 ||
        mem->stats.invalid_realloc > 0
    ) {
        printf("Memory Error: "
               "leaks: %d, "
               "invalid frees: %d, "
               "zero mallocs: %d, "
               "negative mallocs: %d, "
               "big mallocs: %d, "
               "too many allocs: %d, "
               "writes beyond: %d, "
               "writes before: %d, "
               "invalid realloc: %d, ",
            mem->stats.mem_leaks,
            mem->stats.invalid_frees,
            mem->stats.zero_allocs,
            mem->stats.negative_allocs,
            mem->stats.big_allocs,
            mem->stats.too_many_allocs,
            mem->stats.writes_before,
            mem->stats.writes_beyond,
            mem->stats.invalid_realloc
        );
    }
 
}
 
void* malloc_init_block_%RANDOM%(int blockIndex, unsigned int sz) {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
 
    mem->mallocated_memory[blockIndex].used = 1;
    for(int o = 0; o < mem->MALLOC_MEM_BLOCK_COUNT_PRE; o++) {
        mem->mallocated_memory[blockIndex].memoryPre[o] = 0;
    }
    for(int o = 0; o < mem->MALLOC_MEM_BLOCK_COUNT_POST; o++) {
        mem->mallocated_memory[blockIndex].memoryPost[o] = 0;
    }
    for(int o = 0; o < mem->MALLOC_MEM_BLOCK_SIZE; o++) {
        mem->mallocated_memory[blockIndex].memory[o] = 0;
    }
    mem->mallocated_memory[blockIndex].used = 1;
 
 
    mem->config.used_blocks++;
    mem->mallocated_memory[blockIndex].sz = sz;
    return &(mem->mallocated_memory[blockIndex].memory);
}
 
void* malloc(unsigned int sz) {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
 
    if(mem->config.available_allocations < 0) {
        mem->config.available_allocations = mem->MALLOC_MEM_BLOCK_COUNT;
    }
 
    if (mem->config.used_blocks >= mem->config.available_allocations) {
        return 0;
    }
 
    if(sz > (unsigned int) mem->MALLOC_MEM_BLOCK_SIZE) {
        mem->stats.big_allocs++;
        return 0;
    } else if( ((int)sz) < 0) {
        mem->stats.negative_allocs++;
        return 0;
    } else if(sz == 0) {
        mem->stats.zero_allocs++;
        return 0;
    }
 
 
    if(mem->config.used_blocks == mem->MALLOC_MEM_BLOCK_COUNT) {
        return 0;
    } else {
        for(int i = 0; i < mem->config.last_init_block; i++) {
            if(mem->mallocated_memory[i].used == 0) {
                return mem->functions.malloc_init_block(i, sz);
            }
        }
 
        mem->config.last_init_block++;
        return mem->functions.malloc_init_block(mem->config.last_init_block - 1, sz);
    }
}
 
void free(void* ptr) {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
 
    for(int i = 0; i < mem->config.last_init_block; i++) {
        if((&(mem->mallocated_memory[i].memory)) == ptr) { // Our memory
            if (mem->mallocated_memory[i].used != 1) { // Should never happen
                mem->stats.invalid_frees++;
            } else {
                mem->mallocated_memory[i].used = 0;
                mem->config.used_blocks--;
            }
 
            // No clearing, next malloc clears, if needed
            for(int o = mem->mallocated_memory[i].sz; o < mem->MALLOC_MEM_BLOCK_SIZE; o++) {
                if(mem->mallocated_memory[i].memory[o] != 0){
                    mem->stats.writes_beyond++;
                }
            }
            for(int o = 0; o < mem->MALLOC_MEM_BLOCK_COUNT_PRE; o++) {
                if(mem->mallocated_memory[i].memoryPre[o] != 0){
                    mem->stats.writes_before++;
                }
            }
            for(int o = 0; o < mem->MALLOC_MEM_BLOCK_COUNT_POST; o++) {
                if(mem->mallocated_memory[i].memoryPost[o] != 0){
                    mem->stats.writes_beyond++;
                }
            }
 
            return;
        }
 
    }
    // No our memory, freeing whatever bad
    mem->stats.invalid_frees++;
}
 
void* calloc(unsigned int num, unsigned int sz) {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
    return mem->functions.malloc(num*sz);
}
 
void* realloc(void* ptr, unsigned int sz) {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
 
    // Find the memory
    for(int i = 0; i < mem->config.last_init_block; i++) {
        if((&(mem->mallocated_memory[i].memory)) == ptr) { // Our memory
            if (mem->mallocated_memory[i].used != 1) { // Should never happen
                mem->stats.invalid_realloc++;
                return 0;
            } else {
 
                // Check for corruptions before extending. Twice the severity, twice the errors
                for(int o = mem->mallocated_memory[i].sz; o < mem->MALLOC_MEM_BLOCK_SIZE; o++) {
                    if(mem->mallocated_memory[i].memory[o] != 0){
                        mem->stats.invalid_realloc++;
                        mem->stats.writes_beyond++;
                    }
                }
 
                for(int o = 0; o < mem->MALLOC_MEM_BLOCK_COUNT_PRE; o++) {
                    if(mem->mallocated_memory[i].memoryPre[o] != 0){
                        mem->stats.invalid_realloc++;
                        mem->stats.writes_before++;
                    }
                }
 
                for(int o = 0; o < mem->MALLOC_MEM_BLOCK_COUNT_POST; o++) {
                    if(mem->mallocated_memory[i].memoryPost[o] != 0){
                        mem->stats.invalid_realloc++;
                        mem->stats.writes_beyond++;
                    }
                }
 
                // No corruptions, check for size
                if(sz > (unsigned int) mem->MALLOC_MEM_BLOCK_SIZE) {
                    mem->stats.big_allocs++;
                    return 0;
                } else if( ((int)sz) < 0) {
                    mem->stats.negative_allocs++;
                    return 0;
                } else if(sz == 0) {
                    mem->stats.zero_allocs++;
                    return 0;
                }
 
                if (mem->mallocated_memory[i].sz < sz) { // Trimming -> zero fill the extension
                    for(unsigned int o = sz; o < mem->mallocated_memory[i].sz; o++) {
                        mem->mallocated_memory[i].memory[o] = 0;
                    }
                }
                mem->mallocated_memory[i].sz = sz;
                return &(mem->mallocated_memory[i].memory);
            }
        }
    }
 
    mem->stats.invalid_realloc++;
    return 0;
}
 
void* aligned_alloc(unsigned int alignment, unsigned int sz) {
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
    if(sz % alignment > 0) {
        mem->stats.negative_allocs++;
        return 0;
    }
 
    // lol, no
    return mem->functions.malloc(sz);
}
 
void init_memory_%RANDOM%() {
    // No memset
    char* data = (char*) &memory_%RANDOM%;
    for(unsigned int i = 0; i < sizeof(struct t_memory_%RANDOM%); i++) {
        data[i] = 0;
    }
 
    struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
    mem->MALLOC_MEM_BLOCK_COUNT = MALLOC_MEM_BLOCK_COUNT_%RANDOM%;
    mem->MALLOC_MEM_BLOCK_SIZE = MALLOC_MEM_BLOCK_SIZE_%RANDOM%;
    mem->MALLOC_MEM_BLOCK_COUNT_PRE = MALLOC_MEM_BLOCK_COUNT_PRE_%RANDOM%;
    mem->MALLOC_MEM_BLOCK_COUNT_POST = MALLOC_MEM_BLOCK_COUNT_POST_%RANDOM%;
 
    mem->functions.init_memory = &init_memory_%RANDOM%;
    mem->functions.check_memory_after_end = &check_memory_after_end_%RANDOM%;
    mem->functions.malloc_init_block = &malloc_init_block_%RANDOM%;
    mem->functions.malloc = &malloc;
    mem->functions.aligned_alloc = &aligned_alloc;
    mem->functions.realloc = &realloc;
    mem->functions.calloc = &calloc;
    mem->functions.free = &free;
 
    mem->userMain = &main;
}
 
#ifdef main
#undef main
#endif
 
// The real entry point
int main(int argc, char** argv) {
 
    // Init the memory
    init_memory_%RANDOM%();
     struct t_memory_%RANDOM%* mem = &memory_%RANDOM%;
 
    // Segfault by default
    int result = -1;
 
 
    if(argc >= 2) {
 
        // Read total number of allocations available
        if(mem->config.available_allocations < 0) {
            mem->config.available_allocations = mem->MALLOC_MEM_BLOCK_COUNT;
        }
 
        int argAllocations = 0;
        int sign = 1;
        for(int i = 0; argv[1][i] != '\0';i++){
            char c = argv[1][i];
            if(c >= '0' && c <= '9') {
                argAllocations *= 10;
                argAllocations += c - '0';
            } else if (c == '-') { // ... but why?
                sign = -1;
            }
        }
 
        // And add the one we are about to do
        argAllocations++;
        mem->config.available_allocations = argAllocations * sign;
 
        // Create new argv base on the original one without the first argument
        char** anotherArgv = (char**) malloc(sizeof(char*) * (argc - 1));
 
        // Copy file name
        anotherArgv[0] = argv[0];
 
        // And every argument after that
        for(int i = 2; i < argc; i++) {
            anotherArgv[i-1] = argv[i];
        }
 
        // Call user main
        result = mem->userMain(argc-1, anotherArgv);
 
        // Destroy our allocated argv
        free(anotherArgv);
 
        // Check memory for errors
        mem->functions.check_memory_after_end();
 
        return result;
    }
 
    return result;
}
 

Comments