#import "malloc_test.h"
#import "auto_zone.h"
#import <libc.h>
#import <stdio.h>
#import <math.h>
#import <mach/mach_init.h>
#import <mach/message.h>
size_t _malloc_test_uniform_generator(unsigned context) {
if (!context) context = vm_page_size;
return random() % context;
}
size_t _malloc_test_healthy_mix_generator(unsigned context) {
unsigned rr = random() % 1000;
if (!context) context = 100 * vm_page_size;
if (rr < 200) return 16;
if (rr < 600) return 32;
if (rr < 900) return 48;
if (rr < 990) return _malloc_test_uniform_generator(context / 100);
if (rr < 999) return _malloc_test_uniform_generator(context / 10);
return random() % context;
}
size_t _malloc_test_constant_size(unsigned context) {
return context;
}
#define MAGIC1 0x12aef356
#define MAGIC2 0xfe235601
#if 1
#define SET_ALL_POINTERS(ptr) auto_zone_set_layout_type(auto_zone(), ptr, AUTO_MEMORY_SCANNED)
#define SET_NO_POINTERS(ptr) auto_zone_set_layout_type(auto_zone(), ptr, AUTO_MEMORY_UNSCANNED)
#else
#define SET_ALL_POINTERS(ptr) {}
#define SET_NO_POINTERS(ptr) {}
#endif
void filler(void *ptr, size_t size, void **ptrs_array, unsigned array_size) {
if (size < 8) return;
if (size & 3) {
unsigned class = _TEST_CLASS_ODD_SIZE;
unsigned *words = ptr;
words[0] = class;
} else if (size < _TEST_CLASS_PTR_ARRAY_AFTER - _TEST_CLASS_PTR_ARRAY) {
unsigned class = _TEST_CLASS_PTR_ARRAY + size;
unsigned *words = ptr;
SET_ALL_POINTERS(ptr);
words[0] = class;
words++; size -= 4;
while (size >= 4) {
void *ptr = (ptrs_array) ? ptrs_array[random() % array_size] : NULL;
words[0] = (unsigned)ptr;
words++; size -= 4;
}
} else if (random() & 1) {
unsigned class = _TEST_CLASS_NO_PTR;
unsigned *words = ptr;
SET_NO_POINTERS(ptr);
words[0] = class;
words[1] = MAGIC1;
words[(size-4)/4] = MAGIC2;
} else {
unsigned *words = ptr;
words[1] = random() << 4;
}
}
void _malloc_test_basic_loop(malloc_zone_t *zone, unsigned count, _malloc_test_size_generator_t size_generator, unsigned context) {
unsigned index = count;
while (index--) {
size_t size = size_generator(context);
void *ptr = malloc_zone_malloc(zone, size);
free(ptr);
}
}
void _malloc_test_increasing_reallocs(malloc_zone_t *zone, unsigned count, unsigned increment) {
unsigned size = 0;
char *ptr = NULL;
while (count--) {
size += increment;
ptr = malloc_zone_realloc(zone, ptr, size);
ptr[0] = 'A';
ptr[size-1] = 'Z';
}
malloc_zone_free(zone, ptr);
}
void _malloc_test_allocate_a_bunch_then_free(malloc_zone_t *zone, unsigned count, _malloc_test_size_generator_t size_generator, unsigned context) {
void **array = malloc_zone_calloc(zone, count, sizeof(void *));
size_t *sizes = malloc_zone_calloc(zone, count, sizeof(size_t));
unsigned index;
index = 0; while (index < count) {
sizes[index++] = size_generator(context);
}
index = 0; while (index < count) {
unsigned size = sizes[index];
unsigned msize;
void *ptr = malloc_zone_malloc(zone, size);
array[index] = ptr;
msize = malloc_size(ptr);
*((unsigned *)ptr) = msize;
index++;
}
index = count; while (index--) {
void *ptr = array[index];
unsigned size = malloc_size(ptr);
if (*((unsigned *)ptr) != size) {
printf("*** for %p recorded size was %d for requested %d; now malloc_size is %d\n", ptr, *((unsigned *)ptr), (unsigned)sizes[index], size);
}
malloc_zone_free(zone, ptr);
}
malloc_zone_free(zone, sizes);
malloc_zone_free(zone, array);
}
static boolean_t check_ptr(unsigned char *ptr) {
#if 0
unsigned size;
unsigned ix;
size = ((unsigned *)ptr)[0];
ix = 4;
if (size < 1000) while (ix < size) {
if (ptr[ix] != (ix & 0xff)) return 0;
ix++;
}
#endif
return 1;
}
void **_malloc_test_random_fill(malloc_zone_t *zone, size_t array_size, _malloc_test_size_generator_t size_generator, unsigned context, int fd) {
void **array;
unsigned num = 0;
array = malloc_zone_calloc(zone, array_size, 4);
if (fd) printf("\tvoid **array = malloc_zone_calloc(zone, %d, 4);\n", (int)array_size);
while (num < array_size) {
unsigned rr = random() % 8;
unsigned char *ptr;
unsigned size;
if (0) {
unsigned index = num;
while (index--) if (!check_ptr(array[index])) {
printf("*** Item at %d seems damaged; size=%d\n", index, ((unsigned *)array[index])[0]);
sleep(3600);
}
}
switch (rr) {
case 0:
case 1:
case 2:
case 3:
size = size_generator(context);
if (size < 4) size = 4;
if (fd) printf("\tarray[%d] = malloc_zone_malloc(zone, %d);\n", num, size);
ptr = malloc_zone_malloc(zone, size);
if (num) filler(ptr, size, array, num);
array[num++] = ptr;
break;
case 4:
case 5:
if (num) {
if (fd) printf("\tmalloc_zone_free(zone, array[%d]);\n", num-1);
ptr = array[--num];
if (!check_ptr(ptr)) {
printf("*** Item at %d seems damaged\n", num+1);
sleep(3600);
}
malloc_zone_free(zone, ptr);
}
break;
case 6: if (num) {
unsigned index = random() % num;
size = size_generator(context);
if (size < 4) size = 4;
if (fd) printf("\tarray[%d] = malloc_zone_realloc(zone, array[%d], %d);\n", index, index, size);
ptr = malloc_zone_realloc(zone, array[index], size);
if (num) filler(ptr, size, array, num);
array[index] = ptr;
}
break;
case 7:
if (num) {
unsigned index = random() % num;
malloc_size(array[index]);
}
break;
}
}
return array;
}
void _malloc_test_random_free(malloc_zone_t *zone, void **array, size_t num, int fd) {
while (num--) {
if (fd) printf("\tmalloc_zone_free(zone, array[%d]);\n", (unsigned)num);
if (array[num]) malloc_zone_free(zone, array[num]);
}
if (fd) printf("\tmalloc_zone_free(zone, array);\n");
malloc_zone_free(zone, array);
}
void **_malloc_test_worst_free_heap(malloc_zone_t *zone, size_t array_size, size_t item_size) {
void **array;
unsigned num = 0;
array = malloc_zone_calloc(zone, array_size, sizeof(void *));
while (num < array_size) {
array[num++] = malloc_zone_malloc(zone, item_size);
}
num = 0;
while (num < array_size) {
malloc_zone_free(zone, array[num]);
array[num] = NULL;
num += 2;
}
return array;
}
void _malloc_test_generational(malloc_zone_t *zone, unsigned allocation_budget, _malloc_test_size_generator_t size_generator, unsigned context) {
unsigned count = allocation_budget / 100;
void **old_gen = malloc_zone_calloc(zone, count, sizeof(void *));
void **new_gen = malloc_zone_calloc(zone, count, sizeof(void *));
unsigned index = 0;
while (index < count) {
size_t size = size_generator(context);
void *ptr = malloc_zone_malloc(zone, size);
filler(ptr, size, old_gen, count);
old_gen[index] = ptr;
index++;
}
unsigned gen = 0;
while (gen < 100) {
unsigned index = 0;
while (index < count) {
size_t size = size_generator(context);
void *ptr = malloc_zone_malloc(zone, size);
filler(ptr, size, old_gen, count);
new_gen[index] = ptr;
index++;
}
index = 0;
while (index < count) {
boolean_t old = (random() % 100) < 5;
malloc_zone_free(zone, (old) ? old_gen[index] : new_gen[index]);
if (old) old_gen[index] = new_gen[index];
index++;
}
gen++;
}
index = count; while (index--) {
malloc_zone_free(zone, old_gen[index]);
}
malloc_zone_free(zone, old_gen);
malloc_zone_free(zone, new_gen);
}
extern void **_malloc_test_create_network(malloc_zone_t *zone, _malloc_test_size_generator_t size_generator, unsigned count, float point_to_another, unsigned context) {
void **array = malloc_zone_calloc(zone, count, sizeof(void *));
unsigned index;
unsigned point_threshold = round((float)0xffff * point_to_another);
for (index = 0; index < count; index++) {
size_t size = size_generator(context);
void *ptr = malloc_zone_calloc(zone, size, 1);
array[index] = ptr;
if ((size >= 8) && ((random() & 0xffff) < point_threshold)) {
void *other = array[random() % (index+1)];
((void **)ptr)[1] = other;
}
}
return array;
}