#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