Files
kolibrios/programs/develop/ktcc/trunk/libc.obj/samples/malloc_test.c
Egor00f cb29ecffb7
All checks were successful
Build system / Check kernel codestyle (pull_request) Successful in 41s
Build system / Build (pull_request) Successful in 16m37s
libc.obj: fixes and optimizations for allocator && add new samples to sh build
fix: in `__mem_MERGE_MEM_NODES` `base->free = base->size`, its wrong.
forgot to set size for new block
optimization: add `__last_mem_node`. usually  its node with max free space among other nodes. firstly `malloc` try find space in it.
update(fix and optimizations) `realloc`.
now sdltest is working!
2026-02-04 12:42:00 +05:00

296 lines
8.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "../source/stdlib/_mem.h"
#define RUN_TEST(func) \
do { \
printf("---\tRUN TEST: %s\t---\n", #func); \
if (func()) { \
printf("[SUCCESS]\tTest %s is ok.\n\n", #func); \
} else { \
printf("[FAIL]\tTest %s failed.\n\n", #func); \
exit(EXIT_FAILURE); \
} \
} while (0)
// c behind 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]) {
printf("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)) {
printf("node %p in node %p", GET_MEM_NODE_HEADER(ptr[i]), GET_MEM_NODE_HEADER(ptr[j]));
// additional info
printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %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);
printf("node %p\nsize:%p\nfree:%p\nnext: %p\nlast: %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; // Нельзя проверить NULL
}
unsigned char *byte_ptr = (unsigned char *)ptr;
for (size_t i = 0; i < size; ++i) {
if (byte_ptr[i] != pattern) {
fprintf(stderr, "Ошибка: Байт %zu не соответствует паттерну. Ожидалось %02X, получено %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);
// Стандарт C11 (7.22.3.5) говорит, что realloc(ptr, 0) может вернуть NULL
// или указатель, который можно передать free().
// Если возвращается NULL, оригинальный указатель ptr все еще действителен и должен быть освобожден.
// Если возвращается не-NULL, оригинальный ptr недействителен, а новый ptr должен быть освобожден.
if (new_ptr == NULL) {
printf("realloc(ptr, 0) return NULL.\n");
free(ptr); // Освобождаем оригинальный ptr
} else {
printf("realloc(ptr, 0) return: %p.\n", new_ptr);
free(new_ptr); // Освобождаем новый 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;
}