Files
kolibrios/programs/develop/ktcc/trunk/libc.obj/samples/malloc_test.c

292 lines
7.0 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "../source/stdlib/_mem.h"
#define RUN_TEST(func) \
printf("---\tRUN TEST: %s\t---\n", #func); \
if (func()) { \
printf("[SUCCESS]\tTest %s is ok.\n\n", #func); \
} else { \
fprintf(stderr, "[FAIL]\tTest %s failed.\n\n", #func); \
exit(EXIT_FAILURE); \
}
// c between a and b
#define IN_RANGE(a, b, c, len) ((a > c && c > b) || ((a > c + len && c + len > b)))
bool test_malloc_basic_allocation()
{
void* ptr = malloc(sizeof(int));
if (ptr)
free(ptr);
return ptr;
}
bool test_malloc_zero_bytes()
{
return malloc(0) == NULL;
}
bool test_malloc_multiple_allocations()
{
void* ptr[512];
for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) {
ptr[i] = malloc(i);
if (ptr[i] == NULL) {
return false;
}
}
for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) {
for (int j = 1; j < sizeof(ptr) / sizeof(*ptr); j++) {
if (i != j) {
if (ptr[i] == ptr[j]) {
fprintf(stderr, "ptrs[%d] == ptrs[%d].\n", i, j);
return false;
} else if (IN_RANGE(
(char*)GET_MEM_NODE_HEADER(ptr[i]) + GET_MEM_NODE_HEADER(ptr[i])->size,
(char*)GET_MEM_NODE_HEADER(ptr[i]),
(char*)GET_MEM_NODE_HEADER(ptr[j]),
GET_MEM_NODE_HEADER(ptr[j])->size)) {
fprintf(stderr, "node %p in node %p", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[j]));
// additional info, may help with debug
fprintf(stderr, "node %p\n size:%p\n free:%p\n next: %p\n last: %p\n", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[i])->size, GET_MEM_NODE_HEADER(ptr[i])->free, GET_MEM_NODE_HEADER(ptr[i])->next, GET_MEM_NODE_HEADER(ptr[i])->last);
fprintf(stderr, "node %p\n size:%p\n free:%p\n next: %p\n last: %p\n", GET_MEM_NODE_HEADER(ptr[j]), GET_MEM_NODE_HEADER(ptr[j])->size, GET_MEM_NODE_HEADER(ptr[j])->free, GET_MEM_NODE_HEADER(ptr[j])->next, GET_MEM_NODE_HEADER(ptr[j])->last);
exit(EXIT_FAILURE);
}
}
}
}
for (int i = 1; i < sizeof(ptr) / sizeof(*ptr); i++) {
free(ptr[i]);
}
return true;
}
bool test_malloc_data_integrity()
{
const char* As = "AAA";
const char* Cs = "CCC";
char* A = (char*)malloc(10);
char* B = (char*)malloc(10);
char* C = (char*)malloc(10);
if (!A || !B || !C) {
printf("can't alloc\n");
free(A);
free(B);
free(C);
return false;
}
strcpy(A, As);
strcpy(C, Cs);
free(B);
if (strcmp(A, As) != 0) {
printf("A data is broken after free(B). A = '%s'\n", A);
free(A);
free(C);
return false;
}
if (strcmp(C, Cs) != 0) {
printf("C data is broken after free(B). C = '%s'\n", C);
free(A);
free(C);
return false;
}
free(A);
free(C);
return true;
}
bool test_malloc_large_allocation()
{
void* ptr = malloc(1024 * 1024 * 16); // alloc 16mb
if (ptr)
free(ptr);
return ptr;
}
bool test_malloc_allocation_and_free()
{
free(malloc(sizeof(int)));
return true;
}
void fill_buffer(void* ptr, size_t size, unsigned char pattern)
{
if (ptr) {
memset(ptr, pattern, size);
}
}
bool check_buffer(void* ptr, size_t size, unsigned char pattern)
{
if (!ptr) {
return false;
}
unsigned char* byte_ptr = (unsigned char*)ptr;
for (size_t i = 0; i < size; ++i) {
if (byte_ptr[i] != pattern) {
fprintf(stderr, "Error: Byte %zu does not match pattern. Expected %02X, got %02X\n",
i, pattern, byte_ptr[i]);
return false;
}
}
return true;
}
bool test_realloc_basic_grow()
{
size_t old_size = 10;
size_t new_size = 20;
int* ptr = (int*)malloc(old_size * sizeof(int));
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, old_size * sizeof(int), 0xAA);
int* new_ptr = (int*)realloc(ptr, new_size * sizeof(int));
if (new_ptr == NULL) {
free(ptr);
return false;
}
if (!check_buffer(new_ptr, old_size * sizeof(int), 0xAA)) {
free(new_ptr);
return false;
}
fill_buffer(new_ptr + old_size, (new_size - old_size) * sizeof(int), 0xBB);
if (!check_buffer(new_ptr + old_size, (new_size - old_size) * sizeof(int), 0xBB)) {
free(new_ptr);
return false;
}
free(new_ptr);
return true;
}
bool test_realloc_basic_shrink()
{
size_t old_size = 20;
size_t new_size = 10;
int* ptr = (int*)malloc(old_size * sizeof(int));
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, old_size * sizeof(int), 0xCC);
int* new_ptr = (int*)realloc(ptr, new_size * sizeof(int));
if (new_ptr == NULL) {
free(ptr);
return false;
}
if (!check_buffer(new_ptr, new_size * sizeof(int), 0xCC)) {
free(new_ptr);
return false;
}
free(new_ptr);
return true;
}
bool test_realloc_same_size()
{
size_t size = 15;
int* ptr = (int*)malloc(size * sizeof(int));
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, size * sizeof(int), 0xDD);
int* new_ptr = (int*)realloc(ptr, size * sizeof(int));
if (new_ptr == NULL) {
free(ptr);
return false;
}
if (!check_buffer(new_ptr, size * sizeof(int), 0xDD)) {
free(new_ptr);
return false;
}
free(new_ptr);
return true;
}
bool test_realloc_null_ptr()
{
size_t size = 25;
void* ptr = realloc(NULL, size);
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, size, 0xEE);
if (!check_buffer(ptr, size, 0xEE)) {
free(ptr);
return false;
}
free(ptr);
return true;
}
bool test_realloc_to_zero_size()
{
size_t old_size = 30;
void* ptr = malloc(old_size);
if (ptr == NULL) {
return false;
}
fill_buffer(ptr, old_size, 0xFF);
void* new_ptr = realloc(ptr, 0);
if (new_ptr == NULL) {
printf("realloc(ptr, 0) return NULL.\n");
free(ptr);
} else {
printf("realloc(ptr, 0) return: %p.\n", new_ptr);
free(new_ptr);
}
return true;
}
int main()
{
RUN_TEST(test_malloc_basic_allocation);
RUN_TEST(test_malloc_zero_bytes);
RUN_TEST(test_malloc_multiple_allocations);
RUN_TEST(test_malloc_data_integrity);
RUN_TEST(test_malloc_large_allocation);
RUN_TEST(test_malloc_basic_allocation);
RUN_TEST(test_malloc_allocation_and_free);
RUN_TEST(test_realloc_basic_grow);
RUN_TEST(test_realloc_basic_shrink);
RUN_TEST(test_realloc_same_size);
RUN_TEST(test_realloc_null_ptr);
RUN_TEST(test_realloc_to_zero_size);
return 0;
}