#include #include // 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; }