├── .gitignore ├── src └── memory_interface │ ├── tests │ ├── test_default_strategy.h │ ├── test_default_strategy.c │ └── test_fuzz_default_strategy.c │ ├── memstats │ ├── tests │ │ ├── test_stats_report.c │ │ ├── test_memory_stats.c │ │ └── test_edge_cases.c │ ├── src │ │ └── stats_report.c │ ├── include │ │ ├── stats_report.h │ │ └── memory_stats.h │ ├── main.c │ ├── README.md │ └── Makefile │ ├── memstrategy │ ├── include │ │ ├── strategy_validator.h │ │ ├── memory_strategy.h │ │ ├── memory_pool_strategy.h │ │ └── strategy_status.h │ ├── src │ │ ├── strategy_validator.c │ │ ├── memory_strategy.c │ │ ├── strategy_status.c │ │ └── memory_pool_strategy.c │ ├── main.c │ ├── Makefile │ ├── test │ │ ├── strategy_test.c │ │ ├── memory_strategy_test.c │ │ ├── validator_test.c │ │ └── pool_strategy_test.c │ └── README.md │ ├── statetracker │ ├── examples │ │ └── main.c │ ├── Makefile │ ├── include │ │ └── strategy_status.h │ ├── README.md │ ├── test │ │ └── strategy_test.c │ └── src │ │ └── strategy_status.c │ ├── Makefile │ ├── main.c │ ├── src │ ├── default_strategy.h │ └── default_strategy.c │ └── README.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | tags 3 | 4 | # Prerequisites 5 | *.d 6 | 7 | # Object files 8 | *.o 9 | *.ko 10 | *.obj 11 | *.elf 12 | 13 | # Linker output 14 | *.ilk 15 | *.map 16 | *.exp 17 | 18 | # Precompiled Headers 19 | *.gch 20 | *.pch 21 | 22 | # Libraries 23 | *.lib 24 | *.a 25 | *.la 26 | *.lo 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | # Debug files 43 | *.dSYM/ 44 | *.su 45 | *.idb 46 | *.pdb 47 | 48 | # Kernel Module Compile Results 49 | *.mod* 50 | *.cmd 51 | .tmp_versions/ 52 | modules.order 53 | Module.symvers 54 | Mkfile.old 55 | dkms.conf 56 | -------------------------------------------------------------------------------- /src/memory_interface/tests/test_default_strategy.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_DEFAULT_STRATEGY_H 2 | #define TEST_DEFAULT_STRATEGY_H 3 | 4 | #include 5 | 6 | // clang-format off 7 | // Standard test suite functions 8 | bool test_strategy_creation(void); 9 | bool test_basic_allocation(void); 10 | bool test_concurrent_allocations(void); 11 | bool test_error_handling(void); 12 | bool test_memory_tracking(void); 13 | bool test_status_transitions(void); 14 | bool test_validation(void); 15 | bool test_peak_usage(void); 16 | 17 | // Fuzzing test functions 18 | void test_allocation_pattern_fuzzing(void); 19 | void test_edge_case_fuzzing(void); 20 | void run_fuzz_tests(void); 21 | 22 | // Test runners 23 | int run_default_strategy_tests(void); 24 | int run_all_tests(void); 25 | // clang-format on 26 | 27 | #endif // TEST_DEFAULT_STRATEGY_H 28 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/tests/test_stats_report.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../include/stats_report.h" 5 | 6 | void 7 | test_stats_report_to_string () 8 | { 9 | stats_report_t report = {.alloc_count = 100, 10 | .free_count = 90, 11 | .current_bytes = 1024, 12 | .peak_bytes = 2048}; 13 | 14 | const char *report_str = stats_report_to_string (&report); 15 | (void) report_str; 16 | 17 | assert (strstr (report_str, "100") != NULL); 18 | assert (strstr (report_str, "90") != NULL); 19 | assert (strstr (report_str, "1024") != NULL); 20 | assert (strstr (report_str, "2048") != NULL); 21 | 22 | const char *null_report = stats_report_to_string (NULL); 23 | (void) null_report; 24 | assert (strcmp (null_report, "Invalid report") == 0); 25 | 26 | printf ("Stats report string conversion test passed\n"); 27 | } 28 | 29 | int 30 | main (int argc, char **argv) 31 | { 32 | (void) argc; 33 | (void) argv; 34 | 35 | test_stats_report_to_string (); 36 | printf ("All stats report tests passed!\n"); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/include/strategy_validator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file strategy_validator.h 3 | * @brief Validation system for memory management strategies 4 | */ 5 | 6 | #ifndef MEMORY_STRATEGY_VALIDATOR_H_ 7 | #define MEMORY_STRATEGY_VALIDATOR_H_ 8 | 9 | #include 10 | #include 11 | 12 | struct MemoryStrategy; 13 | 14 | /** 15 | * @brief Validates strategy health and contract compliance 16 | * @param strategy Pointer to memory strategy 17 | * @return true if strategy is valid and follows interface contract 18 | */ 19 | bool 20 | validate_strategy (const struct MemoryStrategy *strategy); 21 | 22 | /** 23 | * @brief Validates allocation request parameters 24 | * @param strategy Pointer to memory strategy 25 | * @param size Requested allocation size 26 | * @return true if allocation request is valid 27 | */ 28 | bool 29 | validate_allocation (const struct MemoryStrategy *strategy, size_t size); 30 | 31 | /** 32 | * @brief Validates deallocation request parameters 33 | * @param strategy Pointer to memory strategy 34 | * @param ptr Pointer to memory for deallocation 35 | * @return true if deallocation request is valid 36 | */ 37 | bool 38 | validate_deallocation (const struct MemoryStrategy *strategy, const void *ptr); 39 | 40 | #endif /* MEMORY_STRATEGY_VALIDATOR_H_ */ 41 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/include/memory_strategy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file memory_strategy.h 3 | * @brief Memory management strategy interface 4 | */ 5 | 6 | #ifndef MEMORY_STRATEGY_H_ 7 | #define MEMORY_STRATEGY_H_ 8 | 9 | #include "strategy_status.h" 10 | #include 11 | #include 12 | 13 | /** 14 | * @brief Memory strategy interface 15 | * @note All implementations must provide thread-safe operations 16 | */ 17 | typedef struct MemoryStrategy 18 | { 19 | /* Core operations */ 20 | void *(*allocate) (struct MemoryStrategy *self, size_t size); 21 | void (*deallocate) (struct MemoryStrategy *self, void *ptr); 22 | StrategyStatus (*get_status) (struct MemoryStrategy *self); 23 | bool (*validate) (struct MemoryStrategy *self); 24 | 25 | /* Internal state */ 26 | StatusTracker *status_tracker; /**< Thread-safe status tracking */ 27 | void *strategy_data; /**< Implementation-specific data */ 28 | } MemoryStrategy; 29 | 30 | /** 31 | * @brief Initialize a memory strategy 32 | * @param strategy Pointer to strategy to initialize 33 | * @return true if initialization successful, false otherwise 34 | */ 35 | bool 36 | initialize_strategy (MemoryStrategy *strategy); 37 | 38 | /** 39 | * @brief Clean up a memory strategy 40 | * @param strategy Pointer to strategy to cleanup 41 | */ 42 | void 43 | cleanup_strategy (MemoryStrategy *strategy); 44 | 45 | #endif /* MEMORY_STRATEGY_H_ */ 46 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/src/strategy_validator.c: -------------------------------------------------------------------------------- 1 | #include "strategy_validator.h" 2 | #include "memory_strategy.h" 3 | #include 4 | #include 5 | 6 | // clang-format off 7 | static bool validate_function_pointers(const MemoryStrategy* strategy); 8 | static bool validate_state(const MemoryStrategy* strategy); 9 | static bool validate_size(size_t size); 10 | static bool validate_pointer(const void* ptr); 11 | // clang-format on 12 | 13 | static bool 14 | validate_function_pointers (const MemoryStrategy *strategy) 15 | { 16 | return strategy->allocate && strategy->deallocate && strategy->get_status 17 | && strategy->validate; 18 | } 19 | 20 | static bool 21 | validate_state (const MemoryStrategy *strategy) 22 | { 23 | if (!strategy->status_tracker) 24 | { 25 | return false; 26 | } 27 | 28 | StrategyStatus current; 29 | if (get_current_status (strategy->status_tracker, ¤t) 30 | != STRATEGY_SUCCESS) 31 | { 32 | return false; 33 | } 34 | 35 | return current == STRATEGY_STATE_ACTIVE; 36 | } 37 | 38 | static bool 39 | validate_size (size_t size) 40 | { 41 | return size > 0 && size <= SIZE_MAX / 2; 42 | } 43 | 44 | static bool 45 | validate_pointer (const void *ptr) 46 | { 47 | return ptr != NULL && ((uintptr_t) ptr % sizeof (void *) == 0); 48 | } 49 | 50 | bool 51 | validate_strategy (const MemoryStrategy *strategy) 52 | { 53 | if (!strategy) 54 | { 55 | return false; 56 | } 57 | 58 | return validate_function_pointers (strategy) && validate_state (strategy); 59 | } 60 | 61 | bool 62 | validate_allocation (const MemoryStrategy *strategy, size_t size) 63 | { 64 | if (!strategy) 65 | { 66 | return false; 67 | } 68 | 69 | return validate_state (strategy) && validate_size (size); 70 | } 71 | 72 | bool 73 | validate_deallocation (const MemoryStrategy *strategy, const void *ptr) 74 | { 75 | if (!strategy) 76 | { 77 | return false; 78 | } 79 | 80 | return validate_state (strategy) && validate_pointer (ptr); 81 | } 82 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/src/stats_report.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stats_report.c 3 | * @brief Implementation of memory statistics reporting functionality 4 | */ 5 | 6 | #include "../include/stats_report.h" 7 | #include 8 | #include 9 | 10 | /** Size of the static report buffer */ 11 | #define REPORT_BUFFER_SIZE 4096 12 | 13 | /** Static buffer for report string generation */ 14 | static char report_buffer[REPORT_BUFFER_SIZE]; 15 | 16 | const char * 17 | stats_report_to_string (const stats_report_t *report) 18 | { 19 | if (!report) 20 | return "Invalid report"; 21 | 22 | int offset 23 | = snprintf (report_buffer, REPORT_BUFFER_SIZE, 24 | "Memory Statistics Report\n" 25 | "=====================\n" 26 | "Basic Statistics:\n" 27 | " Allocations: %lu\n" 28 | " Deallocations: %lu\n" 29 | " Current Memory: %zu bytes\n" 30 | " Peak Memory: %zu bytes\n" 31 | "\nPattern Analysis:\n" 32 | " Average Size: %.2f bytes\n" 33 | " Alloc Rate: %lu/sec\n" 34 | "\nSize Distribution:\n", 35 | report->alloc_count, report->free_count, report->current_bytes, 36 | report->peak_bytes, report->avg_allocation_size, 37 | report->allocation_frequency); 38 | 39 | for (int i = 0; i < STATS_SIZE_BUCKET_COUNT && offset < REPORT_BUFFER_SIZE; 40 | i++) 41 | { 42 | offset += snprintf (report_buffer + offset, REPORT_BUFFER_SIZE - offset, 43 | " ≤ %zu bytes: %lu allocations\n", 44 | report->size_distribution[i].threshold, 45 | report->size_distribution[i].count); 46 | } 47 | 48 | if (offset < REPORT_BUFFER_SIZE) 49 | { 50 | offset 51 | += snprintf (report_buffer + offset, REPORT_BUFFER_SIZE - offset, 52 | "\nLeak Detection:\n" 53 | " Active Allocations: %u\n" 54 | " Total Leaked: %zu bytes\n", 55 | report->active_allocation_count, report->total_leaked_bytes); 56 | 57 | if (report->leak_count > 0) 58 | { 59 | offset += snprintf (report_buffer + offset, REPORT_BUFFER_SIZE - offset, 60 | " Detected Leaks: %u\n", report->leak_count); 61 | } 62 | } 63 | 64 | report_buffer[REPORT_BUFFER_SIZE - 1] = '\0'; 65 | 66 | return report_buffer; 67 | } 68 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main.c 3 | * @brief Example usage of the memory management strategy API 4 | */ 5 | 6 | #include "include/memory_strategy.h" 7 | #include "include/memory_pool_strategy.h" 8 | #include 9 | #include 10 | 11 | #define ALLOCATION_SIZE 1024 12 | #define SMALL_ALLOC 64 13 | 14 | int 15 | main (void) 16 | { 17 | // Create and initialize pool strategy 18 | MemoryStrategy *strategy = create_pool_strategy (); 19 | if (!strategy) 20 | { 21 | fprintf (stderr, "Failed to create memory pool strategy\n"); 22 | return 1; 23 | } 24 | 25 | // Verify strategy is active 26 | if (strategy->get_status (strategy) != STRATEGY_STATE_ACTIVE) 27 | { 28 | fprintf (stderr, "Strategy initialization failed\n"); 29 | destroy_pool_strategy (strategy); 30 | return 1; 31 | } 32 | 33 | printf ("Memory pool strategy initialized successfully\n"); 34 | 35 | // Test allocation 36 | void *ptr = strategy->allocate (strategy, ALLOCATION_SIZE); 37 | if (!ptr) 38 | { 39 | fprintf (stderr, "Memory allocation failed\n"); 40 | destroy_pool_strategy (strategy); 41 | return 1; 42 | } 43 | 44 | // Use the allocated memory 45 | memset (ptr, 0xAA, ALLOCATION_SIZE); 46 | printf ("Successfully allocated and wrote to %zu bytes\n", 47 | (size_t) ALLOCATION_SIZE); 48 | 49 | // Multiple small allocations 50 | void *small_ptrs[5]; 51 | for (int i = 0; i < 5; i++) 52 | { 53 | small_ptrs[i] = strategy->allocate (strategy, SMALL_ALLOC); 54 | if (!small_ptrs[i]) 55 | { 56 | fprintf (stderr, "Small allocation %d failed\n", i); 57 | destroy_pool_strategy (strategy); 58 | return 1; 59 | } 60 | memset (small_ptrs[i], i, SMALL_ALLOC); 61 | } 62 | printf ("Successfully performed 5 small allocations\n"); 63 | 64 | // Deallocate memory 65 | strategy->deallocate (strategy, ptr); 66 | for (int i = 0; i < 5; i++) 67 | { 68 | strategy->deallocate (strategy, small_ptrs[i]); 69 | } 70 | printf ("Successfully deallocated all memory\n"); 71 | 72 | // Cleanup 73 | destroy_pool_strategy (strategy); 74 | printf ("Memory pool strategy destroyed successfully\n"); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /src/memory_interface/statetracker/examples/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "./include/strategy_status.h" 6 | 7 | #define NUM_WORKER_THREADS 4 8 | #define ITERATIONS_PER_THREAD 5 9 | 10 | void 11 | print_status (const StatusTracker *tracker) 12 | { 13 | StrategyStatus current; 14 | uint64_t transitions, errors; 15 | 16 | if (get_current_status (tracker, ¤t) == STRATEGY_SUCCESS 17 | && get_transition_count (tracker, &transitions) == STRATEGY_SUCCESS 18 | && get_error_count (tracker, &errors) == STRATEGY_SUCCESS) 19 | { 20 | printf ("Current Status: %s\n", get_state_string (current)); 21 | printf ("Total Transitions: %lu\n", transitions); 22 | printf ("Total Errors: %lu\n\n", errors); 23 | } 24 | } 25 | 26 | void * 27 | worker_thread (void *arg) 28 | { 29 | StatusTracker *tracker = (StatusTracker *) arg; 30 | 31 | for (int i = 0; i < ITERATIONS_PER_THREAD; i++) 32 | { 33 | if (transition_status (tracker, STRATEGY_STATE_ACTIVE) == STRATEGY_SUCCESS) 34 | { 35 | usleep (100000); // Simulate work 36 | 37 | if (rand () % 4 == 0) 38 | { // 25% chance of error 39 | transition_status (tracker, STRATEGY_STATE_ERROR); 40 | usleep (50000); 41 | } 42 | 43 | transition_status (tracker, STRATEGY_STATE_INITIALIZED); 44 | } 45 | } 46 | 47 | return NULL; 48 | } 49 | 50 | int 51 | main (void) 52 | { 53 | StatusTracker tracker; 54 | pthread_t threads[NUM_WORKER_THREADS]; 55 | 56 | printf ("Thread-Safe State Management Demo\n"); 57 | printf ("================================\n\n"); 58 | 59 | if (initialize_status (&tracker) != STRATEGY_SUCCESS) 60 | { 61 | fprintf (stderr, "Failed to initialize tracker\n"); 62 | return 1; 63 | } 64 | 65 | printf ("Initial state:\n"); 66 | print_status (&tracker); 67 | 68 | for (int i = 0; i < NUM_WORKER_THREADS; i++) 69 | { 70 | if (pthread_create (&threads[i], NULL, worker_thread, &tracker) != 0) 71 | { 72 | fprintf (stderr, "Failed to create thread %d\n", i); 73 | return 1; 74 | } 75 | } 76 | 77 | for (int i = 0; i < NUM_WORKER_THREADS; i++) 78 | pthread_join (threads[i], NULL); 79 | 80 | printf ("Final state:\n"); 81 | print_status (&tracker); 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/Makefile: -------------------------------------------------------------------------------- 1 | # Compiler settings 2 | CC = gcc 3 | CFLAGS = -Wall -Wextra -Wunused -Wunreachable-code -Werror -std=c11 -I./include -g 4 | LDFLAGS = -pthread 5 | 6 | # Directories 7 | SRC_DIR = src 8 | INC_DIR = include 9 | TEST_DIR = test 10 | BUILD_DIR = build 11 | LIB_DIR = lib 12 | 13 | # Source files 14 | SRC_FILES = $(wildcard $(SRC_DIR)/*.c) 15 | OBJ_FILES = $(SRC_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) 16 | 17 | # Test files 18 | TEST_FILES = $(wildcard $(TEST_DIR)/*.c) 19 | TEST_BINS = $(TEST_FILES:$(TEST_DIR)/%.c=$(BUILD_DIR)/%) 20 | 21 | # Output files 22 | LIB_NAME = libmemstrategy.a 23 | # Build the library into the build folder 24 | LIB_FILE = $(BUILD_DIR)/$(LIB_NAME) 25 | EXAMPLE_EXEC = example 26 | 27 | # Targets 28 | .PHONY: all clean test example install help 29 | 30 | all: $(LIB_FILE) $(TEST_BINS) $(EXAMPLE_EXEC) 31 | 32 | # Create required directory (only BUILD_DIR is needed for normal build) 33 | $(BUILD_DIR): 34 | @mkdir -p $@ 35 | 36 | # Build library object files 37 | $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) 38 | @echo "Compiling $<..." 39 | $(CC) $(CFLAGS) -c $< -o $@ 40 | 41 | # Build static library (built in BUILD_DIR) 42 | $(LIB_FILE): $(OBJ_FILES) | $(BUILD_DIR) 43 | @echo "Creating static library $(LIB_NAME)..." 44 | ar rcs $@ $^ 45 | 46 | # Build test executables (linking against the library in BUILD_DIR) 47 | $(BUILD_DIR)/%: $(TEST_DIR)/%.c $(LIB_FILE) | $(BUILD_DIR) 48 | @echo "Linking test executable $@..." 49 | $(CC) $(CFLAGS) $< -L$(BUILD_DIR) -lmemstrategy -o $@ $(LDFLAGS) 50 | 51 | # Build example program (linking against the library in BUILD_DIR) 52 | $(EXAMPLE_EXEC): main.c $(LIB_FILE) | $(BUILD_DIR) 53 | @echo "Building example program..." 54 | $(CC) $(CFLAGS) -L$(BUILD_DIR) main.c -o $@ $(LDFLAGS) -lmemstrategy 55 | 56 | test: $(TEST_BINS) 57 | @echo "Running all tests..." 58 | @for test in $(TEST_BINS); do \ 59 | echo "\nRunning $$test:"; \ 60 | ./$$test; \ 61 | done 62 | 63 | # Install target: copies the library and headers into LIB_DIR 64 | install: $(LIB_FILE) 65 | @echo "Installing $(LIB_NAME) and headers into $(LIB_DIR)..." 66 | @mkdir -p $(LIB_DIR) 67 | @cp $(LIB_FILE) $(LIB_DIR)/ 68 | @cp -r $(INC_DIR)/* $(LIB_DIR)/ 69 | @echo "Installation complete: $(LIB_DIR)/$(LIB_NAME) and header files copied." 70 | 71 | clean: 72 | @echo "Cleaning build artifacts..." 73 | @rm -rf $(BUILD_DIR) $(LIB_DIR) $(EXAMPLE_EXEC) $(TEST_BINS) 74 | 75 | help: 76 | @echo "Available targets:" 77 | @echo " all - Build library, tests, and example program" 78 | @echo " test - Run all tests" 79 | @echo " example - Build the example program" 80 | @echo " install - Copy library and header files into ./lib" 81 | @echo " clean - Remove build artifacts" 82 | @echo " help - Show this help message" 83 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/test/strategy_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file strategy_test.c 3 | * @brief Test suite for memory strategy implementation 4 | */ 5 | 6 | #include "memory_strategy.h" 7 | #include "memory_pool_strategy.h" 8 | #include "strategy_validator.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define NUM_THREADS 4 15 | #define TEST_ALLOC_SIZE 1024 16 | #define SMALL_ALLOC_SIZE 64 17 | #define NUM_ALLOCATIONS 10 18 | 19 | static void * 20 | thread_pool_test_func (void *arg) 21 | { 22 | MemoryStrategy *strategy = (MemoryStrategy *) arg; 23 | void *ptrs[NUM_ALLOCATIONS]; 24 | 25 | // Test multiple small allocations 26 | for (int i = 0; i < NUM_ALLOCATIONS; i++) 27 | { 28 | ptrs[i] = strategy->allocate (strategy, SMALL_ALLOC_SIZE); 29 | assert (ptrs[i] != NULL); 30 | 31 | // Write to memory to test usability 32 | memset (ptrs[i], i, SMALL_ALLOC_SIZE); 33 | } 34 | 35 | // Test validation 36 | assert (strategy->validate (strategy)); 37 | 38 | // Test status 39 | assert (strategy->get_status (strategy) == STRATEGY_STATE_ACTIVE); 40 | 41 | // Test deallocation 42 | for (int i = 0; i < NUM_ALLOCATIONS; i++) 43 | { 44 | strategy->deallocate (strategy, ptrs[i]); 45 | } 46 | 47 | return NULL; 48 | } 49 | 50 | static void 51 | test_thread_safety (MemoryStrategy *strategy) 52 | { 53 | pthread_t threads[NUM_THREADS]; 54 | 55 | for (int i = 0; i < NUM_THREADS; i++) 56 | { 57 | assert (pthread_create (&threads[i], NULL, thread_pool_test_func, strategy) 58 | == 0); 59 | } 60 | 61 | for (int i = 0; i < NUM_THREADS; i++) 62 | { 63 | assert (pthread_join (threads[i], NULL) == 0); 64 | } 65 | } 66 | 67 | static void 68 | run_tests (void) 69 | { 70 | // Test pool strategy 71 | MemoryStrategy *pool_strategy = create_pool_strategy (); 72 | assert (pool_strategy != NULL); 73 | 74 | // Test basic operations 75 | void *ptr = pool_strategy->allocate (pool_strategy, TEST_ALLOC_SIZE); 76 | assert (ptr != NULL); 77 | assert (pool_strategy->validate (pool_strategy)); 78 | 79 | // Test memory usage 80 | memset (ptr, 0xAA, TEST_ALLOC_SIZE); 81 | unsigned char *check = (unsigned char *) ptr; 82 | for (size_t i = 0; i < TEST_ALLOC_SIZE; i++) 83 | { 84 | assert (check[i] == 0xAA); 85 | } 86 | 87 | pool_strategy->deallocate (pool_strategy, ptr); 88 | 89 | // Test thread safety 90 | test_thread_safety (pool_strategy); 91 | 92 | // Test error handling 93 | assert (!pool_strategy->allocate (pool_strategy, 94 | POOL_BLOCK_SIZE * POOL_BLOCK_COUNT * 2)); 95 | 96 | // Test cleanup 97 | destroy_pool_strategy (pool_strategy); 98 | 99 | printf ("All tests passed successfully!\n"); 100 | } 101 | 102 | int 103 | main (void) 104 | { 105 | run_tests (); 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/src/memory_strategy.c: -------------------------------------------------------------------------------- 1 | #include "memory_strategy.h" 2 | #include "strategy_validator.h" 3 | #include 4 | #include 5 | 6 | static void * 7 | default_allocate (MemoryStrategy *self, size_t size); 8 | static void 9 | default_deallocate (MemoryStrategy *self, void *ptr); 10 | static StrategyStatus 11 | default_get_status (MemoryStrategy *self); 12 | static bool 13 | default_validate (MemoryStrategy *self); 14 | 15 | static void * 16 | default_allocate (MemoryStrategy *self, size_t size) 17 | { 18 | if (!validate_allocation (self, size)) 19 | { 20 | transition_status (self->status_tracker, STRATEGY_STATE_ERROR); 21 | return NULL; 22 | } 23 | 24 | void *ptr = malloc (size); 25 | if (!ptr) 26 | { 27 | transition_status (self->status_tracker, STRATEGY_STATE_ERROR); 28 | } 29 | return ptr; 30 | } 31 | 32 | static void 33 | default_deallocate (MemoryStrategy *self, void *ptr) 34 | { 35 | if (!validate_deallocation (self, ptr)) 36 | { 37 | transition_status (self->status_tracker, STRATEGY_STATE_ERROR); 38 | return; 39 | } 40 | free (ptr); 41 | } 42 | 43 | static StrategyStatus 44 | default_get_status (MemoryStrategy *self) 45 | { 46 | StrategyStatus status; 47 | if (!self || !self->status_tracker 48 | || get_current_status (self->status_tracker, &status) != STRATEGY_SUCCESS) 49 | { 50 | return STRATEGY_STATE_ERROR; 51 | } 52 | return status; 53 | } 54 | 55 | static bool 56 | default_validate (MemoryStrategy *self) 57 | { 58 | return validate_strategy (self); 59 | } 60 | 61 | bool 62 | initialize_strategy (MemoryStrategy *strategy) 63 | { 64 | if (!strategy) 65 | { 66 | return false; 67 | } 68 | 69 | strategy->status_tracker = malloc (sizeof (StatusTracker)); 70 | if (!strategy->status_tracker) 71 | { 72 | return false; 73 | } 74 | 75 | if (initialize_status (strategy->status_tracker) != STRATEGY_SUCCESS) 76 | { 77 | free (strategy->status_tracker); 78 | return false; 79 | } 80 | 81 | strategy->allocate = default_allocate; 82 | strategy->deallocate = default_deallocate; 83 | strategy->get_status = default_get_status; 84 | strategy->validate = default_validate; 85 | strategy->strategy_data = NULL; 86 | 87 | if (transition_status (strategy->status_tracker, STRATEGY_STATE_ACTIVE) 88 | != STRATEGY_SUCCESS) 89 | { 90 | free (strategy->status_tracker); 91 | return false; 92 | } 93 | 94 | return true; 95 | } 96 | 97 | void 98 | cleanup_strategy (MemoryStrategy *strategy) 99 | { 100 | if (!strategy) 101 | { 102 | return; 103 | } 104 | 105 | if (strategy->status_tracker) 106 | { 107 | free (strategy->status_tracker); 108 | } 109 | 110 | if (strategy->strategy_data) 111 | { 112 | free (strategy->strategy_data); 113 | } 114 | 115 | memset (strategy, 0, sizeof (MemoryStrategy)); 116 | } 117 | -------------------------------------------------------------------------------- /src/memory_interface/Makefile: -------------------------------------------------------------------------------- 1 | # Top-level Makefile for building and organizing libraries 2 | 3 | # Compiler and flags 4 | CC := gcc 5 | CFLAGS := -Wall -Wextra -pthread -fPIC 6 | LDFLAGS := -pthread 7 | INCLUDE_DIR := $(LIBRARY_DIR) 8 | LIB_FLAGS := -lmemstats -lmemstrategy -lstatetracker 9 | 10 | # Directories 11 | MODULES := memstats memstrategy statetracker 12 | LIBRARY_DIR := library 13 | BUILD_DIR := build 14 | TEST_DIR := tests 15 | SRC_DIR := src 16 | 17 | # Source files (move these up before they're used) 18 | SRC_FILES := $(wildcard $(SRC_DIR)/*.c) 19 | TEST_SRCS := $(wildcard $(TEST_DIR)/*.c) 20 | 21 | # Additional directories and variables 22 | LIB_DIR := lib 23 | OBJ_DIR := $(BUILD_DIR)/obj 24 | LIBRARY_NAME := libdefault_strategy.a 25 | LIBRARY_OUTPUT := $(LIB_DIR)/$(LIBRARY_NAME) 26 | OBJECTS := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRC_FILES)) 27 | 28 | # Output files 29 | TEST_RUNNER := $(BUILD_DIR)/test_runner 30 | 31 | # Add main executable variables (updated path) 32 | MAIN_SRC := main.c 33 | MAIN_OBJ := $(OBJ_DIR)/main.o 34 | MAIN_EXE := $(BUILD_DIR)/memory_interface 35 | 36 | # Phony targets 37 | .PHONY: all clean install $(MODULES) test check lib main 38 | 39 | # Default target 40 | all: install test main 41 | 42 | # Create necessary directories (updated) 43 | $(BUILD_DIR) $(LIBRARY_DIR) $(LIB_DIR) $(OBJ_DIR): 44 | mkdir -p $@ 45 | 46 | # Install target - creates library directory and builds all modules 47 | install: $(LIBRARY_DIR) $(MODULES) 48 | cp memstats/lib/*.a memstats/lib/*.h $(LIBRARY_DIR)/ 49 | cp memstrategy/lib/*.a memstrategy/lib/*.h $(LIBRARY_DIR)/ 50 | cp statetracker/lib/*.a statetracker/lib/*.h $(LIBRARY_DIR)/ 51 | 52 | # Module targets 53 | $(MODULES): 54 | $(MAKE) -C $@ install 55 | 56 | # Clean target 57 | clean: 58 | rm -rf $(LIBRARY_DIR) $(BUILD_DIR) ${LIB_DIR} 59 | for dir in $(MODULES); do \ 60 | $(MAKE) -C $$dir clean; \ 61 | done 62 | 63 | # Object file compilation - fixed include paths 64 | $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR) 65 | $(CC) $(CFLAGS) -I$(LIBRARY_DIR) -I$(SRC_DIR) -c $< -o $@ 66 | 67 | # Library target (updated) 68 | .PHONY: lib 69 | lib: install $(OBJECTS) 70 | mkdir -p $(LIB_DIR) 71 | ar rcs $(LIBRARY_OUTPUT) $(OBJECTS) 72 | cp $(SRC_DIR)/*.h $(LIB_DIR)/ 73 | 74 | # Build the default strategy test 75 | test: $(BUILD_DIR) install 76 | $(CC) $(CFLAGS) \ 77 | -I$(LIBRARY_DIR) \ 78 | -I$(INCLUDE_DIR) \ 79 | -I$(SRC_DIR) \ 80 | $(SRC_FILES) \ 81 | $(TEST_SRCS) \ 82 | -L$(LIBRARY_DIR) \ 83 | $(LIB_FLAGS) \ 84 | -o $(TEST_RUNNER) 85 | 86 | # Add main target 87 | main: $(MAIN_EXE) 88 | 89 | $(MAIN_EXE): $(MAIN_OBJ) lib 90 | $(CC) $(CFLAGS) -o $@ $(MAIN_OBJ) \ 91 | -L$(LIB_DIR) -ldefault_strategy \ 92 | -L$(LIBRARY_DIR) $(LIB_FLAGS) 93 | 94 | # Update main object compilation rule 95 | $(MAIN_OBJ): $(MAIN_SRC) | $(OBJ_DIR) 96 | $(CC) $(CFLAGS) -I$(LIBRARY_DIR) -I$(SRC_DIR) -c $< -o $@ 97 | 98 | # Run tests 99 | check: test 100 | ./$(TEST_RUNNER) 101 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/include/stats_report.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stats_report.h 3 | * @brief Memory statistics reporting functionality 4 | * 5 | * This header defines structures and functions for reporting memory statistics, 6 | * including allocation patterns, memory leaks, and usage trends. 7 | * 8 | * @copyright 7etsuo (c) 2025 9 | */ 10 | 11 | #ifndef MEMORY_STATS_REPORT_H_ 12 | #define MEMORY_STATS_REPORT_H_ 13 | 14 | #include 15 | #include 16 | 17 | /** 18 | * Maximum number of size buckets for allocation distribution 19 | */ 20 | #define STATS_SIZE_BUCKET_COUNT 8 21 | 22 | /** 23 | * Maximum number of leaks to track in a report 24 | */ 25 | #define STATS_MAX_LEAK_REPORTS 100 26 | 27 | /** 28 | * @brief Information about a detected memory leak 29 | */ 30 | typedef struct stats_leak_info 31 | { 32 | void *address; /**< Leaked memory address */ 33 | size_t size; /**< Size of leaked allocation in bytes */ 34 | const char *file; /**< Source file where allocation occurred */ 35 | int line; /**< Line number where allocation occurred */ 36 | uint64_t timestamp; /**< Time of allocation (unix timestamp) */ 37 | } stats_leak_info_t; 38 | 39 | /** 40 | * @brief Size distribution bucket information 41 | */ 42 | typedef struct stats_size_bucket 43 | { 44 | size_t threshold; /**< Upper bound of size bucket in bytes */ 45 | uint64_t count; /**< Number of allocations in this bucket */ 46 | } stats_size_bucket_t; 47 | 48 | /** 49 | * @brief Comprehensive memory statistics report 50 | */ 51 | typedef struct stats_report 52 | { 53 | /* Basic allocation statistics */ 54 | uint64_t alloc_count; /**< Total number of allocations */ 55 | uint64_t free_count; /**< Total number of deallocations */ 56 | size_t current_bytes; /**< Currently allocated bytes */ 57 | size_t peak_bytes; /**< Peak allocated bytes */ 58 | 59 | /* Pattern analysis */ 60 | stats_size_bucket_t size_distribution[STATS_SIZE_BUCKET_COUNT]; /**< 61 | Distribution of allocation sizes */ 62 | double avg_allocation_size; /**< Average allocation size in bytes */ 63 | uint64_t allocation_frequency; /**< Allocations per second */ 64 | 65 | /* Leak detection */ 66 | uint32_t 67 | active_allocation_count; /**< Number of active (unfreed) allocations */ 68 | size_t total_leaked_bytes; /**< Total bytes from unfreed allocations */ 69 | stats_leak_info_t 70 | leaks[STATS_MAX_LEAK_REPORTS]; /**< Details of detected leaks */ 71 | uint32_t leak_count; /**< Number of leaks in the report */ 72 | } stats_report_t; 73 | 74 | // clang-format off 75 | /** 76 | * @brief Convert stats report to a human-readable string representation 77 | * 78 | * @param report Pointer to stats_report structure to convert 79 | * @return Pointer to statically allocated string containing the report. 80 | * Returns "Invalid report" if report is NULL. 81 | * @note The returned string is valid until the next call to this function 82 | */ 83 | const char *stats_report_to_string(const stats_report_t *report); 84 | // clang-format on 85 | 86 | #endif /* MEMORY_STATS_REPORT_H_ */ 87 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/include/memory_pool_strategy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file memory_pool_strategy.h 3 | * @brief Memory pool implementation of the memory strategy interface 4 | * @security Thread-safe, bounds-checked, overflow-protected 5 | */ 6 | 7 | #ifndef MEMORY_POOL_STRATEGY_H_ 8 | #define MEMORY_POOL_STRATEGY_H_ 9 | 10 | #include "memory_strategy.h" 11 | #include 12 | #include 13 | #include 14 | 15 | /* Memory Pool Configuration Constants */ 16 | /** 17 | * @brief Core memory block configuration 18 | * @security All constants are power of 2 to prevent integer overflow in 19 | * calculations 20 | */ 21 | enum PoolConfig 22 | { 23 | POOL_BLOCK_SIZE = 256, /**< Size of each memory block in bytes */ 24 | POOL_BLOCK_COUNT = 1024, /**< Total number of blocks in the pool */ 25 | BLOCKS_PER_BITMAP = 64, /**< Number of blocks tracked per bitmap word */ 26 | MAX_ALLOCATION_RETRIES = 3 /**< Maximum retries for failed allocations */ 27 | }; 28 | 29 | /** 30 | * @brief Memory allocation size limits 31 | * @security Prevents integer overflow in size calculations 32 | */ 33 | enum PoolSizeLimits 34 | { 35 | POOL_MIN_ALLOCATION = sizeof (void *), /**< Minimum allocation size */ 36 | POOL_METADATA_SIZE = sizeof (size_t), /**< Size of block metadata */ 37 | POOL_MAX_ALLOCATION 38 | = (POOL_BLOCK_SIZE * (POOL_BLOCK_COUNT / 2) - POOL_METADATA_SIZE) 39 | /**< Maximum allocation size (limited to half pool to prevent fragmentation) 40 | */ 41 | }; 42 | 43 | /** 44 | * @brief Memory pool statistics and metrics 45 | * @security All members protected by atomic operations 46 | */ 47 | typedef struct PoolMetrics 48 | { 49 | atomic_uint_fast32_t blocks_used; /**< Number of blocks currently in use */ 50 | atomic_uint_fast32_t total_allocations; /**< Total successful allocations */ 51 | atomic_uint_fast32_t 52 | failed_allocations; /**< Number of failed allocation attempts */ 53 | atomic_uint_fast32_t concurrent_ops; /**< Number of concurrent operations */ 54 | } PoolMetrics; 55 | 56 | /** 57 | * @brief Memory pool data structure 58 | * @security All members protected by atomic operations and bounds checking 59 | */ 60 | typedef struct 61 | { 62 | atomic_uintptr_t pool_memory; /**< Pre-allocated memory pool */ 63 | atomic_uintptr_t block_bitmap; /**< Bitmap tracking block usage */ 64 | atomic_size_t bitmap_size; /**< Size of bitmap in words */ 65 | atomic_uint_fast32_t thread_count; /**< Number of active threads */ 66 | atomic_uint_fast32_t 67 | initialization_flag; /**< Ensures single initialization */ 68 | PoolMetrics metrics; /**< Pool usage statistics */ 69 | } MemoryPool; 70 | 71 | /** 72 | * @brief Create a new memory pool strategy 73 | * @return Initialized MemoryStrategy with pool implementation 74 | * @security Thread-safe, null-checked, memory-safe 75 | */ 76 | MemoryStrategy * 77 | create_pool_strategy (void); 78 | 79 | /** 80 | * @brief Clean up and free a pool strategy 81 | * @param strategy Strategy to clean up 82 | * @security Thread-safe, null-checked, double-free protected 83 | */ 84 | void 85 | destroy_pool_strategy (MemoryStrategy *strategy); 86 | 87 | #endif /* MEMORY_POOL_STRATEGY_H_ */ 88 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/include/memory_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_STATS_H_ 2 | #define MEMORY_STATS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "stats_report.h" 8 | 9 | /* Return values for memory stats operations */ 10 | #define MEMORY_STATS_SUCCESS 0 11 | #define MEMORY_STATS_ERROR 1 12 | 13 | /* Maximum number of allocations to track for leak detection */ 14 | #define STATS_MAX_TRACKED_ALLOCATIONS 1000 15 | 16 | /* Size of circular buffer for allocation pattern analysis */ 17 | #define STATS_PATTERN_HISTORY_SIZE 100 18 | 19 | /** 20 | * @brief Memory statistics tracking context 21 | */ 22 | typedef struct memory_stats 23 | { 24 | /* Basic statistics - atomic counters */ 25 | _Atomic uint64_t alloc_count; /**< Total allocation count */ 26 | _Atomic uint64_t free_count; /**< Total deallocation count */ 27 | _Atomic size_t current_bytes; /**< Current allocated bytes */ 28 | _Atomic size_t peak_bytes; /**< Peak allocated bytes */ 29 | 30 | /* Pattern analysis */ 31 | struct 32 | { 33 | size_t size_threshold; /**< Upper bound of this bucket */ 34 | _Atomic uint64_t count; /**< Number of allocations in this range */ 35 | } size_distribution[STATS_SIZE_BUCKET_COUNT]; 36 | 37 | _Atomic uint64_t 38 | total_allocation_time; /**< Total time spent in allocations */ 39 | 40 | /* Active allocation tracking with atomic pointers */ 41 | struct 42 | { 43 | _Atomic (void *) address; /**< Memory address - atomic pointer */ 44 | _Atomic size_t size; /**< Size of allocation - atomic */ 45 | const char *file; /**< Source file of allocation */ 46 | int line; /**< Line number of allocation */ 47 | _Atomic uint64_t timestamp; /**< Time of allocation - atomic */ 48 | _Atomic uint8_t valid; /**< Valid flag - atomic */ 49 | _Atomic uint8_t in_use; /**< In-use flag for synchronization */ 50 | } active_allocations[STATS_MAX_TRACKED_ALLOCATIONS]; 51 | 52 | _Atomic uint32_t active_allocation_count; /**< Number of active allocations */ 53 | _Atomic uint64_t 54 | total_leaked_bytes; /**< Total bytes from unfreed allocations */ 55 | 56 | /* Pattern history tracking */ 57 | struct 58 | { 59 | _Atomic size_t size; /**< Allocation size */ 60 | _Atomic uint64_t timestamp; /**< Time of allocation */ 61 | } recent_allocations[STATS_PATTERN_HISTORY_SIZE]; 62 | _Atomic uint32_t 63 | allocation_history_index; /**< Current index in circular buffer */ 64 | } memory_stats_t; 65 | 66 | // clang-format off 67 | /* Function declarations */ 68 | void memory_stats_init(memory_stats_t *stats); 69 | void memory_stats_update_allocation(memory_stats_t *stats, void *ptr, size_t size, const char *file, int line); 70 | int memory_stats_get_allocation_size(const memory_stats_t *stats, const void *ptr, size_t *size); 71 | void memory_stats_update_deallocation(memory_stats_t *stats, void *ptr); 72 | void memory_stats_reset(memory_stats_t *stats); 73 | void memory_stats_get_report(const memory_stats_t *stats, stats_report_t *report); 74 | char *memory_stats_analyze_patterns(const memory_stats_t *stats); 75 | char *memory_stats_check_leaks(const memory_stats_t *stats); 76 | // clang-format on 77 | 78 | #endif /* MEMORY_STATS_H_ */ 79 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "include/memory_stats.h" 6 | 7 | memory_stats_t stats; 8 | 9 | void 10 | demonstrate_basic_tracking () 11 | { 12 | printf ("\n=== Basic Memory Tracking ===\n"); 13 | void *ptr1 = malloc (256); 14 | void *ptr2 = malloc (1024); 15 | 16 | memory_stats_update_allocation (&stats, ptr1, 256, __FILE__, __LINE__); 17 | memory_stats_update_allocation (&stats, ptr2, 1024, __FILE__, __LINE__); 18 | 19 | stats_report_t report; 20 | memory_stats_get_report (&stats, &report); 21 | printf ("Current allocations: %lu\n", report.alloc_count); 22 | printf ("Current memory usage: %zu bytes\n", report.current_bytes); 23 | 24 | memory_stats_update_deallocation (&stats, ptr1); 25 | free (ptr1); 26 | memory_stats_update_deallocation (&stats, ptr2); 27 | free (ptr2); 28 | } 29 | 30 | void 31 | demonstrate_pattern_analysis () 32 | { 33 | printf ("\n=== Pattern Analysis ===\n"); 34 | 35 | size_t sizes[] = {32, 64, 128, 256, 512, 1024, 2048, 4096}; 36 | void *ptrs[8]; 37 | 38 | for (int i = 0; i < 8; i++) 39 | { 40 | ptrs[i] = malloc (sizes[i]); 41 | memory_stats_update_allocation (&stats, ptrs[i], sizes[i], __FILE__, 42 | __LINE__); 43 | } 44 | 45 | char *analysis = memory_stats_analyze_patterns (&stats); 46 | printf ("%s\n", analysis); 47 | free (analysis); 48 | 49 | for (int i = 0; i < 8; i++) 50 | { 51 | memory_stats_update_deallocation (&stats, ptrs[i]); 52 | free (ptrs[i]); 53 | } 54 | } 55 | 56 | void 57 | demonstrate_leak_detection () 58 | { 59 | printf ("\n=== Leak Detection ===\n"); 60 | 61 | void *leak1 = malloc (128); 62 | void *leak2 = malloc (256); 63 | void *non_leak = malloc (512); 64 | 65 | memory_stats_update_allocation (&stats, leak1, 128, __FILE__, __LINE__); 66 | memory_stats_update_allocation (&stats, leak2, 256, __FILE__, __LINE__); 67 | memory_stats_update_allocation (&stats, non_leak, 512, __FILE__, __LINE__); 68 | 69 | memory_stats_update_deallocation (&stats, non_leak); 70 | free (non_leak); 71 | 72 | char *leak_report = memory_stats_check_leaks (&stats); 73 | printf ("%s\n", leak_report); 74 | free (leak_report); 75 | 76 | memory_stats_update_deallocation (&stats, leak1); 77 | memory_stats_update_deallocation (&stats, leak2); 78 | free (leak1); 79 | free (leak2); 80 | } 81 | 82 | int 83 | main (int argc, char **argv) 84 | { 85 | (void) argc; 86 | (void) argv; 87 | 88 | printf ("Memory Statistics Tracking Example\n"); 89 | printf ("=================================\n"); 90 | 91 | memory_stats_init (&stats); 92 | 93 | demonstrate_basic_tracking (); 94 | demonstrate_pattern_analysis (); 95 | demonstrate_leak_detection (); 96 | 97 | stats_report_t final_report; 98 | memory_stats_get_report (&stats, &final_report); 99 | printf ("\n=== Final Statistics ===\n"); 100 | printf ("Total allocations: %lu\n", final_report.alloc_count); 101 | printf ("Total deallocations: %lu\n", final_report.free_count); 102 | printf ("Peak memory usage: %zu bytes\n", final_report.peak_bytes); 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /src/memory_interface/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file main.c 3 | * @brief Example usage of the thread-safe memory management strategy API 4 | */ 5 | 6 | #include "src/default_strategy.h" 7 | #include 8 | #include 9 | #include 10 | 11 | #define NUM_THREADS 4 12 | #define NUM_ALLOCATIONS 100 13 | #define ALLOCATION_SIZE 1024 14 | 15 | static void * 16 | thread_worker (void *arg) 17 | { 18 | DefaultStrategy *strategy = (DefaultStrategy *) arg; 19 | void *allocations[NUM_ALLOCATIONS]; 20 | 21 | printf ("Thread %lu: Starting memory operations\n", 22 | (unsigned long) pthread_self ()); 23 | 24 | for (int i = 0; i < NUM_ALLOCATIONS; i++) 25 | { 26 | allocations[i] = strategy->base.allocate (&strategy->base, ALLOCATION_SIZE); 27 | if (allocations[i]) 28 | { 29 | memset (allocations[i], i % 255, ALLOCATION_SIZE); 30 | 31 | unsigned char *data = (unsigned char *) allocations[i]; 32 | for (size_t j = 0; j < ALLOCATION_SIZE; j++) 33 | { 34 | if (data[j] != (i % 255)) 35 | { 36 | printf ("Thread %lu: Memory verification failed at allocation %d\n", 37 | (unsigned long) pthread_self (), i); 38 | break; 39 | } 40 | } 41 | } 42 | else 43 | { 44 | printf ("Thread %lu: Allocation %d failed\n", 45 | (unsigned long) pthread_self (), i); 46 | } 47 | } 48 | 49 | // Deallocate memory 50 | for (int i = 0; i < NUM_ALLOCATIONS; i++) 51 | { 52 | if (allocations[i]) 53 | { 54 | strategy->base.deallocate (&strategy->base, allocations[i]); 55 | } 56 | } 57 | 58 | printf ("Thread %lu: Completed memory operations\n", 59 | (unsigned long) pthread_self ()); 60 | return NULL; 61 | } 62 | 63 | int 64 | main (void) 65 | { 66 | printf ("Starting memory management strategy example...\n\n"); 67 | 68 | DefaultStrategy *strategy = create_default_strategy (); 69 | if (!strategy) 70 | { 71 | fprintf (stderr, "Failed to create memory strategy\n"); 72 | return 1; 73 | } 74 | 75 | printf ("Memory strategy initialized successfully\n"); 76 | printf ("Strategy name: %s\n", get_strategy_name ()); 77 | 78 | if (strategy->base.get_status (&strategy->base) != STRATEGY_STATE_ACTIVE) 79 | { 80 | fprintf (stderr, "Strategy initialization failed\n"); 81 | destroy_default_strategy (strategy); 82 | return 1; 83 | } 84 | 85 | pthread_t threads[NUM_THREADS]; 86 | printf ("\nStarting %d threads for concurrent memory operations...\n", 87 | NUM_THREADS); 88 | 89 | for (int i = 0; i < NUM_THREADS; i++) 90 | { 91 | if (pthread_create (&threads[i], NULL, thread_worker, strategy) != 0) 92 | { 93 | fprintf (stderr, "Failed to create thread %d\n", i); 94 | destroy_default_strategy (strategy); 95 | return 1; 96 | } 97 | } 98 | 99 | for (int i = 0; i < NUM_THREADS; i++) 100 | pthread_join (threads[i], NULL); 101 | 102 | printf ("\nMemory usage statistics:\n"); 103 | printf ("Current usage: %zu bytes\n", get_current_usage (strategy)); 104 | printf ("Peak usage: %zu bytes\n", get_peak_usage (strategy)); 105 | printf ("Total allocated: %zu bytes\n", get_total_allocated (strategy)); 106 | printf ("Total freed: %zu bytes\n", get_total_freed (strategy)); 107 | 108 | printf ("\nCleaning up...\n"); 109 | destroy_default_strategy (strategy); 110 | printf ("Memory strategy destroyed successfully\n"); 111 | 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/memory_interface/statetracker/Makefile: -------------------------------------------------------------------------------- 1 | # Compiler settings 2 | CC = gcc 3 | CFLAGS = -Wall -Wextra -Wunused -Wunreachable-code -Werror -I./include \ 4 | -fstack-protector-strong \ 5 | -D_FORTIFY_SOURCE=2 \ 6 | -O2 -fPIC \ 7 | -Wformat=2 -Wformat-security \ 8 | -fno-strict-aliasing \ 9 | -fno-common \ 10 | -pthread 11 | 12 | # Directories 13 | SRC_DIR = src 14 | TEST_DIR = test 15 | EXAMPLES_DIR = examples 16 | INCLUDE_DIR = include 17 | BUILD_DIR = build 18 | LIB_DIR = lib 19 | 20 | # Source files 21 | SRC = $(wildcard $(SRC_DIR)/*.c) 22 | TEST_SRC = $(wildcard $(TEST_DIR)/*.c) 23 | EXAMPLE_SRC = $(wildcard $(EXAMPLES_DIR)/*.c) 24 | 25 | # Object files 26 | OBJ = $(SRC:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) 27 | TEST_OBJ = $(TEST_SRC:$(TEST_DIR)/%.c=$(BUILD_DIR)/%.o) 28 | EXAMPLE_OBJ = $(EXAMPLE_SRC:$(EXAMPLES_DIR)/%.c=$(BUILD_DIR)/%.o) 29 | 30 | # Library target 31 | LIB_NAME = libstatetracker.a 32 | LIB_FILE = $(BUILD_DIR)/$(LIB_NAME) 33 | 34 | # Executable targets 35 | TEST_EXEC = $(BUILD_DIR)/strategy_test 36 | EXAMPLE_EXEC = $(BUILD_DIR)/example 37 | 38 | .PHONY: all lib clean test example install help 39 | 40 | all: $(LIB_FILE) $(TEST_EXEC) $(EXAMPLE_EXEC) 41 | 42 | # Create build directory 43 | $(BUILD_DIR): 44 | mkdir -p $(BUILD_DIR) 45 | 46 | # Build object files for library 47 | $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) 48 | @echo "Compiling $<..." 49 | $(CC) $(CFLAGS) -c $< -o $@ 50 | 51 | # Build object files for tests 52 | $(BUILD_DIR)/%.o: $(TEST_DIR)/%.c | $(BUILD_DIR) 53 | @echo "Compiling $<..." 54 | $(CC) $(CFLAGS) -c $< -o $@ 55 | 56 | # Build object files for examples 57 | $(BUILD_DIR)/%.o: $(EXAMPLES_DIR)/%.c | $(BUILD_DIR) 58 | @echo "Compiling $<..." 59 | $(CC) $(CFLAGS) -c $< -o $@ 60 | 61 | # Build static library from SRC objects 62 | $(LIB_FILE): $(OBJ) | $(BUILD_DIR) 63 | @echo "Creating static library $(LIB_NAME)..." 64 | ar rcs $@ $^ 65 | 66 | # Build the library only 67 | lib: $(LIB_FILE) 68 | @echo "Static library $(LIB_NAME) built successfully." 69 | 70 | # Build test executable by linking against the static library 71 | $(TEST_EXEC): $(TEST_OBJ) $(LIB_FILE) | $(BUILD_DIR) 72 | @echo "Linking test executable $@..." 73 | $(CC) $(CFLAGS) $(TEST_OBJ) -L$(BUILD_DIR) -lstatetracker -o $@ $(LDFLAGS) 74 | 75 | # Build example executable by linking against the static library 76 | $(EXAMPLE_EXEC): $(EXAMPLE_OBJ) $(LIB_FILE) | $(BUILD_DIR) 77 | @echo "Linking example executable $@..." 78 | $(CC) $(CFLAGS) $(EXAMPLE_OBJ) -L$(BUILD_DIR) -lstatetracker -o $@ $(LDFLAGS) 79 | 80 | test: $(TEST_EXEC) 81 | @echo "Running test executable..." 82 | ./$(TEST_EXEC) 83 | 84 | example: $(EXAMPLE_EXEC) 85 | @echo "Running example executable..." 86 | ./$(EXAMPLE_EXEC) 87 | 88 | install: $(LIB_FILE) 89 | @echo "Installing $(LIB_NAME) and headers into $(LIB_DIR)..." 90 | @mkdir -p $(LIB_DIR) 91 | @cp $(LIB_FILE) $(LIB_DIR)/ 92 | @cp -r $(INCLUDE_DIR)/* $(LIB_DIR)/ 93 | @echo "Installation complete: $(LIB_DIR)/$(LIB_NAME) and header files copied." 94 | 95 | clean: 96 | @echo "Cleaning build artifacts and installed files..." 97 | @rm -rf $(BUILD_DIR) $(LIB_DIR) 98 | 99 | help: 100 | @echo "Available targets:" 101 | @echo " all - Build library, tests, and example program" 102 | @echo " lib - Build the static library only" 103 | @echo " test - Run the test executable" 104 | @echo " example - Run the example executable" 105 | @echo " install - Copy the static library and header files into ./lib" 106 | @echo " clean - Remove build artifacts and installed files" 107 | @echo " help - Show this help message" 108 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/test/memory_strategy_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file memory_strategy_test.c 3 | * @brief Test suite for memory strategy core interface 4 | */ 5 | 6 | #include "memory_strategy.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define TEST_ALLOC_SIZE 1024 13 | #define NUM_THREADS 4 14 | #define NUM_ITERATIONS 100 15 | 16 | static void 17 | test_strategy_initialization (void) 18 | { 19 | printf ("Testing strategy initialization...\n"); 20 | 21 | MemoryStrategy strategy; 22 | memset (&strategy, 0, sizeof (MemoryStrategy)); 23 | 24 | assert (initialize_strategy (&strategy) == true); 25 | assert (strategy.status_tracker != NULL); 26 | assert (strategy.allocate != NULL); 27 | assert (strategy.deallocate != NULL); 28 | assert (strategy.get_status != NULL); 29 | assert (strategy.validate != NULL); 30 | 31 | assert (strategy.get_status (&strategy) == STRATEGY_STATE_ACTIVE); 32 | 33 | cleanup_strategy (&strategy); 34 | printf ("Strategy initialization tests passed\n"); 35 | } 36 | 37 | static void 38 | test_null_handling (void) 39 | { 40 | printf ("Testing null pointer handling...\n"); 41 | 42 | // Test initialization with null 43 | assert (initialize_strategy (NULL) == false); 44 | 45 | // Test cleanup with null 46 | cleanup_strategy (NULL); // Should not crash 47 | 48 | MemoryStrategy strategy; 49 | memset (&strategy, 0, sizeof (MemoryStrategy)); 50 | 51 | // Initialize valid strategy but without status tracker 52 | strategy.allocate = NULL; // Ensure no function pointers 53 | strategy.deallocate = NULL; 54 | strategy.get_status = NULL; 55 | strategy.validate = NULL; 56 | strategy.status_tracker = NULL; 57 | strategy.strategy_data = NULL; 58 | 59 | // Test operations with null strategy data 60 | void *ptr 61 | = strategy.allocate ? strategy.allocate (&strategy, TEST_ALLOC_SIZE) : NULL; 62 | assert (ptr == NULL); 63 | 64 | if (strategy.deallocate) 65 | { 66 | strategy.deallocate (&strategy, NULL); // Should not crash 67 | } 68 | 69 | StrategyStatus status = strategy.get_status ? strategy.get_status (&strategy) 70 | : STRATEGY_STATE_ERROR; 71 | assert (status == STRATEGY_STATE_ERROR); 72 | 73 | cleanup_strategy (&strategy); 74 | printf ("Null pointer handling tests passed\n"); 75 | } 76 | 77 | static void * 78 | concurrent_test_thread (void *arg) 79 | { 80 | MemoryStrategy *strategy = (MemoryStrategy *) arg; 81 | void *ptrs[NUM_ITERATIONS]; 82 | 83 | for (int i = 0; i < NUM_ITERATIONS; i++) 84 | { 85 | // Allocate memory 86 | ptrs[i] = strategy->allocate (strategy, TEST_ALLOC_SIZE); 87 | assert (ptrs[i] != NULL); 88 | 89 | // Write to memory to test usability 90 | memset (ptrs[i], i % 256, TEST_ALLOC_SIZE); 91 | 92 | // Verify status remains active 93 | assert (strategy->get_status (strategy) == STRATEGY_STATE_ACTIVE); 94 | } 95 | 96 | // Deallocate all memory 97 | for (int i = 0; i < NUM_ITERATIONS; i++) 98 | { 99 | strategy->deallocate (strategy, ptrs[i]); 100 | } 101 | 102 | return NULL; 103 | } 104 | 105 | static void 106 | test_concurrent_operations (void) 107 | { 108 | printf ("Testing concurrent operations...\n"); 109 | 110 | MemoryStrategy strategy; 111 | assert (initialize_strategy (&strategy) == true); 112 | 113 | pthread_t threads[NUM_THREADS]; 114 | 115 | // Start concurrent threads 116 | for (int i = 0; i < NUM_THREADS; i++) 117 | { 118 | assert ( 119 | pthread_create (&threads[i], NULL, concurrent_test_thread, &strategy) 120 | == 0); 121 | } 122 | 123 | // Wait for all threads to complete 124 | for (int i = 0; i < NUM_THREADS; i++) 125 | { 126 | assert (pthread_join (threads[i], NULL) == 0); 127 | } 128 | 129 | // Verify strategy is still in valid state 130 | assert (strategy.get_status (&strategy) == STRATEGY_STATE_ACTIVE); 131 | assert (strategy.validate (&strategy) == true); 132 | 133 | cleanup_strategy (&strategy); 134 | printf ("Concurrent operation tests passed\n"); 135 | } 136 | 137 | static void 138 | test_error_recovery (void) 139 | { 140 | printf ("Testing error recovery...\n"); 141 | 142 | MemoryStrategy strategy; 143 | assert (initialize_strategy (&strategy) == true); 144 | 145 | // Force error state through invalid operation 146 | void *ptr = strategy.allocate (&strategy, 0); // Invalid size 147 | assert (ptr == NULL); 148 | assert (strategy.get_status (&strategy) == STRATEGY_STATE_ERROR); 149 | 150 | // Attempt recovery through reinitialization 151 | cleanup_strategy (&strategy); 152 | assert (initialize_strategy (&strategy) == true); 153 | assert (strategy.get_status (&strategy) == STRATEGY_STATE_ACTIVE); 154 | 155 | // Verify normal operations work after recovery 156 | ptr = strategy.allocate (&strategy, TEST_ALLOC_SIZE); 157 | assert (ptr != NULL); 158 | strategy.deallocate (&strategy, ptr); 159 | 160 | cleanup_strategy (&strategy); 161 | printf ("Error recovery tests passed\n"); 162 | } 163 | 164 | int 165 | main (void) 166 | { 167 | printf ("Running memory strategy interface tests...\n\n"); 168 | 169 | test_strategy_initialization (); 170 | test_null_handling (); 171 | test_concurrent_operations (); 172 | test_error_recovery (); 173 | 174 | printf ("\nAll memory strategy interface tests passed successfully!\n"); 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/tests/test_memory_stats.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../include/memory_stats.h" 7 | 8 | #define NUM_THREADS 4 9 | #define ITERATIONS 1000 10 | #define TEST_ALLOCATION_SIZE 1024 11 | 12 | void 13 | test_basic_operations () 14 | { 15 | memory_stats_t stats; 16 | stats_report_t report; 17 | 18 | memory_stats_init (&stats); 19 | 20 | void *ptr = malloc (TEST_ALLOCATION_SIZE); 21 | memory_stats_update_allocation (&stats, ptr, TEST_ALLOCATION_SIZE, __FILE__, 22 | __LINE__); 23 | memory_stats_get_report (&stats, &report); 24 | assert (report.alloc_count == 1); 25 | assert (report.current_bytes == TEST_ALLOCATION_SIZE); 26 | assert (report.peak_bytes == TEST_ALLOCATION_SIZE); 27 | 28 | memory_stats_update_deallocation (&stats, ptr); 29 | free (ptr); 30 | memory_stats_get_report (&stats, &report); 31 | assert (report.free_count == 1); 32 | assert (report.current_bytes == 0); 33 | assert (report.peak_bytes == TEST_ALLOCATION_SIZE); 34 | 35 | memory_stats_reset (&stats); 36 | memory_stats_get_report (&stats, &report); 37 | assert (report.alloc_count == 0); 38 | assert (report.free_count == 0); 39 | assert (report.current_bytes == 0); 40 | assert (report.peak_bytes == 0); 41 | 42 | printf ("Basic operations test passed\n"); 43 | } 44 | 45 | void 46 | test_pattern_analysis () 47 | { 48 | memory_stats_t stats; 49 | stats_report_t report; 50 | 51 | memory_stats_init (&stats); 52 | 53 | size_t test_sizes[] = {16, 64, 256, 1024, 4096}; 54 | void *ptrs[5]; 55 | size_t num_sizes = sizeof (test_sizes) / sizeof (test_sizes[0]); 56 | 57 | for (size_t i = 0; i < num_sizes; i++) 58 | { 59 | ptrs[i] = malloc (test_sizes[i]); 60 | memory_stats_update_allocation (&stats, ptrs[i], test_sizes[i], __FILE__, 61 | __LINE__); 62 | } 63 | 64 | char *analysis = memory_stats_analyze_patterns (&stats); 65 | assert (analysis != NULL); 66 | 67 | memory_stats_get_report (&stats, &report); 68 | assert (report.alloc_count == num_sizes); 69 | assert (report.avg_allocation_size > 0); 70 | 71 | size_t total_count = 0; 72 | for (int i = 0; i < STATS_SIZE_BUCKET_COUNT; i++) 73 | { 74 | total_count += report.size_distribution[i].count; 75 | } 76 | assert (total_count == num_sizes); 77 | 78 | for (size_t i = 0; i < num_sizes; i++) 79 | { 80 | memory_stats_update_deallocation (&stats, ptrs[i]); 81 | free (ptrs[i]); 82 | } 83 | 84 | free (analysis); 85 | printf ("Pattern analysis test passed\n"); 86 | } 87 | 88 | void 89 | test_leak_detection () 90 | { 91 | memory_stats_t stats; 92 | stats_report_t report; 93 | 94 | memory_stats_init (&stats); 95 | 96 | void *leak1 = malloc (128); 97 | void *leak2 = malloc (256); 98 | void *non_leak = malloc (512); 99 | 100 | memory_stats_update_allocation (&stats, leak1, 128, __FILE__, __LINE__); 101 | memory_stats_update_allocation (&stats, leak2, 256, __FILE__, __LINE__); 102 | memory_stats_update_allocation (&stats, non_leak, 512, __FILE__, __LINE__); 103 | 104 | memory_stats_update_deallocation (&stats, non_leak); 105 | free (non_leak); 106 | 107 | char *leak_report = memory_stats_check_leaks (&stats); 108 | assert (leak_report != NULL); 109 | 110 | memory_stats_get_report (&stats, &report); 111 | assert (report.active_allocation_count == 2); 112 | assert (report.total_leaked_bytes == 384); 113 | assert (report.leak_count >= 2); 114 | 115 | memory_stats_update_deallocation (&stats, leak1); 116 | memory_stats_update_deallocation (&stats, leak2); 117 | free (leak1); 118 | free (leak2); 119 | free (leak_report); 120 | 121 | printf ("Leak detection test passed\n"); 122 | } 123 | 124 | typedef struct 125 | { 126 | memory_stats_t *stats; 127 | int thread_id; 128 | } thread_args_t; 129 | 130 | void * 131 | thread_routine (void *arg) 132 | { 133 | thread_args_t *args = (thread_args_t *) arg; 134 | 135 | for (int i = 0; i < ITERATIONS; i++) 136 | { 137 | void *ptr = malloc (TEST_ALLOCATION_SIZE); 138 | memory_stats_update_allocation (args->stats, ptr, TEST_ALLOCATION_SIZE, 139 | __FILE__, __LINE__); 140 | memory_stats_update_deallocation (args->stats, ptr); 141 | free (ptr); 142 | } 143 | 144 | return NULL; 145 | } 146 | 147 | void 148 | test_thread_safety () 149 | { 150 | memory_stats_t stats; 151 | stats_report_t report; 152 | pthread_t threads[NUM_THREADS]; 153 | thread_args_t thread_args[NUM_THREADS]; 154 | 155 | memory_stats_init (&stats); 156 | 157 | for (int i = 0; i < NUM_THREADS; i++) 158 | { 159 | thread_args[i].stats = &stats; 160 | thread_args[i].thread_id = i; 161 | pthread_create (&threads[i], NULL, thread_routine, &thread_args[i]); 162 | } 163 | 164 | for (int i = 0; i < NUM_THREADS; i++) 165 | { 166 | pthread_join (threads[i], NULL); 167 | } 168 | 169 | memory_stats_get_report (&stats, &report); 170 | assert (report.alloc_count == NUM_THREADS * ITERATIONS); 171 | assert (report.free_count == NUM_THREADS * ITERATIONS); 172 | assert (report.current_bytes == 0); 173 | assert (report.total_leaked_bytes == 0); 174 | 175 | printf ("Thread safety test passed\n"); 176 | } 177 | 178 | int 179 | main () 180 | { 181 | test_basic_operations (); 182 | test_pattern_analysis (); 183 | test_leak_detection (); 184 | test_thread_safety (); 185 | printf ("All tests passed!\n"); 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/include/strategy_status.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file strategy_status.h 3 | * @brief Thread-safe state management system for memory allocation strategies 4 | */ 5 | 6 | #ifndef MEMORY_STRATEGY_STATUS_H_ 7 | #define MEMORY_STRATEGY_STATUS_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* Configuration Constants */ 14 | /** 15 | * @brief System configuration constants 16 | */ 17 | #define STRATEGY_MAX_RETRIES 3 18 | #define STRATEGY_ERROR_STRING "ERROR" 19 | 20 | /* Error Codes */ 21 | /** 22 | * @brief Operation result codes 23 | */ 24 | typedef enum 25 | { 26 | STRATEGY_SUCCESS = 0, /**< Operation completed successfully */ 27 | STRATEGY_NULL_POINTER = -1, /**< Null pointer provided */ 28 | STRATEGY_INVALID_STATE = -2, /**< Invalid state requested */ 29 | STRATEGY_OVERFLOW = -3, /**< Counter overflow detected */ 30 | STRATEGY_ATOMIC_FAILURE = -4 /**< Atomic operation failed */ 31 | } StrategyResult; 32 | 33 | /* State Definitions */ 34 | /** 35 | * @brief Memory allocation strategy states 36 | * @security All transitions between states are validated at compile time and 37 | * runtime 38 | */ 39 | typedef enum 40 | { 41 | STRATEGY_STATE_INITIALIZED = 0, /**< Initial state after creation */ 42 | STRATEGY_STATE_ACTIVE, /**< Normal operating state */ 43 | STRATEGY_STATE_ERROR, /**< Error condition detected */ 44 | STRATEGY_STATE_TRANSITIONING, /**< Temporarily between states */ 45 | STRATEGY_MAX_STATE = STRATEGY_STATE_TRANSITIONING /**< Bound checking value */ 46 | } StrategyStatus; 47 | 48 | /** 49 | * @brief Thread-safe status tracking structure 50 | * @security All members are protected by atomic operations with sequential 51 | * consistency 52 | */ 53 | typedef struct 54 | { 55 | volatile _Atomic (StrategyStatus) 56 | current_status; /**< Current state (atomic for thread safety) */ 57 | volatile _Atomic (uint64_t) 58 | transition_count; /**< Number of state transitions */ 59 | volatile _Atomic (uint64_t) error_count; /**< Number of errors encountered */ 60 | } StatusTracker; 61 | 62 | /* Core Functions */ 63 | /** 64 | * @brief Initialize a new status tracker 65 | * @param tracker Pointer to the StatusTracker to initialize 66 | * @return StrategyResult indicating success or failure 67 | * @security Thread-safe, NULL-pointer protected, sequential consistency 68 | */ 69 | StrategyResult 70 | initialize_status (StatusTracker *const tracker); 71 | 72 | /** 73 | * @brief Attempt to transition to a new state 74 | * @param tracker Pointer to the StatusTracker 75 | * @param new_status The target state 76 | * @return StrategyResult indicating success or failure 77 | * @security Thread-safe, bounds-checked, overflow-protected 78 | */ 79 | StrategyResult 80 | transition_status (StatusTracker *const tracker, 81 | const StrategyStatus new_status); 82 | 83 | /* Status Query Functions */ 84 | /** 85 | * @brief Get the current status 86 | * @param tracker Pointer to the StatusTracker 87 | * @param[out] status Pointer to store the current status 88 | * @return StrategyResult indicating success or failure 89 | * @security Thread-safe, const-correct 90 | */ 91 | StrategyResult 92 | get_current_status (const StatusTracker *const tracker, 93 | StrategyStatus *const status); 94 | 95 | /** 96 | * @brief Get the number of state transitions 97 | * @param tracker Pointer to the StatusTracker 98 | * @param[out] count Pointer to store the transition count 99 | * @return StrategyResult indicating success or failure 100 | * @security Thread-safe, overflow-protected 101 | */ 102 | StrategyResult 103 | get_transition_count (const StatusTracker *const tracker, 104 | uint64_t *const count); 105 | 106 | /** 107 | * @brief Get the number of errors encountered 108 | * @param tracker Pointer to the StatusTracker 109 | * @param[out] count Pointer to store the error count 110 | * @return StrategyResult indicating success or failure 111 | * @security Thread-safe, overflow-protected 112 | */ 113 | StrategyResult 114 | get_error_count (const StatusTracker *const tracker, uint64_t *const count); 115 | 116 | /* State Validation Functions */ 117 | /** 118 | * @brief Check if a state transition is valid 119 | * @param current Current state 120 | * @param next Proposed next state 121 | * @return true if transition is valid, false otherwise 122 | * @security Const function, bounds-checked 123 | */ 124 | bool 125 | is_valid_state_transition (const StrategyStatus current, 126 | const StrategyStatus next); 127 | 128 | /** 129 | * @brief Check if a state is an error state 130 | * @param status State to check 131 | * @return true if state is an error state, false otherwise 132 | * @security Const function, bounds-checked 133 | */ 134 | bool 135 | is_error_state (const StrategyStatus status); 136 | 137 | /** 138 | * @brief Check if a state requires recovery action 139 | * @param status State to check 140 | * @return true if state requires recovery, false otherwise 141 | * @security Const function, bounds-checked 142 | */ 143 | bool 144 | requires_state_recovery (const StrategyStatus status); 145 | 146 | /** 147 | * @brief Get string representation of a status 148 | * @param status State to convert to string 149 | * @return Constant string representing the status 150 | * @security Const function, bounds-checked 151 | */ 152 | const char * 153 | get_state_string (const StrategyStatus status); 154 | 155 | #endif /* MEMORY_STRATEGY_STATUS_H_ */ 156 | -------------------------------------------------------------------------------- /src/memory_interface/statetracker/include/strategy_status.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file strategy_status.h 3 | * @brief Thread-safe state management system for memory allocation strategies 4 | */ 5 | 6 | #ifndef MEMORY_STRATEGY_STATUS_H_ 7 | #define MEMORY_STRATEGY_STATUS_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | /* Configuration Constants */ 14 | /** 15 | * @brief System configuration constants 16 | */ 17 | #define STRATEGY_MAX_RETRIES 3 18 | #define STRATEGY_ERROR_STRING "ERROR" 19 | 20 | /* Error Codes */ 21 | /** 22 | * @brief Operation result codes 23 | */ 24 | typedef enum 25 | { 26 | STRATEGY_SUCCESS = 0, /**< Operation completed successfully */ 27 | STRATEGY_NULL_POINTER = -1, /**< Null pointer provided */ 28 | STRATEGY_INVALID_STATE = -2, /**< Invalid state requested */ 29 | STRATEGY_OVERFLOW = -3, /**< Counter overflow detected */ 30 | STRATEGY_ATOMIC_FAILURE = -4 /**< Atomic operation failed */ 31 | } StrategyResult; 32 | 33 | /* State Definitions */ 34 | /** 35 | * @brief Memory allocation strategy states 36 | * @security All transitions between states are validated at compile time and 37 | * runtime 38 | */ 39 | typedef enum 40 | { 41 | STRATEGY_STATE_INITIALIZED = 0, /**< Initial state after creation */ 42 | STRATEGY_STATE_ACTIVE, /**< Normal operating state */ 43 | STRATEGY_STATE_ERROR, /**< Error condition detected */ 44 | STRATEGY_STATE_TRANSITIONING, /**< Temporarily between states */ 45 | STRATEGY_MAX_STATE = STRATEGY_STATE_TRANSITIONING /**< Bound checking value */ 46 | } StrategyStatus; 47 | 48 | /** 49 | * @brief Thread-safe status tracking structure 50 | * @security All members are protected by atomic operations with sequential 51 | * consistency 52 | */ 53 | typedef struct 54 | { 55 | volatile _Atomic (StrategyStatus) 56 | current_status; /**< Current state (atomic for thread safety) */ 57 | volatile _Atomic (uint64_t) 58 | transition_count; /**< Number of state transitions */ 59 | volatile _Atomic (uint64_t) error_count; /**< Number of errors encountered */ 60 | } StatusTracker; 61 | 62 | /* Core Functions */ 63 | /** 64 | * @brief Initialize a new status tracker 65 | * @param tracker Pointer to the StatusTracker to initialize 66 | * @return StrategyResult indicating success or failure 67 | * @security Thread-safe, NULL-pointer protected, sequential consistency 68 | */ 69 | StrategyResult 70 | initialize_status (StatusTracker *const tracker); 71 | 72 | /** 73 | * @brief Attempt to transition to a new state 74 | * @param tracker Pointer to the StatusTracker 75 | * @param new_status The target state 76 | * @return StrategyResult indicating success or failure 77 | * @security Thread-safe, bounds-checked, overflow-protected 78 | */ 79 | StrategyResult 80 | transition_status (StatusTracker *const tracker, 81 | const StrategyStatus new_status); 82 | 83 | /* Status Query Functions */ 84 | /** 85 | * @brief Get the current status 86 | * @param tracker Pointer to the StatusTracker 87 | * @param[out] status Pointer to store the current status 88 | * @return StrategyResult indicating success or failure 89 | * @security Thread-safe, const-correct 90 | */ 91 | StrategyResult 92 | get_current_status (const StatusTracker *const tracker, 93 | StrategyStatus *const status); 94 | 95 | /** 96 | * @brief Get the number of state transitions 97 | * @param tracker Pointer to the StatusTracker 98 | * @param[out] count Pointer to store the transition count 99 | * @return StrategyResult indicating success or failure 100 | * @security Thread-safe, overflow-protected 101 | */ 102 | StrategyResult 103 | get_transition_count (const StatusTracker *const tracker, 104 | uint64_t *const count); 105 | 106 | /** 107 | * @brief Get the number of errors encountered 108 | * @param tracker Pointer to the StatusTracker 109 | * @param[out] count Pointer to store the error count 110 | * @return StrategyResult indicating success or failure 111 | * @security Thread-safe, overflow-protected 112 | */ 113 | StrategyResult 114 | get_error_count (const StatusTracker *const tracker, uint64_t *const count); 115 | 116 | /* State Validation Functions */ 117 | /** 118 | * @brief Check if a state transition is valid 119 | * @param current Current state 120 | * @param next Proposed next state 121 | * @return true if transition is valid, false otherwise 122 | * @security Const function, bounds-checked 123 | */ 124 | bool 125 | is_valid_state_transition (const StrategyStatus current, 126 | const StrategyStatus next); 127 | 128 | /** 129 | * @brief Check if a state is an error state 130 | * @param status State to check 131 | * @return true if state is an error state, false otherwise 132 | * @security Const function, bounds-checked 133 | */ 134 | bool 135 | is_error_state (const StrategyStatus status); 136 | 137 | /** 138 | * @brief Check if a state requires recovery action 139 | * @param status State to check 140 | * @return true if state requires recovery, false otherwise 141 | * @security Const function, bounds-checked 142 | */ 143 | bool 144 | requires_state_recovery (const StrategyStatus status); 145 | 146 | /** 147 | * @brief Get string representation of a status 148 | * @param status State to convert to string 149 | * @return Constant string representing the status 150 | * @security Const function, bounds-checked 151 | */ 152 | const char * 153 | get_state_string (const StrategyStatus status); 154 | 155 | #endif /* MEMORY_STRATEGY_STATUS_H_ */ 156 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/README.md: -------------------------------------------------------------------------------- 1 | # Memory Statistics Tracking System 2 | 3 | C library for tracking memory allocations, detecting memory leaks, and analyzing memory usage patterns in multi-threaded applications. 4 | 5 | ## Features 6 | 7 | - Thread-safe memory allocation tracking 8 | - Detailed memory usage statistics 9 | - Memory leak detection with source location tracking 10 | - Memory allocation pattern analysis 11 | - Atomic operations for concurrent access 12 | - Configurable size distribution buckets 13 | - Comprehensive test coverage 14 | 15 | ## Installation 16 | 17 | The Makefile now includes an install target that builds the static library (libmemstats.a) and copies it along with the header files into the `./lib` folder. 18 | 19 | ```bash 20 | # Build the release version (recommended for production use) 21 | make release 22 | 23 | # Build with debug symbols and sanitizers (for development) 24 | make debug 25 | 26 | # Build the example program 27 | make example 28 | 29 | # Run all tests 30 | make test 31 | 32 | # Install the library and header files into ./lib 33 | make install 34 | ``` 35 | 36 | ## Usage 37 | 38 | ### Basic Example 39 | 40 | ```c 41 | #include "memory_stats.h" 42 | 43 | int main() { 44 | // Initialize stats tracking 45 | memory_stats_t stats; 46 | memory_stats_init(&stats); 47 | 48 | // Track allocations 49 | void* ptr = malloc(1024); 50 | memory_stats_update_allocation(&stats, ptr, 1024, __FILE__, __LINE__); 51 | 52 | // Get current statistics 53 | stats_report_t report; 54 | memory_stats_get_report(&stats, &report); 55 | printf("Current memory usage: %zu bytes\n", report.current_bytes); 56 | 57 | // Track deallocations 58 | memory_stats_update_deallocation(&stats, ptr); 59 | free(ptr); 60 | 61 | return 0; 62 | } 63 | ``` 64 | 65 | ### Pattern Analysis 66 | 67 | ```c 68 | // Analyze allocation patterns 69 | char* analysis = memory_stats_analyze_patterns(&stats); 70 | printf("%s\n", analysis); 71 | free(analysis); 72 | ``` 73 | 74 | Example output: 75 | ``` 76 | Memory Allocation Pattern Analysis: 77 | ================================ 78 | Average Allocation Size: 256.43 bytes 79 | Allocation Frequency: 1000/sec 80 | 81 | Size Distribution: 82 | ≤ 32 bytes: 1500 allocations 83 | ≤ 64 bytes: 800 allocations 84 | ≤ 128 bytes: 400 allocations 85 | ≤ 256 bytes: 200 allocations 86 | ≤ 512 bytes: 100 allocations 87 | ≤ 1024 bytes: 50 allocations 88 | ≤ 4096 bytes: 25 allocations 89 | > 4096 bytes: 10 allocations 90 | ``` 91 | 92 | ### Leak Detection 93 | 94 | ```c 95 | // Check for memory leaks 96 | char* leak_report = memory_stats_check_leaks(&stats); 97 | printf("%s\n", leak_report); 98 | free(leak_report); 99 | ``` 100 | 101 | Example output: 102 | ``` 103 | Memory Leak Analysis: 104 | =================== 105 | Active Allocations: 2 106 | Total Leaked Bytes: 384 107 | 108 | Detected Leaks: 109 | Leak #1: 110 | Address: 0x7f9348000b70 111 | Size: 128 bytes 112 | Location: main.c:56 113 | Time: 1706198400 114 | 115 | Leak #2: 116 | Address: 0x7f9348001c80 117 | Size: 256 bytes 118 | Location: main.c:57 119 | Time: 1706198410 120 | ``` 121 | 122 | ## Building and Testing 123 | 124 | ```bash 125 | # Build debug version (with sanitizers) 126 | make debug 127 | 128 | # Build release version 129 | make release 130 | 131 | # Build example program 132 | make example 133 | 134 | # Run specific test suites 135 | make test-memory-stats 136 | make test-edge-cases 137 | make test-stats-report 138 | 139 | # Generate code coverage report 140 | make coverage 141 | 142 | # Run static analysis 143 | make analyze 144 | 145 | # Clean build artifacts 146 | make clean 147 | ``` 148 | 149 | ## Thread Safety 150 | 151 | The library uses several techniques to ensure thread safety: 152 | 153 | 1. **Atomic Operations** 154 | - All counters use atomic types. 155 | - Updates are performed using atomic operations. 156 | - Memory ordering is carefully controlled. 157 | 158 | 2. **Lock-free Algorithms** 159 | - No mutexes or locks are used. 160 | - Compare-and-swap operations for updates. 161 | - Wait-free progress for basic operations. 162 | 163 | 3. **Contention Management** 164 | - Exponential backoff for high contention. 165 | - Randomized jitter to prevent thundering herd. 166 | - Multiple retry attempts with backoff. 167 | 168 | 4. **Memory Ordering** 169 | - Acquire/Release semantics for consistency. 170 | - Full memory barriers at critical points. 171 | - Proper synchronization of shared data. 172 | 173 | ## API Reference 174 | 175 | ### Core Functions 176 | 177 | - `void memory_stats_init(memory_stats_t* stats)` 178 | Initializes the memory statistics tracking system. Must be called before any other operations. 179 | 180 | - `void memory_stats_update_allocation(memory_stats_t* stats, void* ptr, size_t size, const char* file, int line)` 181 | Records a new memory allocation. *Thread-safe: Yes.* 182 | 183 | - `void memory_stats_update_deallocation(memory_stats_t* stats, void* ptr)` 184 | Records a memory deallocation. *Thread-safe: Yes.* 185 | 186 | - `void memory_stats_get_report(const memory_stats_t* stats, stats_report_t* report)` 187 | Generates a snapshot of current memory statistics. *Thread-safe: Yes.* 188 | 189 | ### Analysis Functions 190 | 191 | - `char* memory_stats_analyze_patterns(const memory_stats_t* stats)` 192 | Analyzes memory allocation patterns. Returns an allocated string (caller must free). *Thread-safe: Yes.* 193 | 194 | - `char* memory_stats_check_leaks(const memory_stats_t* stats)` 195 | Generates a report of memory leaks. Returns an allocated string (caller must free). *Thread-safe: Yes.* 196 | 197 | --- 198 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/Makefile: -------------------------------------------------------------------------------- 1 | # Compiler and tools 2 | CC := gcc 3 | CFLAGS := -Wall -Wextra -Werror -Wunreachable-code -Wunused -pedantic -g 4 | CPPFLAGS:= -I./include 5 | LDFLAGS := -pthread 6 | 7 | # Build type specific flags 8 | DEBUG_FLAGS := -g -DDEBUG -fsanitize=address 9 | RELEASE_FLAGS := -O2 -DNDEBUG 10 | COVERAGE_FLAGS:= --coverage -fprofile-arcs -ftest-coverage 11 | 12 | # Directories 13 | SRC_DIR := src 14 | TEST_DIR := tests 15 | BUILD_DIR := build 16 | COV_DIR := $(BUILD_DIR)/coverage 17 | DEST_LIB_DIR := ./lib 18 | 19 | # Source files 20 | LIB_SOURCES := $(wildcard $(SRC_DIR)/*.c) 21 | LIB_OBJECTS := $(LIB_SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o) 22 | LIB_DEPS := $(LIB_OBJECTS:.o=.d) 23 | 24 | TEST_SOURCES := $(wildcard $(TEST_DIR)/*.c) 25 | TEST_BINS := $(TEST_SOURCES:$(TEST_DIR)/%.c=$(BUILD_DIR)/%) 26 | TEST_OBJECTS := $(TEST_SOURCES:$(TEST_DIR)/%.c=$(BUILD_DIR)/%.o) 27 | TEST_DEPS := $(TEST_OBJECTS:.o=.d) 28 | 29 | # Main program (example) 30 | MAIN_PROGRAM := $(BUILD_DIR)/memory_stats_example 31 | MAIN_OBJECT := $(BUILD_DIR)/main.o 32 | 33 | # Library target name and file (renamed for clarity) 34 | LIB_NAME := libmemstats.a 35 | LIBRARY := $(BUILD_DIR)/$(LIB_NAME) 36 | 37 | # Default target builds tests and example program 38 | .PHONY: all 39 | all: release example 40 | 41 | # Build type targets 42 | .PHONY: debug release coverage 43 | debug: CFLAGS += $(DEBUG_FLAGS) 44 | debug: LDFLAGS += -lasan 45 | debug: dirs $(TEST_BINS) 46 | 47 | release: CFLAGS += $(RELEASE_FLAGS) 48 | release: dirs $(TEST_BINS) 49 | 50 | coverage: CFLAGS += $(COVERAGE_FLAGS) 51 | coverage: LDFLAGS += $(COVERAGE_FLAGS) 52 | coverage: clean dirs $(TEST_BINS) 53 | @mkdir -p $(COV_DIR) 54 | @for test in $(TEST_BINS); do \ 55 | ./$$test || exit 1; \ 56 | done 57 | gcov -o $(BUILD_DIR) $(LIB_SOURCES) 58 | mv *.gcov $(COV_DIR)/ 59 | 60 | # Create build directories 61 | .PHONY: dirs 62 | dirs: 63 | @mkdir -p $(BUILD_DIR) 64 | 65 | # Dependency generation 66 | $(BUILD_DIR)/%.d: $(SRC_DIR)/%.c 67 | @mkdir -p $(dir $@) 68 | @$(CC) $(CPPFLAGS) -MM -MT '$(BUILD_DIR)/$*.o' $< > $@ 69 | 70 | $(BUILD_DIR)/%.d: $(TEST_DIR)/%.c 71 | @mkdir -p $(dir $@) 72 | @$(CC) $(CPPFLAGS) -MM -MT '$(BUILD_DIR)/$*.o' $< > $@ 73 | 74 | # Compilation rules 75 | $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c 76 | @echo "Compiling $<..." 77 | @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ 78 | 79 | $(BUILD_DIR)/%.o: $(TEST_DIR)/%.c 80 | @echo "Compiling $<..." 81 | @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ 82 | 83 | # Build static library 84 | .PHONY: lib 85 | lib: $(LIBRARY) 86 | 87 | $(LIBRARY): $(LIB_OBJECTS) 88 | @echo "Creating static library $(LIB_NAME)..." 89 | @ar rcs $@ $^ 90 | 91 | # Build test executables 92 | $(BUILD_DIR)/test_%: $(BUILD_DIR)/test_%.o $(LIB_OBJECTS) 93 | @echo "Linking $@..." 94 | @$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ 95 | 96 | # Run all tests 97 | .PHONY: test 98 | test: debug 99 | @echo "Running all tests..." 100 | @for test in $(TEST_BINS); do \ 101 | echo "\nRunning $$test:"; \ 102 | ./$$test || exit 1; \ 103 | done 104 | 105 | # Run specific test suites 106 | .PHONY: test-memory-stats test-edge-cases test-stats-report 107 | test-memory-stats: $(BUILD_DIR)/test_memory_stats 108 | @echo "Running memory stats tests..." 109 | ./$(BUILD_DIR)/test_memory_stats 110 | 111 | test-edge-cases: $(BUILD_DIR)/test_edge_cases 112 | @echo "Running edge cases tests..." 113 | ./$(BUILD_DIR)/test_edge_cases 114 | 115 | test-stats-report: $(BUILD_DIR)/test_stats_report 116 | @echo "Running stats report tests..." 117 | ./$(BUILD_DIR)/test_stats_report 118 | 119 | # Static analysis 120 | .PHONY: analyze 121 | analyze: 122 | @echo "Running static analysis..." 123 | cppcheck --enable=all --suppress=missingIncludeSystem $(SRC_DIR) $(TEST_DIR) 124 | 125 | # Clean build artifacts 126 | .PHONY: clean 127 | clean: 128 | @echo "Cleaning build artifacts..." 129 | @rm -rf $(BUILD_DIR) $(DEST_LIB_DIR) 130 | @rm -f $(SRC_DIR)/*.gc* $(TEST_DIR)/*.gc* 131 | 132 | # Build example program 133 | .PHONY: example 134 | example: CFLAGS += $(RELEASE_FLAGS) 135 | example: $(MAIN_PROGRAM) 136 | 137 | $(MAIN_PROGRAM): $(MAIN_OBJECT) $(LIB_OBJECTS) 138 | @echo "Building example program..." 139 | @$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ 140 | 141 | $(MAIN_OBJECT): main.c 142 | @echo "Compiling main.c..." 143 | @mkdir -p $(BUILD_DIR) 144 | @$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ 145 | 146 | # Install target: builds the library and copies it with headers to ./lib 147 | .PHONY: install 148 | install: lib 149 | @echo "Installing $(LIB_NAME) and headers into ./lib..." 150 | @mkdir -p $(DEST_LIB_DIR) 151 | @cp $(LIBRARY) $(DEST_LIB_DIR)/ 152 | @cp include/*.h $(DEST_LIB_DIR)/ 153 | @echo "Installation complete: $(DEST_LIB_DIR)/$(LIB_NAME) and header files copied." 154 | 155 | # Show help 156 | .PHONY: help 157 | help: 158 | @echo "Available targets:" 159 | @echo " all - Build tests and example program" 160 | @echo " debug - Build with debug symbols and sanitizers" 161 | @echo " release - Build with optimizations" 162 | @echo " coverage - Build and run tests with coverage analysis" 163 | @echo " test - Build and run all tests" 164 | @echo " test-memory-stats- Run memory stats tests only" 165 | @echo " test-edge-cases - Run edge case tests only" 166 | @echo " test-stats-report- Run stats report tests only" 167 | @echo " analyze - Run static code analysis" 168 | @echo " example - Build the example program" 169 | @echo " install - Copy library and headers into ./lib" 170 | @echo " clean - Remove build artifacts" 171 | @echo " help - Show this help message" 172 | 173 | # Include generated dependencies 174 | -include $(LIB_DEPS) $(TEST_DEPS) 175 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/test/validator_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file validator_test.c 3 | * @brief Test suite for memory strategy validation system 4 | */ 5 | 6 | #include "strategy_validator.h" 7 | #include "memory_strategy.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define VALID_SIZE 1024 16 | #define NUM_THREADS 4 17 | #define NUM_ITERATIONS 100 18 | 19 | // Mock strategy for testing 20 | static void * 21 | mock_allocate (struct MemoryStrategy *self, size_t size) 22 | { 23 | (void) self; 24 | (void) size; 25 | return NULL; 26 | } 27 | 28 | static void 29 | mock_deallocate (struct MemoryStrategy *self, void *ptr) 30 | { 31 | (void) self; 32 | (void) ptr; 33 | } 34 | 35 | static StrategyStatus 36 | mock_get_status (struct MemoryStrategy *self) 37 | { 38 | return *(StrategyStatus *) self->strategy_data; 39 | } 40 | 41 | static bool 42 | mock_validate (struct MemoryStrategy *self) 43 | { 44 | (void) self; 45 | return true; 46 | } 47 | 48 | static MemoryStrategy * 49 | create_mock_strategy (void) 50 | { 51 | MemoryStrategy *strategy = calloc (1, sizeof (MemoryStrategy)); 52 | if (!strategy) 53 | return NULL; 54 | 55 | strategy->status_tracker = calloc (1, sizeof (StatusTracker)); 56 | if (!strategy->status_tracker) 57 | { 58 | free (strategy); 59 | return NULL; 60 | } 61 | 62 | strategy->allocate = mock_allocate; 63 | strategy->deallocate = mock_deallocate; 64 | strategy->get_status = mock_get_status; 65 | strategy->validate = mock_validate; 66 | 67 | // Initialize status tracker 68 | initialize_status (strategy->status_tracker); 69 | transition_status (strategy->status_tracker, STRATEGY_STATE_ACTIVE); 70 | 71 | return strategy; 72 | } 73 | 74 | static void 75 | destroy_mock_strategy (MemoryStrategy *strategy) 76 | { 77 | if (!strategy) 78 | return; 79 | if (strategy->status_tracker) 80 | free (strategy->status_tracker); 81 | if (strategy->strategy_data) 82 | free (strategy->strategy_data); 83 | free (strategy); 84 | } 85 | 86 | static void 87 | test_strategy_validation (void) 88 | { 89 | printf ("Testing strategy validation...\n"); 90 | 91 | // Test null strategy 92 | assert (validate_strategy (NULL) == false); 93 | 94 | // Test valid strategy 95 | MemoryStrategy *strategy = create_mock_strategy (); 96 | assert (validate_strategy (strategy) == true); 97 | 98 | // Test incomplete strategy (missing functions) 99 | strategy->allocate = NULL; 100 | assert (validate_strategy (strategy) == false); 101 | 102 | // Test strategy in error state 103 | transition_status (strategy->status_tracker, STRATEGY_STATE_ERROR); 104 | assert (validate_strategy (strategy) == false); 105 | 106 | destroy_mock_strategy (strategy); 107 | printf ("Strategy validation tests passed\n"); 108 | } 109 | 110 | static void 111 | test_allocation_validation (void) 112 | { 113 | printf ("Testing allocation validation...\n"); 114 | 115 | MemoryStrategy *strategy = create_mock_strategy (); 116 | 117 | // Test null strategy 118 | assert (validate_allocation (NULL, VALID_SIZE) == false); 119 | 120 | // Test zero size 121 | assert (validate_allocation (strategy, 0) == false); 122 | 123 | // Test overflow size 124 | assert (validate_allocation (strategy, SIZE_MAX) == false); 125 | 126 | // Test valid size 127 | assert (validate_allocation (strategy, VALID_SIZE) == true); 128 | 129 | // Test allocation in non-active state 130 | transition_status (strategy->status_tracker, STRATEGY_STATE_ERROR); 131 | assert (validate_allocation (strategy, VALID_SIZE) == false); 132 | 133 | destroy_mock_strategy (strategy); 134 | printf ("Allocation validation tests passed\n"); 135 | } 136 | 137 | static void 138 | test_deallocation_validation (void) 139 | { 140 | printf ("Testing deallocation validation...\n"); 141 | 142 | MemoryStrategy *strategy = create_mock_strategy (); 143 | void *test_ptr = (void *) 0x1000; // Mock pointer 144 | 145 | // Test null strategy 146 | assert (validate_deallocation (NULL, test_ptr) == false); 147 | 148 | // Test null pointer 149 | assert (validate_deallocation (strategy, NULL) == false); 150 | 151 | // Test valid deallocation 152 | assert (validate_deallocation (strategy, test_ptr) == true); 153 | 154 | // Test deallocation in non-active state 155 | transition_status (strategy->status_tracker, STRATEGY_STATE_ERROR); 156 | assert (validate_deallocation (strategy, test_ptr) == false); 157 | 158 | destroy_mock_strategy (strategy); 159 | printf ("Deallocation validation tests passed\n"); 160 | } 161 | 162 | static void * 163 | concurrent_validation_thread (void *arg) 164 | { 165 | MemoryStrategy *strategy = (MemoryStrategy *) arg; 166 | 167 | for (int i = 0; i < NUM_ITERATIONS; i++) 168 | { 169 | assert (validate_strategy (strategy) == true); 170 | assert (validate_allocation (strategy, VALID_SIZE) == true); 171 | assert (validate_deallocation (strategy, (void *) 0x1000) == true); 172 | } 173 | 174 | return NULL; 175 | } 176 | 177 | static void 178 | test_concurrent_validation (void) 179 | { 180 | printf ("Testing concurrent validation...\n"); 181 | 182 | MemoryStrategy *strategy = create_mock_strategy (); 183 | pthread_t threads[NUM_THREADS]; 184 | 185 | // Start concurrent threads 186 | for (int i = 0; i < NUM_THREADS; i++) 187 | { 188 | assert ( 189 | pthread_create (&threads[i], NULL, concurrent_validation_thread, strategy) 190 | == 0); 191 | } 192 | 193 | // Wait for all threads to complete 194 | for (int i = 0; i < NUM_THREADS; i++) 195 | { 196 | assert (pthread_join (threads[i], NULL) == 0); 197 | } 198 | 199 | // Verify strategy is still valid 200 | assert (validate_strategy (strategy) == true); 201 | 202 | destroy_mock_strategy (strategy); 203 | printf ("Concurrent validation tests passed\n"); 204 | } 205 | 206 | int 207 | main (void) 208 | { 209 | printf ("Running strategy validator tests...\n\n"); 210 | 211 | test_strategy_validation (); 212 | test_allocation_validation (); 213 | test_deallocation_validation (); 214 | test_concurrent_validation (); 215 | 216 | printf ("\nAll strategy validator tests passed successfully!\n"); 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /src/memory_interface/src/default_strategy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file default_strategy.h 3 | * @brief Thread-safe default memory management strategy implementation 4 | * 5 | * This file implements a thread-safe DefaultStrategy that provides memory 6 | * management functionality with comprehensive tracking and statistics. The 7 | * implementation meets the following key requirements: 8 | * - Thread-safe allocation and deallocation 9 | * - Memory usage statistics and leak detection 10 | * - Status tracking and validation 11 | * - Performance overhead < 5% compared to raw malloc/free 12 | * 13 | * Thread safety is achieved through atomic operations and proper memory 14 | * barriers. 15 | * 16 | * @note All operations are atomic and thread-safe by design 17 | * @warning Not intended for use in signal handlers or interrupt contexts 18 | */ 19 | 20 | #ifndef DEFAULT_STRATEGY_H 21 | #define DEFAULT_STRATEGY_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | // Include paths relative to the include directories 29 | #include "memory_strategy.h" 30 | #include "memory_stats.h" 31 | #include "strategy_status.h" 32 | 33 | /** 34 | * @brief Thread-safe default memory management strategy 35 | * 36 | * Implements the MemoryStrategy interface with additional features: 37 | * - Memory usage statistics tracking 38 | * - Thread-safe status management 39 | * - Peak memory usage monitoring 40 | * - Operation counting for debugging 41 | * 42 | * @note All member variables are atomic to ensure thread safety 43 | * @see MemoryStrategy for the base interface 44 | */ 45 | typedef struct DefaultStrategy 46 | { 47 | MemoryStrategy base; /**< Base strategy interface */ 48 | memory_stats_t *stats; /**< Memory usage statistics */ 49 | StatusTracker status_tracker; /**< Thread-safe status management */ 50 | 51 | // Atomic counters for usage tracking 52 | _Atomic size_t total_allocated; /**< Total bytes allocated */ 53 | _Atomic size_t total_freed; /**< Total bytes freed */ 54 | _Atomic size_t peak_usage; /**< Peak memory usage observed */ 55 | _Atomic uint32_t usage_count; /**< Count of in-flight operations */ 56 | _Atomic uint64_t 57 | operation_count; /**< Unique operation ID counter for debugging */ 58 | } DefaultStrategy; 59 | 60 | // clang-format off 61 | /** 62 | * @brief Creates and initializes a new DefaultStrategy instance 63 | * 64 | * Allocates and initializes a new DefaultStrategy with: 65 | * - Memory statistics tracking 66 | * - Status management 67 | * - Function pointers for the MemoryStrategy interface 68 | * 69 | * @return Pointer to initialized DefaultStrategy or NULL on failure 70 | * @note Thread-safe: Yes 71 | * @see destroy_default_strategy for cleanup 72 | */ 73 | DefaultStrategy *create_default_strategy(void); 74 | 75 | /** 76 | * @brief Cleans up and destroys a DefaultStrategy instance 77 | * 78 | * Ensures proper cleanup of resources: 79 | * - Waits for in-flight operations to complete 80 | * - Generates leak report if needed 81 | * - Frees all associated resources 82 | * 83 | * @param strategy Strategy to destroy (must be non-NULL) 84 | * @note Thread-safe: Yes 85 | * @warning Undefined behavior if strategy is NULL or already destroyed 86 | */ 87 | void destroy_default_strategy(DefaultStrategy *strategy); 88 | 89 | /** 90 | * @brief Thread-safe memory allocation function 91 | * 92 | * Allocates memory while maintaining: 93 | * - Usage statistics 94 | * - Thread safety through atomic operations 95 | * - Error handling and validation 96 | * 97 | * @param base Base strategy pointer (must be non-NULL) 98 | * @param size Number of bytes to allocate (must be > 0) 99 | * @return Allocated memory pointer or NULL on failure 100 | * @note Thread-safe: Yes 101 | * @warning May return NULL if size is 0 or on allocation failure 102 | */ 103 | void *default_allocate(MemoryStrategy *base, size_t size); 104 | 105 | /** 106 | * @brief Thread-safe memory deallocation function 107 | * 108 | * Frees memory while: 109 | * - Updating usage statistics 110 | * - Maintaining thread safety 111 | * - Validating the operation 112 | * 113 | * @param base Base strategy pointer (must be non-NULL) 114 | * @param ptr Pointer to memory to free (may be NULL) 115 | * @note Thread-safe: Yes 116 | * @warning Undefined behavior if ptr was not allocated by this strategy 117 | */ 118 | void default_deallocate(MemoryStrategy *base, void *ptr); 119 | 120 | /** 121 | * @brief Gets current strategy status 122 | * 123 | * @param base Base strategy pointer (must be non-NULL) 124 | * @return Current StrategyStatus 125 | * @note Thread-safe: Yes 126 | * @warning Returns STRATEGY_STATE_ERROR if base is NULL 127 | */ 128 | StrategyStatus default_get_status(MemoryStrategy *base); 129 | 130 | /** 131 | * @brief Validates strategy state 132 | * 133 | * Checks: 134 | * - Function pointer validity 135 | * - Status tracker state 136 | * - Memory stats validity 137 | * 138 | * @param base Base strategy pointer (must be non-NULL) 139 | * @return true if valid, false otherwise 140 | * @note Thread-safe: Yes 141 | */ 142 | bool default_validate(MemoryStrategy *base); 143 | 144 | /** 145 | * @brief Gets strategy name 146 | * 147 | * @return Constant string containing strategy name 148 | * @note Thread-safe: Yes 149 | */ 150 | const char *get_strategy_name(void); 151 | 152 | /** 153 | * @brief Gets current memory usage 154 | * 155 | * @param strategy Strategy instance (must be non-NULL) 156 | * @return Current memory usage in bytes 157 | * @note Thread-safe: Yes 158 | * @warning Returns 0 if strategy is NULL 159 | */ 160 | size_t get_current_usage(const DefaultStrategy *strategy); 161 | 162 | /** 163 | * @brief Gets peak memory usage 164 | * 165 | * @param strategy Strategy instance (must be non-NULL) 166 | * @return Peak memory usage in bytes 167 | * @note Thread-safe: Yes 168 | * @warning Returns 0 if strategy is NULL 169 | */ 170 | size_t get_peak_usage(const DefaultStrategy *strategy); 171 | 172 | /** 173 | * @brief Gets total allocated memory 174 | * 175 | * @param strategy Strategy instance (must be non-NULL) 176 | * @return Total bytes allocated 177 | * @note Thread-safe: Yes 178 | * @warning Returns 0 if strategy is NULL 179 | */ 180 | size_t get_total_allocated(const DefaultStrategy *strategy); 181 | 182 | /** 183 | * @brief Gets total freed memory 184 | * 185 | * @param strategy Strategy instance (must be non-NULL) 186 | * @return Total bytes freed 187 | * @note Thread-safe: Yes 188 | * @warning Returns 0 if strategy is NULL 189 | */ 190 | size_t get_total_freed(const DefaultStrategy *strategy); 191 | // clang-format on 192 | 193 | #endif // DEFAULT_STRATEGY_H 194 | -------------------------------------------------------------------------------- /src/memory_interface/statetracker/README.md: -------------------------------------------------------------------------------- 1 | # Thread-Safe State Management System 2 | 3 | A thread-safe state management system for memory allocation strategies in C. This library provides atomic operations and memory barriers to ensure thread safety while managing state transitions. 4 | 5 | This state management system helps control how a program moves between different states (like "initialized", "active", "error") in a safe way, especially when multiple parts of the program are running concurrently. 6 | 7 | ## Features 8 | 9 | - Thread-safe state transitions with atomic operations 10 | - Overflow protection for counters 11 | - Memory barrier enforcement 12 | - Compile-time bounds checking 13 | - Comprehensive error handling 14 | - Lock-free operations 15 | - Built-in state validation 16 | 17 | ## Prerequisites 18 | 19 | - GCC compiler (supporting C11 or later) 20 | - POSIX-compliant system (Linux/Unix) 21 | - pthread library 22 | - Make build system 23 | 24 | ## Building 25 | 26 | To build the library, tests, and examples, run: 27 | 28 | ```bash 29 | make clean && make all 30 | ``` 31 | 32 | This will compile the source files into the `build/` directory, create the static library (`libstatetracker.a`), and build both the test executable and example program. 33 | 34 | To run the tests, run: 35 | 36 | ```bash 37 | make test 38 | ``` 39 | 40 | To run the example program, run: 41 | 42 | ```bash 43 | make example 44 | ``` 45 | 46 | ## Installation 47 | 48 | To install the library and header files, run: 49 | 50 | ```bash 51 | make install 52 | ``` 53 | 54 | This command creates a `lib/` directory (if it doesn't already exist) and copies the built static library (`libstatetracker.a`) from the `build/` directory along with all header files from the `include/` directory into `lib/`. 55 | 56 | ## API Reference 57 | 58 | ### Core Functions 59 | 60 | #### Initialize Status Tracker 61 | ```c 62 | StrategyResult initialize_status(StatusTracker* const tracker); 63 | ``` 64 | Initializes a new status tracker with the default state `STRATEGY_STATE_INITIALIZED`. 65 | 66 | #### Transition State 67 | ```c 68 | StrategyResult transition_status(StatusTracker* const tracker, const StrategyStatus new_status); 69 | ``` 70 | Safely transitions the tracker to a new state if the transition is valid. 71 | 72 | ### Query Functions 73 | 74 | #### Get Current Status 75 | ```c 76 | StrategyResult get_current_status(const StatusTracker* const tracker, StrategyStatus* const status); 77 | ``` 78 | Retrieves the current state of the tracker. 79 | 80 | #### Get Transition Count 81 | ```c 82 | StrategyResult get_transition_count(const StatusTracker* const tracker, uint64_t* const count); 83 | ``` 84 | Returns the total number of successful state transitions. 85 | 86 | #### Get Error Count 87 | ```c 88 | StrategyResult get_error_count(const StatusTracker* const tracker, uint64_t* const count); 89 | ``` 90 | Returns the total number of errors encountered. 91 | 92 | ### State Validation 93 | 94 | #### Check Valid Transition 95 | ```c 96 | bool is_valid_state_transition(const StrategyStatus current, const StrategyStatus next); 97 | ``` 98 | Checks if a transition between states is valid. 99 | 100 | #### Check Error State 101 | ```c 102 | bool is_error_state(const StrategyStatus status); 103 | ``` 104 | Determines if a state is an error state. 105 | 106 | #### Check Recovery Required 107 | ```c 108 | bool requires_state_recovery(const StrategyStatus status); 109 | ``` 110 | Checks if a state requires recovery action. 111 | 112 | ### State String Representation 113 | ```c 114 | const char* get_state_string(const StrategyStatus status); 115 | ``` 116 | Returns a string representation of a state. 117 | 118 | ## Example Usage 119 | 120 | Here's a basic example of using the library: 121 | 122 | ```c 123 | #include 124 | #include "strategy_status.h" 125 | 126 | int main(void) 127 | { 128 | StatusTracker tracker; 129 | 130 | // Initialize tracker 131 | if (initialize_status(&tracker) != STRATEGY_SUCCESS) { 132 | fprintf(stderr, "Failed to initialize tracker\n"); 133 | return 1; 134 | } 135 | 136 | // Transition to active state 137 | if (transition_status(&tracker, STRATEGY_STATE_ACTIVE) != STRATEGY_SUCCESS) { 138 | fprintf(stderr, "Failed to transition to active state\n"); 139 | return 1; 140 | } 141 | 142 | // Get current status 143 | StrategyStatus current; 144 | if (get_current_status(&tracker, ¤t) == STRATEGY_SUCCESS) { 145 | printf("Current status: %s\n", get_state_string(current)); 146 | } 147 | 148 | return 0; 149 | } 150 | ``` 151 | 152 | See `examples/main.c` for a complete example including thread safety and error handling. 153 | 154 | ## Thread Safety Considerations 155 | 156 | - All operations are atomic and thread-safe 157 | - Memory barriers ensure proper synchronization 158 | - Lock-free design prevents deadlocks 159 | - Overflow protection for all counters 160 | - Race condition prevention through memory ordering 161 | 162 | ### Performance Characteristics 163 | 164 | - Lock-free operations minimize contention 165 | - Atomic operations use hardware-level synchronization 166 | - Minimal memory footprint 167 | - Constant-time state transitions 168 | - Linear scaling with number of threads 169 | 170 | ## Error Handling 171 | 172 | The library returns `StrategyResult` for all operations: 173 | 174 | - `STRATEGY_SUCCESS`: Operation completed successfully 175 | - `STRATEGY_NULL_POINTER`: Null pointer provided 176 | - `STRATEGY_INVALID_STATE`: Invalid state requested 177 | - `STRATEGY_OVERFLOW`: Counter overflow detected 178 | - `STRATEGY_ATOMIC_FAILURE`: Atomic operation failed 179 | 180 | ### Error Recovery Pattern 181 | 182 | ```c 183 | if (transition_status(&tracker, STRATEGY_STATE_ERROR) == STRATEGY_SUCCESS) { 184 | // Handle error state 185 | if (requires_state_recovery(STRATEGY_STATE_ERROR)) { 186 | // Perform recovery actions 187 | transition_status(&tracker, STRATEGY_STATE_INITIALIZED); 188 | } 189 | } 190 | ``` 191 | 192 | ## Troubleshooting 193 | 194 | ### Common Issues and Solutions 195 | 196 | 1. **Runtime Errors** 197 | - Check for null pointer dereferences. 198 | - Verify that state transitions are valid. 199 | - Monitor counter overflow conditions. 200 | 201 | 2. **Performance Issues** 202 | - Reduce contention by minimizing state transitions. 203 | - Use appropriate memory ordering semantics. 204 | - Monitor error counts for excessive failures. 205 | 206 | ## Security 207 | 208 | - All operations are bounds-checked. 209 | - Memory barriers prevent reordering exploits. 210 | - Overflow protection prevents counter attacks. 211 | - Atomic operations prevent race conditions. 212 | - Constant-time operations prevent timing attacks. -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/README.md: -------------------------------------------------------------------------------- 1 | # Thread-Safe Memory Management Strategy 2 | 3 | A robust memory management system providing a flexible interface for implementing custom allocation strategies with comprehensive validation. 4 | 5 | ## Core Components 6 | 7 | ### Memory Strategy Interface (`MemoryStrategy`) 8 | 9 | The core interface that all memory management strategies must implement: 10 | 11 | ```c 12 | typedef struct MemoryStrategy { 13 | void* (*allocate)(struct MemoryStrategy* self, size_t size); 14 | void (*deallocate)(struct MemoryStrategy* self, void* ptr); 15 | StrategyStatus (*get_status)(struct MemoryStrategy* self); 16 | bool (*validate)(struct MemoryStrategy* self); 17 | void* strategy_data; // Implementation-specific data 18 | StatusTracker* status_tracker; // Thread-safe status tracking 19 | } MemoryStrategy; 20 | ``` 21 | 22 | Core Operations: 23 | - `allocate`: Thread-safe memory allocation 24 | - `deallocate`: Thread-safe memory deallocation 25 | - `get_status`: Check strategy health 26 | - `validate`: Verify strategy state 27 | 28 | ### Strategy Validator 29 | 30 | Independent validation system for memory operations: 31 | 32 | ```c 33 | // Validate strategy state and interface compliance 34 | bool validate_strategy(const MemoryStrategy* strategy); 35 | 36 | // Validate allocation parameters 37 | bool validate_allocation(const MemoryStrategy* strategy, size_t size); 38 | 39 | // Validate deallocation parameters 40 | bool validate_deallocation(const MemoryStrategy* strategy, const void* ptr); 41 | ``` 42 | 43 | ### Thread Safety 44 | 45 | All core operations are designed to be thread-safe: 46 | - Atomic status transitions 47 | - Re-entrant validation operations 48 | - Proper memory barriers 49 | - Lock-free operations 50 | 51 | ## Example Implementation 52 | 53 | A reference memory pool implementation is provided as an example of how to implement the interface. This is NOT part of the core API and should be treated as a reference only. 54 | 55 | Find it in the `memory_pool_strategy.h/.c` files. 56 | 57 | ## Usage Example 58 | 59 | ```c 60 | int main(void) { 61 | // Initialize your strategy implementation 62 | MemoryStrategy* strategy = initialize_your_strategy(); 63 | if (!strategy) { 64 | fprintf(stderr, "Failed to initialize strategy\n"); 65 | return 1; 66 | } 67 | 68 | // Verify strategy is valid 69 | if (!strategy->validate(strategy)) { 70 | fprintf(stderr, "Strategy validation failed\n"); 71 | cleanup_your_strategy(strategy); 72 | return 1; 73 | } 74 | 75 | // Allocate memory 76 | void* ptr = strategy->allocate(strategy, 1024); 77 | if (!ptr) { 78 | fprintf(stderr, "Allocation failed\n"); 79 | cleanup_your_strategy(strategy); 80 | return 1; 81 | } 82 | 83 | // Use the memory... 84 | 85 | // Free the memory 86 | strategy->deallocate(strategy, ptr); 87 | 88 | // Clean up 89 | cleanup_your_strategy(strategy); 90 | return 0; 91 | } 92 | ``` 93 | 94 | ## Thread-Safe Usage Example 95 | 96 | ```c 97 | void* worker_thread(void* arg) { 98 | MemoryStrategy* strategy = (MemoryStrategy*)arg; 99 | 100 | // Always validate before use 101 | if (!validate_strategy(strategy)) { 102 | return NULL; 103 | } 104 | 105 | // Thread-safe operations 106 | void* ptr = strategy->allocate(strategy, 1024); 107 | if (ptr && validate_deallocation(strategy, ptr)) { 108 | // Use memory... 109 | strategy->deallocate(strategy, ptr); 110 | } 111 | return NULL; 112 | } 113 | 114 | int main(void) { 115 | MemoryStrategy* strategy = initialize_your_strategy(); 116 | 117 | pthread_t thread1, thread2; 118 | pthread_create(&thread1, NULL, worker_thread, strategy); 119 | pthread_create(&thread2, NULL, worker_thread, strategy); 120 | 121 | pthread_join(thread1, NULL); 122 | pthread_join(thread2, NULL); 123 | 124 | cleanup_your_strategy(strategy); 125 | return 0; 126 | } 127 | ``` 128 | 129 | ## Building and Installation 130 | 131 | To build the library, tests, and example program, run: 132 | 133 | ```bash 134 | make clean && make all 135 | ``` 136 | 137 | This will compile the source files into the `build/` directory and produce the static library (`libmemstrategy.a`), test executables, and example program without creating the `lib/` folder. 138 | 139 | To run tests: 140 | 141 | ```bash 142 | make test 143 | ``` 144 | 145 | To build the example program: 146 | 147 | ```bash 148 | make example 149 | ``` 150 | 151 | **Installation:** 152 | To install the library and header files into the `lib/` folder, run: 153 | 154 | ```bash 155 | make install 156 | ``` 157 | 158 | The install target creates the `lib/` folder (if it doesn't exist) and copies the built library (from the `build/` folder) along with all header files from the `include/` directory into it. 159 | 160 | ## Thread Safety 161 | 162 | The library uses several techniques to ensure thread safety: 163 | 164 | 1. **Atomic Operations** 165 | - All counters use atomic types. 166 | - Updates are performed using atomic operations. 167 | - Memory ordering is carefully controlled. 168 | 169 | 2. **Lock-free Algorithms** 170 | - No mutexes or locks are used. 171 | - Compare-and-swap operations for updates. 172 | - Wait-free progress for basic operations. 173 | 174 | 3. **Contention Management** 175 | - Exponential backoff for high contention. 176 | - Randomized jitter to prevent thundering herd. 177 | - Multiple retry attempts with backoff. 178 | 179 | 4. **Memory Ordering** 180 | - Acquire/Release semantics for consistency. 181 | - Full memory barriers at critical points. 182 | - Proper synchronization of shared data. 183 | 184 | ## API Reference 185 | 186 | ### Core Functions 187 | 188 | - `void memory_stats_init(memory_stats_t* stats)` 189 | Initializes the memory statistics tracking system. Must be called before any other operations. 190 | 191 | - `void memory_stats_update_allocation(memory_stats_t* stats, void* ptr, size_t size, const char* file, int line)` 192 | Records a new memory allocation. *Thread-safe: Yes.* 193 | 194 | - `void memory_stats_update_deallocation(memory_stats_t* stats, void* ptr)` 195 | Records a memory deallocation. *Thread-safe: Yes.* 196 | 197 | - `void memory_stats_get_report(const memory_stats_t* stats, stats_report_t* report)` 198 | Generates a snapshot of current memory statistics. *Thread-safe: Yes.* 199 | 200 | ### Analysis Functions 201 | 202 | - `char* memory_stats_analyze_patterns(const memory_stats_t* stats)` 203 | Analyzes memory allocation patterns. Returns an allocated string (caller must free). *Thread-safe: Yes.* 204 | 205 | - `char* memory_stats_check_leaks(const memory_stats_t* stats)` 206 | Generates a report of memory leaks. Returns an allocated string (caller must free). *Thread-safe: Yes.* -------------------------------------------------------------------------------- /src/memory_interface/README.md: -------------------------------------------------------------------------------- 1 | # Thread-Safe Memory Management System 2 | 3 | A high-performance, thread-safe memory management system designed for concurrent applications that require precise memory tracking, leak detection, and usage statistics. This system provides a robust implementation of memory management strategies with comprehensive monitoring capabilities. 4 | 5 | ## Key Features 6 | 7 | - Thread-safe memory operations with atomic guarantees 8 | - Real-time memory usage tracking and statistics 9 | - Automatic leak detection and reporting 10 | - Peak memory usage monitoring 11 | - Comprehensive error handling and validation 12 | - Performance overhead less than 5% compared to raw malloc/free 13 | - Support for concurrent operations across multiple threads 14 | - Status tracking and state management 15 | - Memory operation debugging capabilities 16 | 17 | ## Installation 18 | 19 | ### Prerequisites 20 | 21 | The system requires the following libraries: 22 | - libmemstats 23 | - libmemstrategy 24 | - libstatetracker 25 | 26 | ### Build System 27 | 28 | The project uses a Makefile-based build system with several targets: 29 | 30 | #### Building the Static Library 31 | 32 | ```bash 33 | make lib 34 | ``` 35 | 36 | This command: 37 | 1. Creates necessary directories (`lib/`, `build/obj/`) 38 | 2. Builds all required dependencies 39 | 3. Compiles the default strategy implementation 40 | 4. Creates `lib/libdefault_strategy.a` 41 | 5. Copies header files to `lib/` 42 | 43 | #### Library Output 44 | 45 | The `lib/` directory will contain: 46 | - `libdefault_strategy.a` - The static library 47 | - All necessary header files 48 | 49 | #### Using the Library 50 | 51 | To link against the built library: 52 | 53 | ```bash 54 | gcc your_program.c -L./lib -ldefault_strategy \ 55 | -L./library -lmemstats -lmemstrategy -lstatetracker 56 | ``` 57 | 58 | #### Additional Make Targets 59 | 60 | - `make` - Builds everything (library, tests, main program) 61 | - `make test` - Builds and prepares tests 62 | - `make check` - Runs the test suite 63 | - `make clean` - Removes all built files 64 | 65 | ### Build Configuration 66 | 67 | Include the following directories in your build path: 68 | ```bash 69 | - ./memstats/include 70 | - ./memstrategy/include 71 | - ./statetracker/include 72 | - ./src 73 | ``` 74 | 75 | ### Compilation 76 | 77 | Build with threading support enabled: 78 | 79 | ```bash 80 | gcc -pthread \ 81 | -I./src \ 82 | -I./memstats/include \ 83 | -I./memstrategy/include \ 84 | -I./statetracker/include \ 85 | your_program.c src/default_strategy.c \ 86 | -L./memstats/lib \ 87 | -L./memstrategy/lib \ 88 | -L./statetracker/lib \ 89 | -lmemstats -lmemstrategy -lstatetracker 90 | ``` 91 | 92 | ## API Reference 93 | 94 | ### Core Functions 95 | 96 | #### Strategy Creation and Destruction 97 | 98 | ```c 99 | DefaultStrategy* create_default_strategy(void); 100 | void destroy_default_strategy(DefaultStrategy* strategy); 101 | ``` 102 | 103 | #### Memory Operations 104 | 105 | ```c 106 | void* default_allocate(MemoryStrategy* base, size_t size); 107 | void default_deallocate(MemoryStrategy* base, void* ptr); 108 | ``` 109 | 110 | #### Status and Validation 111 | 112 | ```c 113 | StrategyStatus default_get_status(MemoryStrategy* base); 114 | bool default_validate(MemoryStrategy* base); 115 | ``` 116 | 117 | #### Usage Statistics 118 | 119 | ```c 120 | size_t get_current_usage(const DefaultStrategy* strategy); 121 | size_t get_peak_usage(const DefaultStrategy* strategy); 122 | size_t get_total_allocated(const DefaultStrategy* strategy); 123 | size_t get_total_freed(const DefaultStrategy* strategy); 124 | ``` 125 | 126 | ### Basic Usage Example 127 | 128 | ```c 129 | #include "default_strategy.h" 130 | 131 | int main() 132 | { 133 | // Create strategy instance 134 | DefaultStrategy* strategy = create_default_strategy(); 135 | if (!strategy) { 136 | return 1; 137 | } 138 | 139 | // Allocate memory 140 | void* memory = strategy->base.allocate(&strategy->base, 1024); 141 | if (!memory) { 142 | destroy_default_strategy(strategy); 143 | return 1; 144 | } 145 | 146 | // Use memory... 147 | 148 | // Deallocate memory 149 | strategy->base.deallocate(&strategy->base, memory); 150 | 151 | // Check for leaks and cleanup 152 | destroy_default_strategy(strategy); 153 | return 0; 154 | } 155 | ``` 156 | 157 | ### Thread-Safe Usage Example 158 | 159 | ```c 160 | void* thread_function(void* arg) 161 | { 162 | DefaultStrategy* strategy = (DefaultStrategy*)arg; 163 | 164 | // Thread-safe memory operations 165 | void* memory = strategy->base.allocate(&strategy->base, 1024); 166 | if (memory) { 167 | // Use memory... 168 | strategy->base.deallocate(&strategy->base, memory); 169 | } 170 | 171 | return NULL; 172 | } 173 | 174 | // Create multiple threads 175 | pthread_t threads[4]; 176 | for (int i = 0; i < 4; i++) { 177 | pthread_create(&threads[i], NULL, thread_function, strategy); 178 | } 179 | ``` 180 | 181 | ## Memory Statistics and Monitoring 182 | 183 | The system provides comprehensive memory usage statistics: 184 | 185 | ```c 186 | DefaultStrategy* strategy = create_default_strategy(); 187 | 188 | // Get current memory usage 189 | size_t current = get_current_usage(strategy); 190 | 191 | // Get peak memory usage 192 | size_t peak = get_peak_usage(strategy); 193 | 194 | // Get total allocation statistics 195 | size_t total_alloc = get_total_allocated(strategy); 196 | size_t total_freed = get_total_freed(strategy); 197 | ``` 198 | 199 | ## Error Handling 200 | 201 | The system includes robust error handling: 202 | 203 | - Null pointer validation 204 | - Size validation 205 | - Thread safety violations detection 206 | - Memory exhaustion handling 207 | - Status tracking and state transitions 208 | - Automatic leak detection during cleanup 209 | 210 | ## Thread Safety Guarantees 211 | 212 | The implementation ensures thread safety through: 213 | 214 | - Atomic operations for all counters 215 | - Memory barriers for proper synchronization 216 | - Thread-safe status management 217 | - Safe state transitions 218 | - Protection against concurrent access issues 219 | 220 | ## Best Practices 221 | 222 | 1. Always initialize the strategy using `create_default_strategy()` 223 | 2. Check return values from allocation operations 224 | 3. Properly deallocate all memory before strategy destruction 225 | 4. Monitor memory usage using the provided statistics functions 226 | 5. Implement appropriate error handling 227 | 6. Use the validation interface before critical operations 228 | 7. Clean up resources with `destroy_default_strategy()` 229 | 230 | ## Performance Considerations 231 | 232 | - Less than 5% overhead compared to raw malloc/free 233 | - Atomic operations used judiciously to minimize contention 234 | - Efficient thread-local storage where appropriate 235 | - Optimized status tracking and state transitions 236 | - Minimal lock contention in concurrent scenarios 237 | 238 | ## Debugging 239 | 240 | The system provides several debugging capabilities: 241 | 242 | - Detailed memory statistics 243 | - Leak detection and reporting 244 | - Operation counting for tracking 245 | - Status monitoring 246 | - Comprehensive validation checks 247 | 248 | ## Limitations 249 | 250 | - Not intended for use in signal handlers or interrupt contexts 251 | - Maximum allocation size limited to SIZE_MAX/4 252 | - Requires proper cleanup to prevent resource leaks 253 | - Thread safety adds minimal performance overhead -------------------------------------------------------------------------------- /src/memory_interface/tests/test_default_strategy.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file test_default_strategy.c 3 | * @brief Test suite for DefaultStrategy implementation 4 | */ 5 | 6 | #include "test_default_strategy.h" 7 | #include "../src/default_strategy.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define MAX_RETRY_COUNT 3 17 | #define RETRY_DELAY_NS 100000 // 100 microseconds 18 | 19 | static void * 20 | concurrent_allocation_worker (void *arg) 21 | { 22 | DefaultStrategy *strategy = (DefaultStrategy *) arg; 23 | const size_t NUM_ALLOCS = 100; 24 | const size_t ALLOC_SIZE = 128; 25 | void *ptrs[100]; 26 | size_t successful_allocs = 0; 27 | 28 | atomic_thread_fence (memory_order_seq_cst); 29 | 30 | for (size_t i = 0; i < NUM_ALLOCS; i++) 31 | { 32 | ptrs[i] = default_allocate (&strategy->base, ALLOC_SIZE); 33 | if (ptrs[i]) 34 | { 35 | memset (ptrs[i], (unsigned char) i, ALLOC_SIZE); 36 | successful_allocs++; 37 | } 38 | } 39 | 40 | atomic_thread_fence (memory_order_seq_cst); 41 | 42 | for (size_t i = 0; i < successful_allocs; i++) 43 | { 44 | unsigned char *mem = (unsigned char *) ptrs[i]; 45 | for (size_t j = 0; j < ALLOC_SIZE; j++) 46 | { 47 | assert (mem[j] == (unsigned char) i); 48 | } 49 | 50 | atomic_thread_fence (memory_order_seq_cst); 51 | default_deallocate (&strategy->base, ptrs[i]); 52 | } 53 | 54 | atomic_thread_fence (memory_order_seq_cst); 55 | return NULL; 56 | } 57 | 58 | bool 59 | test_strategy_creation (void) 60 | { 61 | printf ("Running test_strategy_creation...\n"); 62 | DefaultStrategy *strategy = create_default_strategy (); 63 | if (!strategy) 64 | return false; 65 | 66 | bool success = strategy->base.allocate != NULL 67 | && strategy->base.deallocate != NULL 68 | && strategy->base.get_status != NULL 69 | && strategy->base.validate != NULL && strategy->stats != NULL; 70 | 71 | destroy_default_strategy (strategy); 72 | printf ("test_strategy_creation: %s\n", success ? "PASSED" : "FAILED"); 73 | return success; 74 | } 75 | 76 | bool 77 | test_basic_allocation (void) 78 | { 79 | printf ("Running test_basic_allocation...\n"); 80 | DefaultStrategy *strategy = create_default_strategy (); 81 | if (!strategy) 82 | return false; 83 | 84 | void *ptr = default_allocate (&strategy->base, 1024); 85 | bool success = ptr != NULL; 86 | 87 | if (success) 88 | { 89 | default_deallocate (&strategy->base, ptr); 90 | } 91 | 92 | destroy_default_strategy (strategy); 93 | printf ("test_basic_allocation: %s\n", success ? "PASSED" : "FAILED"); 94 | return success; 95 | } 96 | 97 | bool 98 | test_concurrent_allocations (void) 99 | { 100 | printf ("Running test_concurrent_allocations...\n"); 101 | DefaultStrategy *strategy = create_default_strategy (); 102 | if (!strategy) 103 | return false; 104 | 105 | const int NUM_THREADS = 4; 106 | pthread_t threads[NUM_THREADS]; 107 | bool success = true; 108 | 109 | atomic_thread_fence (memory_order_seq_cst); 110 | size_t initial_usage = get_current_usage (strategy); 111 | printf ("Initial memory usage: %zu\n", initial_usage); 112 | 113 | for (int i = 0; i < NUM_THREADS; i++) 114 | { 115 | if (pthread_create (&threads[i], NULL, concurrent_allocation_worker, 116 | strategy) 117 | != 0) 118 | { 119 | printf ("Failed to create thread %d\n", i); 120 | success = false; 121 | break; 122 | } 123 | struct timespec ts = {0, RETRY_DELAY_NS}; 124 | nanosleep (&ts, NULL); 125 | } 126 | 127 | if (success) 128 | { 129 | for (int i = 0; i < NUM_THREADS; i++) 130 | { 131 | pthread_join (threads[i], NULL); 132 | } 133 | atomic_thread_fence (memory_order_seq_cst); 134 | } 135 | 136 | atomic_thread_fence (memory_order_seq_cst); 137 | size_t final_usage = get_current_usage (strategy); 138 | printf ("Final memory usage: %zu (expected: %zu)\n", final_usage, 139 | initial_usage); 140 | success &= (final_usage == initial_usage); 141 | 142 | stats_report_t report; 143 | memory_stats_get_report (strategy->stats, &report); 144 | printf ("Active allocations: %u\n", report.active_allocation_count); 145 | printf ("Total leaked bytes: %zu\n", report.total_leaked_bytes); 146 | 147 | destroy_default_strategy (strategy); 148 | printf ("test_concurrent_allocations: %s\n", success ? "PASSED" : "FAILED"); 149 | return success; 150 | } 151 | 152 | bool 153 | test_error_handling (void) 154 | { 155 | printf ("Running test_error_handling...\n"); 156 | DefaultStrategy *strategy = create_default_strategy (); 157 | if (!strategy) 158 | return false; 159 | 160 | bool success 161 | = default_allocate (&strategy->base, 0) == NULL && // Invalid size 162 | default_allocate (NULL, 1024) == NULL && // NULL strategy 163 | default_allocate (&strategy->base, SIZE_MAX) == NULL; // Overflow 164 | 165 | destroy_default_strategy (strategy); 166 | printf ("test_error_handling: %s\n", success ? "PASSED" : "FAILED"); 167 | return success; 168 | } 169 | 170 | bool 171 | test_memory_tracking (void) 172 | { 173 | printf ("Running test_memory_tracking...\n"); 174 | DefaultStrategy *strategy = create_default_strategy (); 175 | if (!strategy) 176 | return false; 177 | 178 | void *ptr = default_allocate (&strategy->base, 1024); 179 | bool success = ptr != NULL && get_current_usage (strategy) == 1024; 180 | printf ("Current usage after allocation: %zu\n", 181 | get_current_usage (strategy)); 182 | 183 | if (success) 184 | { 185 | default_deallocate (&strategy->base, ptr); 186 | success &= get_current_usage (strategy) == 0; 187 | printf ("Current usage after deallocation: %zu\n", 188 | get_current_usage (strategy)); 189 | } 190 | 191 | destroy_default_strategy (strategy); 192 | printf ("test_memory_tracking: %s\n", success ? "PASSED" : "FAILED"); 193 | return success; 194 | } 195 | 196 | bool 197 | test_status_transitions (void) 198 | { 199 | printf ("Running test_status_transitions...\n"); 200 | DefaultStrategy *strategy = create_default_strategy (); 201 | if (!strategy) 202 | return false; 203 | 204 | StrategyStatus status = default_get_status (&strategy->base); 205 | bool success = status == STRATEGY_STATE_ACTIVE; 206 | 207 | destroy_default_strategy (strategy); 208 | printf ("test_status_transitions: %s\n", success ? "PASSED" : "FAILED"); 209 | return success; 210 | } 211 | 212 | bool 213 | test_validation (void) 214 | { 215 | printf ("Running test_validation...\n"); 216 | DefaultStrategy *strategy = create_default_strategy (); 217 | if (!strategy) 218 | return false; 219 | 220 | bool success = default_validate (&strategy->base); 221 | 222 | success &= !default_validate (NULL); 223 | 224 | destroy_default_strategy (strategy); 225 | printf ("test_validation: %s\n", success ? "PASSED" : "FAILED"); 226 | return success; 227 | } 228 | 229 | bool 230 | test_peak_usage (void) 231 | { 232 | printf ("Running test_peak_usage...\n"); 233 | DefaultStrategy *strategy = create_default_strategy (); 234 | if (!strategy) 235 | return false; 236 | 237 | void *ptr1 = default_allocate (&strategy->base, 1024); 238 | void *ptr2 = default_allocate (&strategy->base, 2048); 239 | 240 | size_t peak = get_peak_usage (strategy); 241 | printf ("Peak usage after allocations: %zu (expected: 3072)\n", peak); 242 | bool success = peak == 3072; 243 | 244 | default_deallocate (&strategy->base, ptr1); 245 | default_deallocate (&strategy->base, ptr2); 246 | 247 | peak = get_peak_usage (strategy); 248 | printf ("Peak usage after deallocations: %zu (expected: 3072)\n", peak); 249 | success &= peak == 3072; // Peak should remain unchanged 250 | 251 | destroy_default_strategy (strategy); 252 | printf ("test_peak_usage: %s\n", success ? "PASSED" : "FAILED"); 253 | return success; 254 | } 255 | 256 | int 257 | run_default_strategy_tests (void) 258 | { 259 | int passed = 0; 260 | int total = 8; 261 | 262 | printf ("\nRunning DefaultStrategy standard tests...\n"); 263 | 264 | if (test_strategy_creation ()) 265 | passed++; 266 | if (test_basic_allocation ()) 267 | passed++; 268 | if (test_concurrent_allocations ()) 269 | passed++; 270 | if (test_error_handling ()) 271 | passed++; 272 | if (test_memory_tracking ()) 273 | passed++; 274 | if (test_status_transitions ()) 275 | passed++; 276 | if (test_validation ()) 277 | passed++; 278 | if (test_peak_usage ()) 279 | passed++; 280 | 281 | printf ("\nStandard tests passed: %d/%d\n", passed, total); 282 | return passed == total ? 0 : 1; 283 | } 284 | 285 | int 286 | run_all_tests (void) 287 | { 288 | printf ("\n=== Starting Comprehensive Test Suite ===\n"); 289 | 290 | int standard_result = run_default_strategy_tests (); 291 | if (standard_result != 0) 292 | { 293 | printf ("Standard tests failed, skipping fuzzing tests\n"); 294 | return standard_result; 295 | } 296 | 297 | printf ("\n=== Starting Fuzzing Test Suite ===\n"); 298 | run_fuzz_tests (); 299 | 300 | printf ("\n=== All Tests Completed Successfully ===\n"); 301 | return 0; 302 | } 303 | 304 | int 305 | main (void) 306 | { 307 | srand ((unsigned int) time (NULL)); 308 | return run_all_tests (); 309 | } 310 | -------------------------------------------------------------------------------- /src/memory_interface/statetracker/test/strategy_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../include/strategy_status.h" 10 | 11 | #define NUM_THREADS 4 12 | #define ITERATIONS_PER_THREAD 10000 13 | #define OVERFLOW_TEST_THRESHOLD (UINT64_MAX - 100) 14 | 15 | // clang-format off 16 | static void print_test_header (const char *test_name); 17 | static void print_test_result (const char *test_name, bool passed); 18 | static void assert_strategy_success (StrategyResult result, const char *operation); 19 | static void verify_status (const StatusTracker *tracker, StrategyStatus expected); 20 | // clang-format on 21 | 22 | static volatile atomic_bool should_terminate = false; 23 | 24 | typedef struct 25 | { 26 | StatusTracker *tracker; 27 | int thread_id; 28 | uint64_t success_count; 29 | pthread_t thread; 30 | } ThreadData; 31 | 32 | /* Security: Signal handler for thread termination */ 33 | static void 34 | handle_termination (int signum) 35 | { 36 | (void) signum; /* Unused parameter */ 37 | atomic_store (&should_terminate, true); 38 | } 39 | 40 | /* Thread function for concurrent testing */ 41 | void * 42 | concurrent_transitions (void *arg) 43 | { 44 | ThreadData *data = (ThreadData *) arg; 45 | if (data == NULL || data->tracker == NULL) 46 | { 47 | return NULL; 48 | } 49 | 50 | for (int i = 0; i < ITERATIONS_PER_THREAD && !atomic_load (&should_terminate); 51 | i++) 52 | { 53 | if (transition_status (data->tracker, STRATEGY_STATE_ACTIVE) 54 | == STRATEGY_SUCCESS 55 | && transition_status (data->tracker, STRATEGY_STATE_ERROR) 56 | == STRATEGY_SUCCESS 57 | && transition_status (data->tracker, STRATEGY_STATE_INITIALIZED) 58 | == STRATEGY_SUCCESS) 59 | { 60 | data->success_count++; 61 | } 62 | } 63 | 64 | return NULL; 65 | } 66 | 67 | /* Helper function to verify status */ 68 | static void 69 | verify_status (const StatusTracker *tracker, StrategyStatus expected) 70 | { 71 | StrategyStatus current; 72 | assert_strategy_success (get_current_status (tracker, ¤t), 73 | "get_current_status"); 74 | assert (current == expected); 75 | } 76 | 77 | /* Helper function to assert strategy operation success */ 78 | static void 79 | assert_strategy_success (StrategyResult result, const char *operation) 80 | { 81 | if (result != STRATEGY_SUCCESS) 82 | { 83 | printf ("Operation %s failed with error code: %d\n", operation, result); 84 | assert (false); 85 | } 86 | } 87 | 88 | void 89 | test_initialization (void) 90 | { 91 | print_test_header ("Initialization"); 92 | 93 | StatusTracker tracker; 94 | assert_strategy_success (initialize_status (&tracker), "initialize_status"); 95 | 96 | /* Verify initial state */ 97 | verify_status (&tracker, STRATEGY_STATE_INITIALIZED); 98 | 99 | uint64_t count; 100 | assert_strategy_success (get_transition_count (&tracker, &count), 101 | "get_transition_count"); 102 | assert (count == 0); 103 | 104 | assert_strategy_success (get_error_count (&tracker, &count), 105 | "get_error_count"); 106 | assert (count == 0); 107 | 108 | /* Security: Test NULL pointer handling */ 109 | assert (initialize_status (NULL) == STRATEGY_NULL_POINTER); 110 | 111 | print_test_result ("Initialization", true); 112 | } 113 | 114 | void 115 | test_overflow_protection (void) 116 | { 117 | print_test_header ("Overflow Protection"); 118 | 119 | StatusTracker tracker; 120 | assert_strategy_success (initialize_status (&tracker), "initialize_status"); 121 | 122 | /* Set counters near maximum */ 123 | atomic_store_explicit (&tracker.transition_count, OVERFLOW_TEST_THRESHOLD, 124 | memory_order_seq_cst); 125 | atomic_store_explicit (&tracker.error_count, OVERFLOW_TEST_THRESHOLD, 126 | memory_order_seq_cst); 127 | 128 | /* Attempt to cause overflow */ 129 | for (int i = 0; i < 200; i++) 130 | { 131 | StrategyResult result = transition_status (&tracker, STRATEGY_STATE_ERROR); 132 | if (result == STRATEGY_OVERFLOW) 133 | { 134 | break; /* Expected behavior when approaching UINT64_MAX */ 135 | } 136 | 137 | result = transition_status (&tracker, STRATEGY_STATE_INITIALIZED); 138 | if (result == STRATEGY_OVERFLOW) 139 | { 140 | break; /* Expected behavior when approaching UINT64_MAX */ 141 | } 142 | } 143 | 144 | /* Verify no overflow occurred */ 145 | uint64_t count; 146 | assert_strategy_success (get_transition_count (&tracker, &count), 147 | "get_transition_count"); 148 | assert (count <= UINT64_MAX); 149 | 150 | assert_strategy_success (get_error_count (&tracker, &count), 151 | "get_error_count"); 152 | assert (count <= UINT64_MAX); 153 | 154 | print_test_result ("Overflow Protection", true); 155 | } 156 | 157 | void 158 | test_memory_barriers (void) 159 | { 160 | print_test_header ("Memory Barriers"); 161 | 162 | StatusTracker tracker; 163 | assert_strategy_success (initialize_status (&tracker), "initialize_status"); 164 | 165 | /* Test acquire-release semantics */ 166 | atomic_thread_fence (memory_order_acquire); 167 | verify_status (&tracker, STRATEGY_STATE_INITIALIZED); 168 | 169 | atomic_thread_fence (memory_order_release); 170 | assert_strategy_success (transition_status (&tracker, STRATEGY_STATE_ACTIVE), 171 | "transition_status"); 172 | 173 | print_test_result ("Memory Barriers", true); 174 | } 175 | 176 | void 177 | test_thread_safety (void) 178 | { 179 | print_test_header ("Thread Safety"); 180 | 181 | StatusTracker tracker; 182 | assert_strategy_success (initialize_status (&tracker), "initialize_status"); 183 | 184 | /* Setup signal handler */ 185 | struct sigaction sa; 186 | memset (&sa, 0, sizeof (sa)); 187 | sa.sa_handler = handle_termination; 188 | sigaction (SIGTERM, &sa, NULL); 189 | 190 | ThreadData thread_data[NUM_THREADS]; 191 | atomic_store (&should_terminate, false); 192 | 193 | /* Initialize and start threads */ 194 | for (int i = 0; i < NUM_THREADS; i++) 195 | { 196 | thread_data[i].tracker = &tracker; 197 | thread_data[i].thread_id = i; 198 | thread_data[i].success_count = 0; 199 | pthread_create (&thread_data[i].thread, NULL, concurrent_transitions, 200 | &thread_data[i]); 201 | } 202 | 203 | /* Wait for all threads to complete */ 204 | for (int i = 0; i < NUM_THREADS; i++) 205 | { 206 | pthread_join (thread_data[i].thread, NULL); 207 | } 208 | 209 | /* Verify results */ 210 | uint64_t total_success = 0; 211 | for (int i = 0; i < NUM_THREADS; i++) 212 | { 213 | total_success += thread_data[i].success_count; 214 | } 215 | 216 | uint64_t transitions, errors; 217 | assert_strategy_success (get_transition_count (&tracker, &transitions), 218 | "get_transition_count"); 219 | assert_strategy_success (get_error_count (&tracker, &errors), 220 | "get_error_count"); 221 | 222 | printf ("Thread safety results:\n"); 223 | printf ("- Total successful transition sequences: %lu\n", total_success); 224 | printf ("- Total transitions: %lu\n", transitions); 225 | printf ("- Total errors: %lu\n", errors); 226 | 227 | assert (transitions > 0); 228 | assert (total_success > 0); 229 | 230 | print_test_result ("Thread Safety", true); 231 | } 232 | 233 | void 234 | test_error_handling (void) 235 | { 236 | print_test_header ("Error Handling"); 237 | 238 | StatusTracker tracker; 239 | assert_strategy_success (initialize_status (&tracker), "initialize_status"); 240 | 241 | /* Test invalid state transitions */ 242 | assert (transition_status (&tracker, (StrategyStatus) 99) 243 | == STRATEGY_INVALID_STATE); 244 | assert (transition_status (&tracker, (StrategyStatus) -1) 245 | == STRATEGY_INVALID_STATE); 246 | 247 | /* Test NULL pointer handling */ 248 | StrategyStatus status; 249 | uint64_t count; 250 | assert (get_current_status (NULL, &status) == STRATEGY_NULL_POINTER); 251 | assert (get_transition_count (NULL, &count) == STRATEGY_NULL_POINTER); 252 | assert (get_error_count (NULL, &count) == STRATEGY_NULL_POINTER); 253 | assert (transition_status (NULL, STRATEGY_STATE_ACTIVE) 254 | == STRATEGY_NULL_POINTER); 255 | 256 | /* Test error state handling */ 257 | assert_strategy_success (transition_status (&tracker, STRATEGY_STATE_ERROR), 258 | "transition_to_error"); 259 | verify_status (&tracker, STRATEGY_STATE_ERROR); 260 | assert (is_error_state (STRATEGY_STATE_ERROR)); 261 | assert (requires_state_recovery (STRATEGY_STATE_ERROR)); 262 | 263 | print_test_result ("Error Handling", true); 264 | } 265 | 266 | /* Test helper function implementations */ 267 | static void 268 | print_test_header (const char *test_name) 269 | { 270 | printf ("\nRunning %s test...\n", test_name); 271 | } 272 | 273 | static void 274 | print_test_result (const char *test_name, bool passed) 275 | { 276 | printf ("✓ %s test %s\n", test_name, passed ? "passed" : "failed"); 277 | } 278 | 279 | int 280 | main (void) 281 | { 282 | printf ("Running StatusTracker Security Tests...\n"); 283 | printf ("=====================================\n"); 284 | 285 | test_initialization (); 286 | test_overflow_protection (); 287 | test_memory_barriers (); 288 | test_thread_safety (); 289 | test_error_handling (); 290 | 291 | printf ("\nAll security tests completed successfully!\n"); 292 | return 0; 293 | } 294 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/src/strategy_status.c: -------------------------------------------------------------------------------- 1 | #include "../include/strategy_status.h" 2 | #include 3 | #include 4 | #include 5 | 6 | _Static_assert (STRATEGY_MAX_STATE == 3, 7 | "StrategyStatus enum has unexpected number of states"); 8 | 9 | /** 10 | * @brief State transition validation matrix 11 | * Each row represents the current state, each column represents the next state. 12 | * A value of 1 indicates a valid transition, 0 indicates invalid. 13 | * @security Matrix bounds are checked at runtime and compile time 14 | */ 15 | static const uint8_t VALID_TRANSITIONS[4][4] = { 16 | /* TO_STATE */ 17 | /* FROM_STATE INIT ACTIVE ERROR TRANS */ 18 | /* INITIALIZED */ {0, 1, 1, 1}, 19 | /* ACTIVE */ {0, 0, 1, 1}, 20 | /* ERROR */ {1, 1, 0, 1}, 21 | /* TRANS */ {1, 1, 1, 0}}; 22 | 23 | _Static_assert (sizeof (VALID_TRANSITIONS) / sizeof (VALID_TRANSITIONS[0]) 24 | == STRATEGY_MAX_STATE + 1, 25 | "Transition matrix size mismatch"); 26 | 27 | /** 28 | * @brief Status string lookup table for thread-safe access 29 | * @note Array size is validated at compile time 30 | */ 31 | static const char *const STATUS_STRINGS[] = { 32 | "INITIALIZED", "ACTIVE", "ERROR", "TRANSITIONING", 33 | "UNKNOWN" /* Used for out-of-bounds status values */ 34 | }; 35 | 36 | _Static_assert (sizeof (STATUS_STRINGS) / sizeof (STATUS_STRINGS[0]) 37 | == STRATEGY_MAX_STATE + 2, 38 | "Status strings array size mismatch"); 39 | 40 | static StrategyResult 41 | check_counter_overflow (const uint64_t current_value) 42 | { 43 | return (current_value >= UINT64_MAX) ? STRATEGY_OVERFLOW : STRATEGY_SUCCESS; 44 | } 45 | 46 | static StrategyResult 47 | perform_atomic_increment (volatile _Atomic (uint64_t) *const counter, 48 | const uint64_t old_value) 49 | { 50 | bool success 51 | = atomic_compare_exchange_weak_explicit (counter, &old_value, old_value + 1, 52 | memory_order_seq_cst, 53 | memory_order_seq_cst); 54 | return success ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 55 | } 56 | 57 | static StrategyResult 58 | atomic_increment_with_check (volatile _Atomic (uint64_t) *const counter) 59 | { 60 | if (counter == NULL) 61 | return STRATEGY_NULL_POINTER; 62 | 63 | uint64_t old_count; 64 | bool counter_updated = false; 65 | 66 | for (int retry = 0; retry < STRATEGY_MAX_RETRIES && !counter_updated; retry++) 67 | { 68 | old_count = atomic_load_explicit (counter, memory_order_acquire); 69 | 70 | StrategyResult overflow_check = check_counter_overflow (old_count); 71 | if (overflow_check != STRATEGY_SUCCESS) 72 | return overflow_check; 73 | 74 | StrategyResult increment_result 75 | = perform_atomic_increment (counter, old_count); 76 | if (increment_result == STRATEGY_SUCCESS) 77 | counter_updated = true; 78 | } 79 | 80 | return counter_updated ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 81 | } 82 | 83 | static StrategyResult 84 | validate_state_transition (const StrategyStatus current, 85 | const StrategyStatus next) 86 | { 87 | if (current > STRATEGY_MAX_STATE || next > STRATEGY_MAX_STATE) 88 | return STRATEGY_INVALID_STATE; 89 | 90 | return VALID_TRANSITIONS[current][next] ? STRATEGY_SUCCESS 91 | : STRATEGY_INVALID_STATE; 92 | } 93 | 94 | static StrategyResult 95 | perform_atomic_operation (volatile _Atomic (StrategyStatus) *const status, 96 | const StrategyStatus current_status, 97 | const StrategyStatus new_status) 98 | { 99 | bool success 100 | = atomic_compare_exchange_strong_explicit (status, ¤t_status, 101 | new_status, memory_order_seq_cst, 102 | memory_order_seq_cst); 103 | 104 | if (!atomic_is_lock_free (status)) 105 | return STRATEGY_ATOMIC_FAILURE; 106 | 107 | return success ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 108 | } 109 | 110 | static StrategyResult 111 | atomic_transition_status (volatile _Atomic (StrategyStatus) *const status, 112 | const StrategyStatus new_status) 113 | { 114 | if (status == NULL) 115 | return STRATEGY_NULL_POINTER; 116 | 117 | StrategyStatus current_status; 118 | bool success = false; 119 | 120 | for (int retry = 0; retry < STRATEGY_MAX_RETRIES && !success; retry++) 121 | { 122 | current_status = atomic_load_explicit (status, memory_order_acquire); 123 | 124 | StrategyResult validation_result 125 | = validate_state_transition (current_status, new_status); 126 | if (validation_result != STRATEGY_SUCCESS) 127 | return validation_result; 128 | 129 | StrategyResult operation_result 130 | = perform_atomic_operation (status, current_status, new_status); 131 | if (operation_result == STRATEGY_SUCCESS) 132 | success = true; 133 | } 134 | 135 | return success ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 136 | } 137 | 138 | /* Helper function prototypes */ 139 | static StrategyResult 140 | validate_transition_input (const StatusTracker *tracker, 141 | StrategyStatus new_status); 142 | static StrategyResult 143 | handle_state_transition (StatusTracker *tracker, StrategyStatus new_status); 144 | static StrategyResult 145 | update_transition_counters (StatusTracker *tracker, StrategyStatus new_status); 146 | 147 | /* Input validation for transition */ 148 | static StrategyResult 149 | validate_transition_input (const StatusTracker *tracker, 150 | StrategyStatus new_status) 151 | { 152 | if (tracker == NULL) 153 | return STRATEGY_NULL_POINTER; 154 | if (new_status > STRATEGY_MAX_STATE) 155 | return STRATEGY_INVALID_STATE; 156 | return STRATEGY_SUCCESS; 157 | } 158 | 159 | /* Handle the actual state transition */ 160 | static StrategyResult 161 | handle_state_transition (StatusTracker *tracker, StrategyStatus new_status) 162 | { 163 | atomic_thread_fence (memory_order_seq_cst); 164 | StrategyResult result 165 | = atomic_transition_status (&tracker->current_status, new_status); 166 | if (result != STRATEGY_SUCCESS) 167 | return result; 168 | return STRATEGY_SUCCESS; 169 | } 170 | 171 | /* Update transition and error counters */ 172 | static StrategyResult 173 | update_transition_counters (StatusTracker *tracker, StrategyStatus new_status) 174 | { 175 | StrategyResult result 176 | = atomic_increment_with_check (&tracker->transition_count); 177 | if (result != STRATEGY_SUCCESS) 178 | return result; 179 | 180 | if (new_status == STRATEGY_STATE_ERROR) 181 | { 182 | result = atomic_increment_with_check (&tracker->error_count); 183 | if (result != STRATEGY_SUCCESS) 184 | return result; 185 | } 186 | return STRATEGY_SUCCESS; 187 | } 188 | 189 | /* Main transition status function */ 190 | StrategyResult 191 | transition_status (StatusTracker *const tracker, 192 | const StrategyStatus new_status) 193 | { 194 | StrategyResult result = validate_transition_input (tracker, new_status); 195 | if (result != STRATEGY_SUCCESS) 196 | return result; 197 | 198 | result = handle_state_transition (tracker, new_status); 199 | if (result != STRATEGY_SUCCESS) 200 | return result; 201 | 202 | result = update_transition_counters (tracker, new_status); 203 | if (result != STRATEGY_SUCCESS) 204 | return result; 205 | 206 | atomic_thread_fence (memory_order_seq_cst); 207 | return STRATEGY_SUCCESS; 208 | } 209 | 210 | StrategyResult 211 | initialize_status (StatusTracker *const tracker) 212 | { 213 | if (tracker == NULL) 214 | return STRATEGY_NULL_POINTER; 215 | 216 | atomic_thread_fence (memory_order_seq_cst); 217 | 218 | atomic_init (&tracker->current_status, STRATEGY_STATE_INITIALIZED); 219 | atomic_store_explicit (&tracker->transition_count, 0, memory_order_seq_cst); 220 | atomic_store_explicit (&tracker->error_count, 0, memory_order_seq_cst); 221 | 222 | atomic_thread_fence (memory_order_seq_cst); 223 | 224 | return STRATEGY_SUCCESS; 225 | } 226 | 227 | StrategyResult 228 | get_current_status (const StatusTracker *const tracker, 229 | StrategyStatus *const status) 230 | { 231 | if (tracker == NULL || status == NULL) 232 | return STRATEGY_NULL_POINTER; 233 | 234 | atomic_thread_fence (memory_order_seq_cst); 235 | *status 236 | = atomic_load_explicit (&tracker->current_status, memory_order_acquire); 237 | return STRATEGY_SUCCESS; 238 | } 239 | 240 | StrategyResult 241 | get_transition_count (const StatusTracker *const tracker, uint64_t *const count) 242 | { 243 | if (tracker == NULL || count == NULL) 244 | return STRATEGY_NULL_POINTER; 245 | 246 | atomic_thread_fence (memory_order_acquire); 247 | *count 248 | = atomic_load_explicit (&tracker->transition_count, memory_order_acquire); 249 | return STRATEGY_SUCCESS; 250 | } 251 | 252 | StrategyResult 253 | get_error_count (const StatusTracker *const tracker, uint64_t *const count) 254 | { 255 | if (tracker == NULL || count == NULL) 256 | { 257 | return STRATEGY_NULL_POINTER; 258 | } 259 | 260 | atomic_thread_fence (memory_order_acquire); 261 | *count = atomic_load_explicit (&tracker->error_count, memory_order_acquire); 262 | return STRATEGY_SUCCESS; 263 | } 264 | 265 | bool 266 | is_valid_state_transition (const StrategyStatus current, 267 | const StrategyStatus next) 268 | { 269 | return validate_state_transition (current, next) == STRATEGY_SUCCESS; 270 | } 271 | 272 | bool 273 | is_error_state (const StrategyStatus status) 274 | { 275 | return status <= STRATEGY_MAX_STATE && status == STRATEGY_STATE_ERROR; 276 | } 277 | 278 | bool 279 | requires_state_recovery (const StrategyStatus status) 280 | { 281 | if (status > STRATEGY_MAX_STATE) 282 | return false; 283 | return status == STRATEGY_STATE_ERROR 284 | || status == STRATEGY_STATE_TRANSITIONING; 285 | } 286 | 287 | const char * 288 | get_state_string (const StrategyStatus status) 289 | { 290 | return (status <= STRATEGY_MAX_STATE) 291 | ? STATUS_STRINGS[status] 292 | : STATUS_STRINGS[STRATEGY_MAX_STATE + 1]; 293 | } 294 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/test/pool_strategy_test.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pool_strategy_test.c 3 | * @brief Test suite for memory pool strategy implementation 4 | */ 5 | 6 | #include "memory_pool_strategy.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define SMALL_ALLOC_SIZE 64 15 | #define MEDIUM_ALLOC_SIZE (POOL_BLOCK_SIZE - sizeof (size_t)) 16 | #define LARGE_ALLOC_SIZE (POOL_BLOCK_SIZE * 2) 17 | #define NUM_THREADS 4 18 | #define NUM_ALLOCATIONS 10 19 | #define MAX_RETRIES 3 20 | 21 | typedef struct 22 | { 23 | MemoryStrategy *strategy; 24 | int thread_id; 25 | size_t allocation_size; 26 | int num_allocations; 27 | atomic_bool *success; 28 | char *error_msg; 29 | size_t error_msg_size; 30 | } ThreadData; 31 | 32 | static void 33 | test_pool_creation (void) 34 | { 35 | printf ("Testing pool creation and destruction...\n"); 36 | 37 | // Test creation 38 | MemoryStrategy *strategy = create_pool_strategy (); 39 | assert (strategy != NULL); 40 | assert (strategy->strategy_data != NULL); 41 | assert (strategy->allocate != NULL); 42 | assert (strategy->deallocate != NULL); 43 | assert (strategy->get_status != NULL); 44 | assert (strategy->validate != NULL); 45 | 46 | // Test initial state 47 | assert (strategy->get_status (strategy) == STRATEGY_STATE_ACTIVE); 48 | assert (strategy->validate (strategy) == true); 49 | 50 | // Test destruction 51 | destroy_pool_strategy (strategy); 52 | printf ("Pool creation and destruction tests passed\n"); 53 | } 54 | 55 | static void 56 | test_basic_allocation (void) 57 | { 58 | printf ("Testing basic allocation operations...\n"); 59 | 60 | MemoryStrategy *strategy = create_pool_strategy (); 61 | assert (strategy != NULL); 62 | 63 | // Test small allocation 64 | void *ptr1 = strategy->allocate (strategy, SMALL_ALLOC_SIZE); 65 | assert (ptr1 != NULL); 66 | memset (ptr1, 0xAA, SMALL_ALLOC_SIZE); 67 | 68 | // Test medium allocation 69 | void *ptr2 = strategy->allocate (strategy, MEDIUM_ALLOC_SIZE); 70 | assert (ptr2 != NULL); 71 | memset (ptr2, 0xBB, MEDIUM_ALLOC_SIZE); 72 | 73 | // Test large allocation 74 | void *ptr3 = strategy->allocate (strategy, LARGE_ALLOC_SIZE); 75 | assert (ptr3 != NULL); 76 | memset (ptr3, 0xCC, LARGE_ALLOC_SIZE); 77 | 78 | // Verify memory isolation 79 | unsigned char *check1 = ptr1; 80 | unsigned char *check2 = ptr2; 81 | unsigned char *check3 = ptr3; 82 | 83 | for (size_t i = 0; i < SMALL_ALLOC_SIZE; i++) 84 | { 85 | assert (check1[i] == 0xAA); 86 | } 87 | for (size_t i = 0; i < MEDIUM_ALLOC_SIZE; i++) 88 | { 89 | assert (check2[i] == 0xBB); 90 | } 91 | for (size_t i = 0; i < LARGE_ALLOC_SIZE; i++) 92 | { 93 | assert (check3[i] == 0xCC); 94 | } 95 | 96 | // Test deallocation 97 | strategy->deallocate (strategy, ptr1); 98 | strategy->deallocate (strategy, ptr2); 99 | strategy->deallocate (strategy, ptr3); 100 | 101 | // Verify pool state after deallocation 102 | assert (strategy->get_status (strategy) == STRATEGY_STATE_ACTIVE); 103 | assert (strategy->validate (strategy) == true); 104 | 105 | destroy_pool_strategy (strategy); 106 | printf ("Basic allocation tests passed\n"); 107 | } 108 | 109 | static void 110 | test_boundary_conditions (void) 111 | { 112 | printf ("Testing boundary conditions...\n"); 113 | 114 | MemoryStrategy *strategy = create_pool_strategy (); 115 | assert (strategy != NULL); 116 | 117 | // Test zero allocation 118 | void *ptr = strategy->allocate (strategy, 0); 119 | assert (ptr == NULL); 120 | 121 | // Test minimum allocation 122 | ptr = strategy->allocate (strategy, POOL_MIN_ALLOCATION); 123 | assert (ptr != NULL); 124 | strategy->deallocate (strategy, ptr); 125 | 126 | // Test maximum allocation 127 | ptr = strategy->allocate (strategy, POOL_MAX_ALLOCATION); 128 | assert (ptr != NULL); 129 | strategy->deallocate (strategy, ptr); 130 | 131 | // Test overflow allocation 132 | ptr = strategy->allocate (strategy, SIZE_MAX); 133 | assert (ptr == NULL); 134 | 135 | // Test double free 136 | ptr = strategy->allocate (strategy, SMALL_ALLOC_SIZE); 137 | assert (ptr != NULL); 138 | strategy->deallocate (strategy, ptr); 139 | strategy->deallocate (strategy, ptr); // Should not crash 140 | 141 | // Test invalid pointer deallocation 142 | strategy->deallocate (strategy, (void *) 0x1000); // Should not crash 143 | 144 | destroy_pool_strategy (strategy); 145 | printf ("Boundary condition tests passed\n"); 146 | } 147 | 148 | static void 149 | test_fragmentation_handling (void) 150 | { 151 | printf ("Testing fragmentation handling...\n"); 152 | 153 | MemoryStrategy *strategy = create_pool_strategy (); 154 | void *ptrs[100]; 155 | int alloc_count = 0; 156 | 157 | // Allocate alternating sizes to create fragmentation 158 | for (int i = 0; i < 100; i++) 159 | { 160 | size_t size = (i % 2) ? SMALL_ALLOC_SIZE : MEDIUM_ALLOC_SIZE; 161 | ptrs[i] = strategy->allocate (strategy, size); 162 | if (ptrs[i] != NULL) 163 | { 164 | alloc_count++; 165 | } 166 | } 167 | 168 | // Free every other allocation 169 | for (int i = 0; i < alloc_count; i += 2) 170 | { 171 | strategy->deallocate (strategy, ptrs[i]); 172 | } 173 | 174 | // Try to allocate in the gaps 175 | bool allocated_in_gaps = false; 176 | for (int i = 0; i < 10; i++) 177 | { 178 | void *ptr = strategy->allocate (strategy, SMALL_ALLOC_SIZE); 179 | if (ptr != NULL) 180 | { 181 | strategy->deallocate (strategy, ptr); 182 | allocated_in_gaps = true; 183 | break; 184 | } 185 | } 186 | assert (allocated_in_gaps); 187 | 188 | // Cleanup remaining allocations 189 | for (int i = 1; i < alloc_count; i += 2) 190 | { 191 | strategy->deallocate (strategy, ptrs[i]); 192 | } 193 | 194 | destroy_pool_strategy (strategy); 195 | printf ("Fragmentation handling tests passed\n"); 196 | } 197 | 198 | static void * 199 | concurrent_allocation_thread (void *arg) 200 | { 201 | ThreadData *data = (ThreadData *) arg; 202 | void *ptrs[NUM_ALLOCATIONS]; 203 | memset (ptrs, 0, sizeof (ptrs)); 204 | 205 | // First phase: Allocations 206 | for (int i = 0; i < data->num_allocations; i++) 207 | { 208 | int retries = 0; 209 | while (retries < MAX_RETRIES) 210 | { 211 | ptrs[i] 212 | = data->strategy->allocate (data->strategy, data->allocation_size); 213 | if (ptrs[i]) 214 | break; 215 | retries++; 216 | } 217 | 218 | if (!ptrs[i]) 219 | { 220 | snprintf (data->error_msg, data->error_msg_size, 221 | "Thread %d: Failed to allocate block %d after %d retries", 222 | data->thread_id, i, MAX_RETRIES); 223 | atomic_store (data->success, false); 224 | goto cleanup; 225 | } 226 | 227 | // Write unique pattern 228 | memset (ptrs[i], (unsigned char) (data->thread_id * NUM_ALLOCATIONS + i), 229 | data->allocation_size); 230 | } 231 | 232 | // Second phase: Memory verification 233 | for (int i = 0; i < data->num_allocations; i++) 234 | { 235 | unsigned char *check = ptrs[i]; 236 | unsigned char pattern 237 | = (unsigned char) (data->thread_id * NUM_ALLOCATIONS + i); 238 | for (size_t j = 0; j < data->allocation_size; j++) 239 | { 240 | if (check[j] != pattern) 241 | { 242 | snprintf ( 243 | data->error_msg, data->error_msg_size, 244 | "Thread %d: Memory corruption detected in block %d at offset %zu", 245 | data->thread_id, i, j); 246 | atomic_store (data->success, false); 247 | goto cleanup; 248 | } 249 | } 250 | } 251 | 252 | cleanup: 253 | // Final phase: Cleanup 254 | for (int i = 0; i < data->num_allocations; i++) 255 | { 256 | if (ptrs[i]) 257 | { 258 | data->strategy->deallocate (data->strategy, ptrs[i]); 259 | } 260 | } 261 | 262 | return NULL; 263 | } 264 | 265 | static void 266 | test_concurrent_allocations (void) 267 | { 268 | printf ("Testing concurrent allocations...\n"); 269 | 270 | MemoryStrategy *strategy = create_pool_strategy (); 271 | assert (strategy != NULL); 272 | 273 | pthread_t threads[NUM_THREADS]; 274 | ThreadData thread_data[NUM_THREADS]; 275 | atomic_bool success = ATOMIC_VAR_INIT (true); 276 | char error_msgs[NUM_THREADS][256]; 277 | 278 | // Create threads with different allocation patterns 279 | for (int i = 0; i < NUM_THREADS; i++) 280 | { 281 | thread_data[i].strategy = strategy; 282 | thread_data[i].thread_id = i; 283 | thread_data[i].allocation_size = SMALL_ALLOC_SIZE; 284 | thread_data[i].num_allocations = NUM_ALLOCATIONS; 285 | thread_data[i].success = &success; 286 | thread_data[i].error_msg = error_msgs[i]; 287 | thread_data[i].error_msg_size = sizeof (error_msgs[i]); 288 | 289 | int rc = pthread_create (&threads[i], NULL, concurrent_allocation_thread, 290 | &thread_data[i]); 291 | assert (rc == 0); 292 | } 293 | 294 | // Wait for all threads 295 | for (int i = 0; i < NUM_THREADS; i++) 296 | { 297 | pthread_join (threads[i], NULL); 298 | } 299 | 300 | // Check for errors 301 | if (!atomic_load (&success)) 302 | { 303 | for (int i = 0; i < NUM_THREADS; i++) 304 | { 305 | if (error_msgs[i][0] != '\0') 306 | { 307 | printf ("Error: %s\n", error_msgs[i]); 308 | } 309 | } 310 | } 311 | 312 | assert (atomic_load (&success)); 313 | assert (strategy->validate (strategy)); 314 | 315 | destroy_pool_strategy (strategy); 316 | printf ("Concurrent allocation tests passed\n"); 317 | } 318 | 319 | int 320 | main (void) 321 | { 322 | printf ("Running memory pool strategy tests...\n\n"); 323 | 324 | test_pool_creation (); 325 | test_basic_allocation (); 326 | test_boundary_conditions (); 327 | test_fragmentation_handling (); 328 | test_concurrent_allocations (); 329 | 330 | printf ("\nAll memory pool strategy tests passed successfully!\n"); 331 | return 0; 332 | } 333 | -------------------------------------------------------------------------------- /src/memory_interface/statetracker/src/strategy_status.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file strategy_status.c 3 | * @brief Thread-safe state management system 4 | */ 5 | 6 | #include "../include/strategy_status.h" 7 | #include 8 | #include 9 | #include 10 | 11 | _Static_assert (STRATEGY_MAX_STATE == 3, 12 | "StrategyStatus enum has unexpected number of states"); 13 | 14 | /** 15 | * @brief State transition validation matrix 16 | * Each row represents the current state, each column represents the next state. 17 | * A value of 1 indicates a valid transition, 0 indicates invalid. 18 | * @security Matrix bounds are checked at runtime and compile time 19 | */ 20 | static const uint8_t VALID_TRANSITIONS[4][4] = { 21 | /* TO_STATE */ 22 | /* FROM_STATE INIT ACTIVE ERROR TRANS */ 23 | /* INITIALIZED */ {0, 1, 1, 1}, 24 | /* ACTIVE */ {0, 0, 1, 1}, 25 | /* ERROR */ {1, 1, 0, 1}, 26 | /* TRANS */ {1, 1, 1, 0}}; 27 | 28 | _Static_assert (sizeof (VALID_TRANSITIONS) / sizeof (VALID_TRANSITIONS[0]) 29 | == STRATEGY_MAX_STATE + 1, 30 | "Transition matrix size mismatch"); 31 | 32 | /** 33 | * @brief Status string lookup table for thread-safe access 34 | * @note Array size is validated at compile time 35 | */ 36 | static const char *const STATUS_STRINGS[] = { 37 | "INITIALIZED", "ACTIVE", "ERROR", "TRANSITIONING", 38 | "UNKNOWN" /* Used for out-of-bounds status values */ 39 | }; 40 | 41 | _Static_assert (sizeof (STATUS_STRINGS) / sizeof (STATUS_STRINGS[0]) 42 | == STRATEGY_MAX_STATE + 2, 43 | "Status strings array size mismatch"); 44 | 45 | static StrategyResult 46 | check_counter_overflow (const uint64_t current_value) 47 | { 48 | return (current_value >= UINT64_MAX) ? STRATEGY_OVERFLOW : STRATEGY_SUCCESS; 49 | } 50 | 51 | static StrategyResult 52 | perform_atomic_increment (volatile _Atomic (uint64_t) *const counter, 53 | const uint64_t old_value) 54 | { 55 | bool success 56 | = atomic_compare_exchange_weak_explicit (counter, &old_value, old_value + 1, 57 | memory_order_seq_cst, 58 | memory_order_seq_cst); 59 | return success ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 60 | } 61 | 62 | static StrategyResult 63 | atomic_increment_with_check (volatile _Atomic (uint64_t) *const counter) 64 | { 65 | if (counter == NULL) 66 | return STRATEGY_NULL_POINTER; 67 | 68 | uint64_t old_count; 69 | bool counter_updated = false; 70 | 71 | for (int retry = 0; retry < STRATEGY_MAX_RETRIES && !counter_updated; retry++) 72 | { 73 | old_count = atomic_load_explicit (counter, memory_order_acquire); 74 | 75 | StrategyResult overflow_check = check_counter_overflow (old_count); 76 | if (overflow_check != STRATEGY_SUCCESS) 77 | return overflow_check; 78 | 79 | StrategyResult increment_result 80 | = perform_atomic_increment (counter, old_count); 81 | if (increment_result == STRATEGY_SUCCESS) 82 | counter_updated = true; 83 | } 84 | 85 | return counter_updated ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 86 | } 87 | 88 | static StrategyResult 89 | validate_state_transition (const StrategyStatus current, 90 | const StrategyStatus next) 91 | { 92 | if (current > STRATEGY_MAX_STATE || next > STRATEGY_MAX_STATE) 93 | return STRATEGY_INVALID_STATE; 94 | 95 | return VALID_TRANSITIONS[current][next] ? STRATEGY_SUCCESS 96 | : STRATEGY_INVALID_STATE; 97 | } 98 | 99 | static StrategyResult 100 | perform_atomic_operation (volatile _Atomic (StrategyStatus) *const status, 101 | const StrategyStatus current_status, 102 | const StrategyStatus new_status) 103 | { 104 | bool success 105 | = atomic_compare_exchange_strong_explicit (status, ¤t_status, 106 | new_status, memory_order_seq_cst, 107 | memory_order_seq_cst); 108 | 109 | if (!atomic_is_lock_free (status)) 110 | return STRATEGY_ATOMIC_FAILURE; 111 | 112 | return success ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 113 | } 114 | 115 | static StrategyResult 116 | atomic_transition_status (volatile _Atomic (StrategyStatus) *const status, 117 | const StrategyStatus new_status) 118 | { 119 | if (status == NULL) 120 | return STRATEGY_NULL_POINTER; 121 | 122 | StrategyStatus current_status; 123 | bool success = false; 124 | 125 | for (int retry = 0; retry < STRATEGY_MAX_RETRIES && !success; retry++) 126 | { 127 | current_status = atomic_load_explicit (status, memory_order_acquire); 128 | 129 | StrategyResult validation_result 130 | = validate_state_transition (current_status, new_status); 131 | if (validation_result != STRATEGY_SUCCESS) 132 | return validation_result; 133 | 134 | StrategyResult operation_result 135 | = perform_atomic_operation (status, current_status, new_status); 136 | if (operation_result == STRATEGY_SUCCESS) 137 | success = true; 138 | } 139 | 140 | return success ? STRATEGY_SUCCESS : STRATEGY_ATOMIC_FAILURE; 141 | } 142 | 143 | /* Helper function prototypes */ 144 | static StrategyResult 145 | validate_transition_input (const StatusTracker *tracker, 146 | StrategyStatus new_status); 147 | static StrategyResult 148 | handle_state_transition (StatusTracker *tracker, StrategyStatus new_status); 149 | static StrategyResult 150 | update_transition_counters (StatusTracker *tracker, StrategyStatus new_status); 151 | 152 | /* Input validation for transition */ 153 | static StrategyResult 154 | validate_transition_input (const StatusTracker *tracker, 155 | StrategyStatus new_status) 156 | { 157 | if (tracker == NULL) 158 | return STRATEGY_NULL_POINTER; 159 | if (new_status > STRATEGY_MAX_STATE) 160 | return STRATEGY_INVALID_STATE; 161 | return STRATEGY_SUCCESS; 162 | } 163 | 164 | /* Handle the actual state transition */ 165 | static StrategyResult 166 | handle_state_transition (StatusTracker *tracker, StrategyStatus new_status) 167 | { 168 | atomic_thread_fence (memory_order_seq_cst); 169 | StrategyResult result 170 | = atomic_transition_status (&tracker->current_status, new_status); 171 | if (result != STRATEGY_SUCCESS) 172 | return result; 173 | return STRATEGY_SUCCESS; 174 | } 175 | 176 | /* Update transition and error counters */ 177 | static StrategyResult 178 | update_transition_counters (StatusTracker *tracker, StrategyStatus new_status) 179 | { 180 | StrategyResult result 181 | = atomic_increment_with_check (&tracker->transition_count); 182 | if (result != STRATEGY_SUCCESS) 183 | return result; 184 | 185 | if (new_status == STRATEGY_STATE_ERROR) 186 | { 187 | result = atomic_increment_with_check (&tracker->error_count); 188 | if (result != STRATEGY_SUCCESS) 189 | return result; 190 | } 191 | return STRATEGY_SUCCESS; 192 | } 193 | 194 | /* Main transition status function */ 195 | StrategyResult 196 | transition_status (StatusTracker *const tracker, 197 | const StrategyStatus new_status) 198 | { 199 | StrategyResult result = validate_transition_input (tracker, new_status); 200 | if (result != STRATEGY_SUCCESS) 201 | return result; 202 | 203 | result = handle_state_transition (tracker, new_status); 204 | if (result != STRATEGY_SUCCESS) 205 | return result; 206 | 207 | result = update_transition_counters (tracker, new_status); 208 | if (result != STRATEGY_SUCCESS) 209 | return result; 210 | 211 | atomic_thread_fence (memory_order_seq_cst); 212 | return STRATEGY_SUCCESS; 213 | } 214 | 215 | StrategyResult 216 | initialize_status (StatusTracker *const tracker) 217 | { 218 | if (tracker == NULL) 219 | return STRATEGY_NULL_POINTER; 220 | 221 | atomic_thread_fence (memory_order_seq_cst); 222 | 223 | atomic_init (&tracker->current_status, STRATEGY_STATE_INITIALIZED); 224 | atomic_store_explicit (&tracker->transition_count, 0, memory_order_seq_cst); 225 | atomic_store_explicit (&tracker->error_count, 0, memory_order_seq_cst); 226 | 227 | atomic_thread_fence (memory_order_seq_cst); 228 | 229 | return STRATEGY_SUCCESS; 230 | } 231 | 232 | StrategyResult 233 | get_current_status (const StatusTracker *const tracker, 234 | StrategyStatus *const status) 235 | { 236 | if (tracker == NULL || status == NULL) 237 | return STRATEGY_NULL_POINTER; 238 | 239 | atomic_thread_fence (memory_order_seq_cst); 240 | *status 241 | = atomic_load_explicit (&tracker->current_status, memory_order_acquire); 242 | return STRATEGY_SUCCESS; 243 | } 244 | 245 | StrategyResult 246 | get_transition_count (const StatusTracker *const tracker, uint64_t *const count) 247 | { 248 | if (tracker == NULL || count == NULL) 249 | return STRATEGY_NULL_POINTER; 250 | 251 | atomic_thread_fence (memory_order_acquire); 252 | *count 253 | = atomic_load_explicit (&tracker->transition_count, memory_order_acquire); 254 | return STRATEGY_SUCCESS; 255 | } 256 | 257 | StrategyResult 258 | get_error_count (const StatusTracker *const tracker, uint64_t *const count) 259 | { 260 | if (tracker == NULL || count == NULL) 261 | { 262 | return STRATEGY_NULL_POINTER; 263 | } 264 | 265 | atomic_thread_fence (memory_order_acquire); 266 | *count = atomic_load_explicit (&tracker->error_count, memory_order_acquire); 267 | return STRATEGY_SUCCESS; 268 | } 269 | 270 | bool 271 | is_valid_state_transition (const StrategyStatus current, 272 | const StrategyStatus next) 273 | { 274 | return validate_state_transition (current, next) == STRATEGY_SUCCESS; 275 | } 276 | 277 | bool 278 | is_error_state (const StrategyStatus status) 279 | { 280 | return status <= STRATEGY_MAX_STATE && status == STRATEGY_STATE_ERROR; 281 | } 282 | 283 | bool 284 | requires_state_recovery (const StrategyStatus status) 285 | { 286 | if (status > STRATEGY_MAX_STATE) 287 | return false; 288 | return status == STRATEGY_STATE_ERROR 289 | || status == STRATEGY_STATE_TRANSITIONING; 290 | } 291 | 292 | const char * 293 | get_state_string (const StrategyStatus status) 294 | { 295 | return (status <= STRATEGY_MAX_STATE) 296 | ? STATUS_STRINGS[status] 297 | : STATUS_STRINGS[STRATEGY_MAX_STATE + 1]; 298 | } 299 | -------------------------------------------------------------------------------- /src/memory_interface/src/default_strategy.c: -------------------------------------------------------------------------------- 1 | #include "default_strategy.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static bool 10 | validate_pointer (const void *ptr) 11 | { 12 | return ptr != NULL; 13 | } 14 | 15 | static bool 16 | validate_size (size_t size) 17 | { 18 | return size > 0 && size <= (SIZE_MAX / 4); 19 | } 20 | 21 | static bool 22 | validate_strategy_base (MemoryStrategy *base) 23 | { 24 | return validate_pointer (base) && validate_pointer (base->strategy_data); 25 | } 26 | 27 | static void 28 | update_peak_usage (DefaultStrategy *strategy, size_t current_usage) 29 | { 30 | if (!validate_pointer (strategy)) 31 | { 32 | return; 33 | } 34 | 35 | atomic_thread_fence (memory_order_seq_cst); 36 | size_t old_peak 37 | = atomic_load_explicit (&strategy->peak_usage, memory_order_acquire); 38 | 39 | if (current_usage > old_peak) 40 | { 41 | atomic_compare_exchange_strong_explicit (&strategy->peak_usage, &old_peak, 42 | current_usage, 43 | memory_order_release, 44 | memory_order_acquire); 45 | } 46 | } 47 | 48 | static bool 49 | is_valid_allocation_size (size_t current_total, size_t new_size) 50 | { 51 | if (!validate_size (new_size)) 52 | { 53 | return false; 54 | } 55 | if (current_total > SIZE_MAX - new_size) 56 | { 57 | return false; 58 | } 59 | if (current_total + new_size > (SIZE_MAX / 4)) 60 | { 61 | return false; 62 | } 63 | return true; 64 | } 65 | 66 | static bool 67 | initialize_strategy_state (DefaultStrategy *strategy) 68 | { 69 | atomic_init (&strategy->total_allocated, 0); 70 | atomic_init (&strategy->total_freed, 0); 71 | atomic_init (&strategy->peak_usage, 0); 72 | atomic_init (&strategy->usage_count, 0); 73 | atomic_init (&strategy->operation_count, 0); 74 | 75 | atomic_thread_fence (memory_order_seq_cst); 76 | 77 | return transition_status (&strategy->status_tracker, STRATEGY_STATE_ACTIVE) 78 | == STRATEGY_SUCCESS; 79 | } 80 | 81 | static void 82 | initialize_strategy_functions (DefaultStrategy *strategy) 83 | { 84 | strategy->base.allocate = default_allocate; 85 | strategy->base.deallocate = default_deallocate; 86 | strategy->base.get_status = default_get_status; 87 | strategy->base.validate = default_validate; 88 | strategy->base.strategy_data = strategy; 89 | } 90 | 91 | static bool 92 | initialize_memory_stats (DefaultStrategy *strategy) 93 | { 94 | strategy->stats = (memory_stats_t *) calloc (1, sizeof (memory_stats_t)); 95 | if (!validate_pointer (strategy->stats)) 96 | { 97 | return false; 98 | } 99 | memory_stats_init (strategy->stats); 100 | return true; 101 | } 102 | 103 | static void 104 | cleanup_memory_stats (DefaultStrategy *strategy) 105 | { 106 | if (validate_pointer (strategy->stats)) 107 | { 108 | memory_stats_reset (strategy->stats); 109 | free (strategy->stats); 110 | strategy->stats = NULL; 111 | } 112 | } 113 | 114 | static void 115 | update_allocation_stats (DefaultStrategy *strategy, void *ptr, size_t size) 116 | { 117 | memory_stats_update_allocation (strategy->stats, ptr, size, __FILE__, 118 | __LINE__); 119 | atomic_thread_fence (memory_order_seq_cst); 120 | atomic_fetch_add_explicit (&strategy->total_allocated, size, 121 | memory_order_release); 122 | } 123 | 124 | static void * 125 | perform_allocation (DefaultStrategy *strategy, size_t size) 126 | { 127 | // Initialize ptr to NULL before any operations 128 | void *ptr = malloc (size); 129 | 130 | // Handle allocation failure 131 | if (ptr == NULL) 132 | { 133 | if (errno == ENOMEM) 134 | { 135 | transition_status (&strategy->status_tracker, STRATEGY_STATE_ERROR); 136 | } 137 | return NULL; 138 | } 139 | 140 | // Update stats only if allocation succeeded 141 | update_allocation_stats (strategy, ptr, size); 142 | return ptr; 143 | } 144 | 145 | static bool 146 | check_strategy_status (DefaultStrategy *strategy) 147 | { 148 | StrategyStatus status; 149 | if (get_current_status (&strategy->status_tracker, &status) 150 | != STRATEGY_SUCCESS 151 | || status != STRATEGY_STATE_ACTIVE) 152 | { 153 | return false; 154 | } 155 | return true; 156 | } 157 | 158 | static void 159 | handle_deallocation (DefaultStrategy *strategy, void *ptr) 160 | { 161 | size_t dealloc_size = 0; 162 | if (memory_stats_get_allocation_size (strategy->stats, ptr, &dealloc_size) 163 | == MEMORY_STATS_SUCCESS) 164 | { 165 | atomic_fetch_add_explicit (&strategy->total_freed, dealloc_size, 166 | memory_order_release); 167 | } 168 | 169 | memory_stats_update_deallocation (strategy->stats, ptr); 170 | atomic_thread_fence (memory_order_seq_cst); 171 | 172 | free (ptr); 173 | } 174 | 175 | static void 176 | check_and_report_leaks (DefaultStrategy *strategy) 177 | { 178 | size_t total_alloc 179 | = atomic_load_explicit (&strategy->total_allocated, memory_order_acquire); 180 | size_t total_freed 181 | = atomic_load_explicit (&strategy->total_freed, memory_order_acquire); 182 | 183 | if (total_alloc > total_freed) 184 | { 185 | char *leak_report = memory_stats_check_leaks (strategy->stats); 186 | if (validate_pointer (leak_report)) 187 | { 188 | fprintf (stderr, "Memory leaks detected during cleanup:\n%s\n", 189 | leak_report); 190 | free (leak_report); 191 | } 192 | } 193 | } 194 | 195 | DefaultStrategy * 196 | create_default_strategy (void) 197 | { 198 | DefaultStrategy *strategy 199 | = (DefaultStrategy *) calloc (1, sizeof (DefaultStrategy)); 200 | if (!validate_pointer (strategy)) 201 | { 202 | return NULL; 203 | } 204 | 205 | if (!initialize_memory_stats (strategy)) 206 | { 207 | free (strategy); 208 | return NULL; 209 | } 210 | 211 | initialize_strategy_functions (strategy); 212 | 213 | if (initialize_status (&strategy->status_tracker) != STRATEGY_SUCCESS) 214 | { 215 | cleanup_memory_stats (strategy); 216 | free (strategy); 217 | return NULL; 218 | } 219 | 220 | if (!initialize_strategy_state (strategy)) 221 | { 222 | cleanup_memory_stats (strategy); 223 | free (strategy); 224 | return NULL; 225 | } 226 | 227 | return strategy; 228 | } 229 | 230 | void * 231 | default_allocate (MemoryStrategy *base, size_t size) 232 | { 233 | if (!validate_strategy_base (base)) 234 | { 235 | return NULL; 236 | } 237 | 238 | DefaultStrategy *strategy = (DefaultStrategy *) base->strategy_data; 239 | atomic_fetch_add_explicit (&strategy->usage_count, 1, memory_order_acquire); 240 | atomic_thread_fence (memory_order_seq_cst); 241 | 242 | if (!check_strategy_status (strategy)) 243 | { 244 | atomic_fetch_sub_explicit (&strategy->usage_count, 1, memory_order_release); 245 | return NULL; 246 | } 247 | 248 | size_t current_total 249 | = atomic_load_explicit (&strategy->total_allocated, memory_order_acquire) 250 | - atomic_load_explicit (&strategy->total_freed, memory_order_acquire); 251 | 252 | if (!is_valid_allocation_size (current_total, size)) 253 | { 254 | atomic_fetch_sub_explicit (&strategy->usage_count, 1, memory_order_release); 255 | return NULL; 256 | } 257 | 258 | void *ptr = perform_allocation (strategy, size); 259 | if (ptr != NULL) 260 | { 261 | update_peak_usage (strategy, current_total + size); 262 | } 263 | 264 | atomic_thread_fence (memory_order_seq_cst); 265 | atomic_fetch_sub_explicit (&strategy->usage_count, 1, memory_order_release); 266 | 267 | return ptr; 268 | } 269 | 270 | void 271 | default_deallocate (MemoryStrategy *base, void *ptr) 272 | { 273 | if (!validate_strategy_base (base) || !validate_pointer (ptr)) 274 | { 275 | return; 276 | } 277 | 278 | DefaultStrategy *strategy = (DefaultStrategy *) base->strategy_data; 279 | atomic_fetch_add_explicit (&strategy->usage_count, 1, memory_order_acquire); 280 | atomic_thread_fence (memory_order_seq_cst); 281 | 282 | StrategyStatus status; 283 | if (get_current_status (&strategy->status_tracker, &status) 284 | != STRATEGY_SUCCESS 285 | || status == STRATEGY_STATE_ERROR) 286 | { 287 | atomic_fetch_sub_explicit (&strategy->usage_count, 1, memory_order_release); 288 | return; 289 | } 290 | 291 | handle_deallocation (strategy, ptr); 292 | 293 | atomic_thread_fence (memory_order_seq_cst); 294 | atomic_fetch_sub_explicit (&strategy->usage_count, 1, memory_order_release); 295 | } 296 | 297 | void 298 | destroy_default_strategy (DefaultStrategy *strategy) 299 | { 300 | if (!validate_pointer (strategy)) 301 | { 302 | return; 303 | } 304 | 305 | transition_status (&strategy->status_tracker, STRATEGY_STATE_ERROR); 306 | atomic_thread_fence (memory_order_seq_cst); 307 | 308 | while (atomic_load_explicit (&strategy->usage_count, memory_order_acquire) 309 | > 0) 310 | { 311 | usleep (1000); 312 | } 313 | 314 | check_and_report_leaks (strategy); 315 | cleanup_memory_stats (strategy); 316 | 317 | explicit_bzero (strategy, sizeof (DefaultStrategy)); 318 | free (strategy); 319 | } 320 | 321 | StrategyStatus 322 | default_get_status (MemoryStrategy *base) 323 | { 324 | if (!validate_strategy_base (base)) 325 | { 326 | return STRATEGY_STATE_ERROR; 327 | } 328 | 329 | DefaultStrategy *strategy = (DefaultStrategy *) base->strategy_data; 330 | StrategyStatus status; 331 | if (get_current_status (&strategy->status_tracker, &status) 332 | != STRATEGY_SUCCESS) 333 | { 334 | return STRATEGY_STATE_ERROR; 335 | } 336 | return status; 337 | } 338 | 339 | bool 340 | default_validate (MemoryStrategy *base) 341 | { 342 | if (!validate_strategy_base (base)) 343 | { 344 | return false; 345 | } 346 | 347 | DefaultStrategy *strategy = (DefaultStrategy *) base->strategy_data; 348 | atomic_thread_fence (memory_order_acquire); 349 | 350 | StrategyStatus status; 351 | if (get_current_status (&strategy->status_tracker, &status) 352 | != STRATEGY_SUCCESS) 353 | { 354 | return false; 355 | } 356 | 357 | if (status != STRATEGY_STATE_ACTIVE && status != STRATEGY_STATE_INITIALIZED) 358 | { 359 | return false; 360 | } 361 | 362 | if (!validate_pointer (strategy->stats)) 363 | { 364 | return false; 365 | } 366 | 367 | return strategy->base.allocate != NULL && strategy->base.deallocate != NULL 368 | && strategy->base.get_status != NULL 369 | && strategy->base.validate != NULL; 370 | } 371 | 372 | const char * 373 | get_strategy_name (void) 374 | { 375 | return "DefaultStrategy"; 376 | } 377 | 378 | size_t 379 | get_current_usage (const DefaultStrategy *strategy) 380 | { 381 | if (!validate_pointer (strategy)) 382 | { 383 | return 0; 384 | } 385 | 386 | atomic_thread_fence (memory_order_seq_cst); 387 | size_t allocated 388 | = atomic_load_explicit (&strategy->total_allocated, memory_order_acquire); 389 | size_t freed 390 | = atomic_load_explicit (&strategy->total_freed, memory_order_acquire); 391 | atomic_thread_fence (memory_order_seq_cst); 392 | 393 | return allocated > freed ? allocated - freed : 0; 394 | } 395 | 396 | size_t 397 | get_peak_usage (const DefaultStrategy *strategy) 398 | { 399 | if (!validate_pointer (strategy)) 400 | { 401 | return 0; 402 | } 403 | return atomic_load_explicit (&strategy->peak_usage, memory_order_acquire); 404 | } 405 | 406 | size_t 407 | get_total_allocated (const DefaultStrategy *strategy) 408 | { 409 | if (!validate_pointer (strategy)) 410 | { 411 | return 0; 412 | } 413 | return atomic_load_explicit (&strategy->total_allocated, 414 | memory_order_acquire); 415 | } 416 | 417 | size_t 418 | get_total_freed (const DefaultStrategy *strategy) 419 | { 420 | if (!validate_pointer (strategy)) 421 | { 422 | return 0; 423 | } 424 | return atomic_load_explicit (&strategy->total_freed, memory_order_acquire); 425 | } 426 | -------------------------------------------------------------------------------- /src/memory_interface/memstats/tests/test_edge_cases.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../include/memory_stats.h" 10 | 11 | #define HIGH_THREAD_COUNT 100 12 | #define RAPID_ITERATIONS 1000 13 | #define OVERFLOW_SIZE (SIZE_MAX / 2) 14 | #define STRESS_THREADS 8 15 | #define STRESS_ITERATIONS 10000 16 | 17 | static void * 18 | stress_alloc_dealloc_thread (void *arg) 19 | { 20 | memory_stats_t *stats = (memory_stats_t *) arg; 21 | void *ptrs[10]; 22 | 23 | for (int i = 0; i < STRESS_ITERATIONS; i++) 24 | { 25 | for (int j = 0; j < 10; j++) 26 | { 27 | size_t size = (rand () % 1024) + 1; 28 | ptrs[j] = malloc (size); 29 | if (ptrs[j] == NULL) 30 | continue; 31 | memory_stats_update_allocation (stats, ptrs[j], size, __FILE__, __LINE__); 32 | } 33 | 34 | usleep (rand () % 100); 35 | 36 | for (int j = 9; j >= 0; j--) 37 | { 38 | if (ptrs[j] != NULL) 39 | { 40 | memory_stats_update_deallocation (stats, ptrs[j]); 41 | free (ptrs[j]); 42 | ptrs[j] = NULL; 43 | } 44 | } 45 | 46 | sched_yield (); 47 | } 48 | return NULL; 49 | } 50 | 51 | void 52 | test_stress_concurrent_access () 53 | { 54 | printf ("Testing stress concurrent access...\n"); 55 | memory_stats_t stats; 56 | stats_report_t initial_report, final_report; 57 | pthread_t threads[STRESS_THREADS]; 58 | 59 | memory_stats_init (&stats); 60 | memory_stats_get_report (&stats, &initial_report); 61 | assert (initial_report.alloc_count == 0); 62 | assert (initial_report.free_count == 0); 63 | 64 | for (int i = 0; i < STRESS_THREADS; i++) 65 | { 66 | int rc 67 | = pthread_create (&threads[i], NULL, stress_alloc_dealloc_thread, &stats); 68 | (void) rc; 69 | assert (rc == 0); 70 | } 71 | 72 | for (int i = 0; i < STRESS_THREADS; i++) 73 | { 74 | pthread_join (threads[i], NULL); 75 | } 76 | 77 | usleep (1000); 78 | 79 | memory_stats_get_report (&stats, &final_report); 80 | uint64_t expected_count = STRESS_THREADS * STRESS_ITERATIONS * 10; 81 | 82 | printf ("Expected count: %lu\n", expected_count); 83 | printf ("Actual alloc count: %lu\n", final_report.alloc_count); 84 | printf ("Actual free count: %lu\n", final_report.free_count); 85 | 86 | assert (final_report.alloc_count <= expected_count); 87 | assert (final_report.free_count == final_report.alloc_count); 88 | assert (final_report.current_bytes == 0); 89 | assert (final_report.total_leaked_bytes == 0); 90 | 91 | printf ("Stress concurrent access tests passed\n"); 92 | } 93 | 94 | void 95 | test_fragmentation_patterns () 96 | { 97 | printf ("Testing fragmentation patterns...\n"); 98 | memory_stats_t stats; 99 | memory_stats_init (&stats); 100 | 101 | #define FRAG_ALLOCS 100 102 | void *ptrs[FRAG_ALLOCS]; 103 | size_t sizes[FRAG_ALLOCS]; 104 | 105 | for (int i = 0; i < FRAG_ALLOCS; i++) 106 | { 107 | sizes[i] = (1 << (i % 12)) + 1; 108 | ptrs[i] = malloc (sizes[i]); 109 | memory_stats_update_allocation (&stats, ptrs[i], sizes[i], __FILE__, 110 | __LINE__); 111 | } 112 | 113 | for (int i = 0; i < FRAG_ALLOCS; i += 2) 114 | { 115 | memory_stats_update_deallocation (&stats, ptrs[i]); 116 | free (ptrs[i]); 117 | } 118 | 119 | for (int i = 0; i < FRAG_ALLOCS; i += 2) 120 | { 121 | size_t new_size = sizes[i] / 2; 122 | ptrs[i] = malloc (new_size); 123 | memory_stats_update_allocation (&stats, ptrs[i], new_size, __FILE__, 124 | __LINE__); 125 | } 126 | 127 | char *pattern_report = memory_stats_analyze_patterns (&stats); 128 | assert (pattern_report != NULL); 129 | assert (strstr (pattern_report, "Distribution") != NULL); 130 | free (pattern_report); 131 | 132 | for (int i = 0; i < FRAG_ALLOCS; i++) 133 | { 134 | memory_stats_update_deallocation (&stats, ptrs[i]); 135 | free (ptrs[i]); 136 | } 137 | 138 | printf ("Fragmentation pattern tests passed\n"); 139 | } 140 | 141 | void 142 | test_atomic_corners () 143 | { 144 | printf ("Testing atomic operation corner cases...\n"); 145 | memory_stats_t stats; 146 | memory_stats_init (&stats); 147 | 148 | void *ptr = malloc (1); 149 | for (int i = 0; i < 1000000; i++) 150 | { 151 | memory_stats_update_allocation (&stats, ptr, 1, __FILE__, __LINE__); 152 | memory_stats_update_deallocation (&stats, ptr); 153 | } 154 | free (ptr); 155 | 156 | #define PEAK_THREADS 4 157 | #define PEAK_ITERATIONS 1000 158 | 159 | pthread_t peak_threads[PEAK_THREADS]; 160 | for (int i = 0; i < PEAK_THREADS; i++) 161 | { 162 | pthread_create (&peak_threads[i], NULL, stress_alloc_dealloc_thread, 163 | &stats); 164 | } 165 | 166 | for (int i = 0; i < PEAK_THREADS; i++) 167 | { 168 | pthread_join (peak_threads[i], NULL); 169 | } 170 | 171 | stats_report_t report; 172 | memory_stats_get_report (&stats, &report); 173 | assert (report.peak_bytes > 0); 174 | assert (report.current_bytes == 0); 175 | 176 | printf ("Atomic corner case tests passed\n"); 177 | } 178 | 179 | void 180 | test_null_cases () 181 | { 182 | printf ("Testing NULL pointer handling...\n"); 183 | 184 | memory_stats_init (NULL); 185 | memory_stats_update_allocation (NULL, NULL, 0, NULL, 0); 186 | memory_stats_update_deallocation (NULL, NULL); 187 | memory_stats_get_report (NULL, NULL); 188 | memory_stats_analyze_patterns (NULL); 189 | memory_stats_check_leaks (NULL); 190 | 191 | memory_stats_t valid_stats; 192 | memory_stats_init (&valid_stats); 193 | memory_stats_update_allocation (&valid_stats, NULL, 0, NULL, 0); 194 | memory_stats_update_deallocation (&valid_stats, NULL); 195 | 196 | printf ("NULL pointer tests passed\n"); 197 | } 198 | 199 | void 200 | test_size_boundaries () 201 | { 202 | printf ("Testing size boundary conditions...\n"); 203 | memory_stats_t stats; 204 | stats_report_t report; 205 | memory_stats_init (&stats); 206 | 207 | void *ptr0 = malloc (0); 208 | memory_stats_update_allocation (&stats, ptr0, 0, __FILE__, __LINE__); 209 | memory_stats_get_report (&stats, &report); 210 | assert (report.alloc_count == 1); 211 | free (ptr0); 212 | 213 | void *ptr1 = malloc (STATS_SIZE_BUCKET_COUNT * 1024); 214 | memory_stats_update_allocation (&stats, ptr1, STATS_SIZE_BUCKET_COUNT * 1024, 215 | __FILE__, __LINE__); 216 | memory_stats_get_report (&stats, &report); 217 | assert (report.size_distribution[STATS_SIZE_BUCKET_COUNT - 1].count > 0); 218 | free (ptr1); 219 | 220 | size_t large_size = 1024 * 1024 * 10; 221 | void *ptr2 = malloc (large_size); 222 | if (ptr2) 223 | { 224 | memory_stats_update_allocation (&stats, ptr2, large_size, __FILE__, 225 | __LINE__); 226 | memory_stats_get_report (&stats, &report); 227 | assert (report.current_bytes >= large_size); 228 | free (ptr2); 229 | } 230 | 231 | printf ("Size boundary tests passed\n"); 232 | } 233 | 234 | void * 235 | stress_thread_routine (void *arg) 236 | { 237 | memory_stats_t *stats = (memory_stats_t *) arg; 238 | size_t sizes[] = {16, 32, 64, 128, 256, 512, 1024}; 239 | 240 | for (int i = 0; i < RAPID_ITERATIONS; i++) 241 | { 242 | size_t size = sizes[i % (sizeof (sizes) / sizeof (sizes[0]))]; 243 | void *ptr = malloc (size); 244 | memory_stats_update_allocation (stats, ptr, size, __FILE__, __LINE__); 245 | 246 | if (rand () % 2) 247 | { 248 | memory_stats_update_deallocation (stats, ptr); 249 | free (ptr); 250 | } 251 | } 252 | return NULL; 253 | } 254 | 255 | void 256 | test_high_concurrency () 257 | { 258 | printf ("Testing high concurrency conditions...\n"); 259 | memory_stats_t stats; 260 | stats_report_t report; 261 | memory_stats_init (&stats); 262 | 263 | pthread_t threads[HIGH_THREAD_COUNT]; 264 | 265 | for (int i = 0; i < HIGH_THREAD_COUNT; i++) 266 | { 267 | pthread_create (&threads[i], NULL, stress_thread_routine, &stats); 268 | } 269 | 270 | for (int i = 0; i < HIGH_THREAD_COUNT; i++) 271 | { 272 | pthread_join (threads[i], NULL); 273 | } 274 | 275 | memory_stats_get_report (&stats, &report); 276 | assert (report.alloc_count == HIGH_THREAD_COUNT * RAPID_ITERATIONS); 277 | 278 | printf ("High concurrency tests passed\n"); 279 | } 280 | 281 | void 282 | test_overflow_handling () 283 | { 284 | printf ("\nStarting reduced overflow handling test...\n"); 285 | memory_stats_t stats; 286 | stats_report_t report; 287 | memory_stats_init (&stats); 288 | 289 | #define DEBUG_TEST_SIZE 5 290 | void *ptrs[DEBUG_TEST_SIZE]; 291 | memset (ptrs, 0, sizeof (ptrs)); 292 | 293 | printf ("\n=== Starting Allocation Phase ===\n"); 294 | for (int i = 0; i < DEBUG_TEST_SIZE; i++) 295 | { 296 | printf ("\nIteration %d:\n", i); 297 | ptrs[i] = malloc (1); 298 | if (!ptrs[i]) 299 | { 300 | printf (" Allocation failed at index %d\n", i); 301 | continue; 302 | } 303 | 304 | printf (" Before allocation update - Getting report...\n"); 305 | memory_stats_get_report (&stats, &report); 306 | printf (" Current alloc_count before update: %lu\n", report.alloc_count); 307 | 308 | memory_stats_update_allocation (&stats, ptrs[i], 1, __FILE__, __LINE__); 309 | 310 | printf (" After allocation update - Getting report...\n"); 311 | memory_stats_get_report (&stats, &report); 312 | printf (" Current alloc_count after update: %lu\n", report.alloc_count); 313 | 314 | if (report.alloc_count != (uint64_t) (i + 1)) 315 | { 316 | printf (" ERROR: Allocation count mismatch. Expected: %d, Got: %lu\n", 317 | i + 1, report.alloc_count); 318 | } 319 | assert (report.alloc_count == (uint64_t) (i + 1)); 320 | 321 | usleep (100); 322 | } 323 | 324 | printf ("\n=== Starting Deallocation Phase ===\n"); 325 | for (int i = 0; i < DEBUG_TEST_SIZE; i++) 326 | { 327 | printf ("\nDeallocation iteration %d:\n", i); 328 | if (!ptrs[i]) 329 | { 330 | printf (" Skipping NULL pointer at index %d\n", i); 331 | continue; 332 | } 333 | 334 | printf (" Before deallocation - Getting report...\n"); 335 | memory_stats_get_report (&stats, &report); 336 | printf (" Current free_count before update: %lu\n", report.free_count); 337 | 338 | memory_stats_update_deallocation (&stats, ptrs[i]); 339 | free (ptrs[i]); 340 | 341 | printf (" After deallocation - Getting report...\n"); 342 | memory_stats_get_report (&stats, &report); 343 | printf (" Current free_count after update: %lu\n", report.free_count); 344 | 345 | if (report.free_count != (uint64_t) (i + 1)) 346 | { 347 | printf (" ERROR: Free count mismatch. Expected: %d, Got: %lu\n", i + 1, 348 | report.free_count); 349 | } 350 | assert (report.free_count == (uint64_t) (i + 1)); 351 | assert (report.alloc_count == DEBUG_TEST_SIZE); 352 | 353 | usleep (100); 354 | } 355 | 356 | printf ("\n=== Final Verification ===\n"); 357 | memory_stats_get_report (&stats, &report); 358 | printf ("Final counts - Alloc: %lu, Free: %lu\n", report.alloc_count, 359 | report.free_count); 360 | 361 | assert (report.alloc_count == DEBUG_TEST_SIZE); 362 | assert (report.free_count == DEBUG_TEST_SIZE); 363 | assert (report.current_bytes == 0); 364 | 365 | printf ("Reduced overflow handling test completed.\n"); 366 | } 367 | 368 | void 369 | test_leak_detection_edges () 370 | { 371 | printf ("Testing leak detection edge cases...\n"); 372 | memory_stats_t stats; 373 | stats_report_t report; 374 | memory_stats_init (&stats); 375 | 376 | void *ptrs[STATS_MAX_TRACKED_ALLOCATIONS + 10]; 377 | 378 | for (int i = 0; i < STATS_MAX_TRACKED_ALLOCATIONS + 10; i++) 379 | { 380 | ptrs[i] = malloc (16); 381 | memory_stats_update_allocation (&stats, ptrs[i], 16, __FILE__, __LINE__); 382 | } 383 | 384 | memory_stats_get_report (&stats, &report); 385 | assert (report.active_allocation_count <= STATS_MAX_TRACKED_ALLOCATIONS); 386 | 387 | for (int i = 0; i < STATS_MAX_TRACKED_ALLOCATIONS + 10; i++) 388 | { 389 | memory_stats_update_deallocation (&stats, ptrs[i]); 390 | free (ptrs[i]); 391 | } 392 | 393 | printf ("Leak detection edge case tests passed\n"); 394 | } 395 | 396 | int 397 | main () 398 | { 399 | printf ("\n=== Starting Focused Overflow Test ===\n"); 400 | test_overflow_handling (); 401 | printf ("=== Focused Test Complete ===\n"); 402 | return 0; 403 | } 404 | -------------------------------------------------------------------------------- /src/memory_interface/memstrategy/src/memory_pool_strategy.c: -------------------------------------------------------------------------------- 1 | #include "memory_pool_strategy.h" 2 | #include "strategy_validator.h" 3 | #include 4 | #include 5 | #include 6 | 7 | static void * 8 | pool_allocate (struct MemoryStrategy *self, size_t size); 9 | static void 10 | pool_deallocate (struct MemoryStrategy *self, void *ptr); 11 | static StrategyStatus 12 | pool_get_status (struct MemoryStrategy *self); 13 | static bool 14 | pool_validate (struct MemoryStrategy *self); 15 | 16 | static bool 17 | is_block_used (const uint64_t *bitmap, size_t block); 18 | static size_t 19 | blocks_needed (size_t size); 20 | static bool 21 | is_ptr_in_pool_range (const void *ptr, const void *pool_start, 22 | size_t pool_size); 23 | static void 24 | secure_clear_memory (volatile void *memory, size_t size); 25 | static bool 26 | find_contiguous_blocks (const uint64_t *bitmap, size_t bitmap_size, 27 | size_t blocks_needed, size_t *start_block); 28 | static void 29 | mark_blocks (uint64_t *bitmap, size_t start_block, size_t num_blocks, 30 | bool used); 31 | 32 | static void * 33 | pool_allocate (struct MemoryStrategy *self, size_t size) 34 | { 35 | if (!validate_allocation (self, size)) 36 | { 37 | return NULL; 38 | } 39 | 40 | MemoryPool *pool = (MemoryPool *) self->strategy_data; 41 | if (!pool || !pool->pool_memory || !pool->block_bitmap) 42 | { 43 | transition_status (self->status_tracker, STRATEGY_STATE_ERROR); 44 | return NULL; 45 | } 46 | 47 | uint32_t current_ops 48 | = atomic_fetch_add_explicit (&pool->metrics.concurrent_ops, 1, 49 | memory_order_acquire); 50 | if (current_ops >= MAX_ALLOCATION_RETRIES) 51 | { 52 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 53 | memory_order_release); 54 | atomic_fetch_add_explicit (&pool->metrics.failed_allocations, 1, 55 | memory_order_relaxed); 56 | return NULL; 57 | } 58 | 59 | const size_t needed = blocks_needed (size); 60 | if (needed == 0) 61 | { 62 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 63 | memory_order_release); 64 | atomic_fetch_add_explicit (&pool->metrics.failed_allocations, 1, 65 | memory_order_relaxed); 66 | return NULL; 67 | } 68 | 69 | uint64_t *bitmap = (uint64_t *) atomic_load_explicit (&pool->block_bitmap, 70 | memory_order_acquire); 71 | size_t bitmap_size 72 | = atomic_load_explicit (&pool->bitmap_size, memory_order_acquire); 73 | 74 | size_t start_block; 75 | if (!find_contiguous_blocks (bitmap, bitmap_size, needed, &start_block)) 76 | { 77 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 78 | memory_order_release); 79 | atomic_fetch_add_explicit (&pool->metrics.failed_allocations, 1, 80 | memory_order_relaxed); 81 | return NULL; 82 | } 83 | 84 | mark_blocks (bitmap, start_block, needed, true); 85 | 86 | uint32_t current_blocks 87 | = atomic_load_explicit (&pool->metrics.blocks_used, memory_order_relaxed); 88 | if (current_blocks > UINT32_MAX - needed) 89 | { 90 | mark_blocks (bitmap, start_block, needed, false); 91 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 92 | memory_order_release); 93 | atomic_fetch_add_explicit (&pool->metrics.failed_allocations, 1, 94 | memory_order_relaxed); 95 | return NULL; 96 | } 97 | 98 | atomic_fetch_add_explicit (&pool->metrics.blocks_used, needed, 99 | memory_order_relaxed); 100 | atomic_fetch_add_explicit (&pool->metrics.total_allocations, 1, 101 | memory_order_relaxed); 102 | 103 | void *pool_memory 104 | = (void *) atomic_load_explicit (&pool->pool_memory, memory_order_acquire); 105 | void *block_start = (char *) pool_memory + (start_block * POOL_BLOCK_SIZE); 106 | 107 | atomic_thread_fence (memory_order_release); 108 | *(size_t *) block_start = needed; 109 | atomic_thread_fence (memory_order_release); 110 | 111 | void *user_ptr = (char *) block_start + POOL_METADATA_SIZE; 112 | secure_clear_memory (user_ptr, 113 | (needed * POOL_BLOCK_SIZE) - POOL_METADATA_SIZE); 114 | 115 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 116 | memory_order_release); 117 | atomic_thread_fence (memory_order_seq_cst); 118 | 119 | return user_ptr; 120 | } 121 | 122 | static void 123 | pool_deallocate (struct MemoryStrategy *self, void *ptr) 124 | { 125 | if (!validate_deallocation (self, ptr)) 126 | { 127 | return; 128 | } 129 | 130 | MemoryPool *pool = (MemoryPool *) self->strategy_data; 131 | if (!pool || !pool->pool_memory || !pool->block_bitmap) 132 | { 133 | transition_status (self->status_tracker, STRATEGY_STATE_ERROR); 134 | return; 135 | } 136 | 137 | uint32_t current_ops 138 | = atomic_fetch_add_explicit (&pool->metrics.concurrent_ops, 1, 139 | memory_order_acquire); 140 | if (current_ops >= MAX_ALLOCATION_RETRIES) 141 | { 142 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 143 | memory_order_release); 144 | return; 145 | } 146 | 147 | void *block_start = (char *) ptr - POOL_METADATA_SIZE; 148 | const size_t pool_size = POOL_BLOCK_SIZE * POOL_BLOCK_COUNT; 149 | void *pool_memory 150 | = (void *) atomic_load_explicit (&pool->pool_memory, memory_order_acquire); 151 | 152 | if (!is_ptr_in_pool_range (block_start, pool_memory, pool_size)) 153 | { 154 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 155 | memory_order_release); 156 | return; 157 | } 158 | 159 | const size_t block_index 160 | = ((char *) block_start - (char *) pool_memory) / POOL_BLOCK_SIZE; 161 | uint64_t *bitmap = (uint64_t *) atomic_load_explicit (&pool->block_bitmap, 162 | memory_order_acquire); 163 | 164 | if (!is_block_used (bitmap, block_index)) 165 | { 166 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 167 | memory_order_release); 168 | return; 169 | } 170 | 171 | atomic_thread_fence (memory_order_acquire); 172 | const size_t num_blocks = *(size_t *) block_start; 173 | 174 | if (num_blocks == 0 || block_index + num_blocks > POOL_BLOCK_COUNT) 175 | { 176 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 177 | memory_order_release); 178 | return; 179 | } 180 | 181 | secure_clear_memory (block_start, num_blocks * POOL_BLOCK_SIZE); 182 | atomic_thread_fence (memory_order_release); 183 | 184 | mark_blocks (bitmap, block_index, num_blocks, false); 185 | 186 | uint32_t current_blocks 187 | = atomic_load_explicit (&pool->metrics.blocks_used, memory_order_relaxed); 188 | if (current_blocks >= num_blocks) 189 | { 190 | atomic_fetch_sub_explicit (&pool->metrics.blocks_used, num_blocks, 191 | memory_order_relaxed); 192 | } 193 | 194 | atomic_fetch_sub_explicit (&pool->metrics.concurrent_ops, 1, 195 | memory_order_release); 196 | atomic_thread_fence (memory_order_seq_cst); 197 | } 198 | 199 | static StrategyStatus 200 | pool_get_status (struct MemoryStrategy *self) 201 | { 202 | StrategyStatus current_status = STRATEGY_STATE_ERROR; 203 | if (validate_strategy (self) 204 | && get_current_status (self->status_tracker, ¤t_status) 205 | == STRATEGY_SUCCESS) 206 | { 207 | return current_status; 208 | } 209 | return STRATEGY_STATE_ERROR; 210 | } 211 | 212 | static bool 213 | pool_validate (struct MemoryStrategy *self) 214 | { 215 | return validate_strategy (self); 216 | } 217 | 218 | MemoryStrategy * 219 | create_pool_strategy (void) 220 | { 221 | MemoryStrategy *strategy = calloc (1, sizeof (MemoryStrategy)); 222 | if (!strategy) 223 | { 224 | return NULL; 225 | } 226 | 227 | if (!initialize_strategy (strategy)) 228 | { 229 | free (strategy); 230 | return NULL; 231 | } 232 | 233 | MemoryPool *pool = calloc (1, sizeof (MemoryPool)); 234 | if (!pool) 235 | { 236 | cleanup_strategy (strategy); 237 | free (strategy); 238 | return NULL; 239 | } 240 | 241 | void *pool_memory 242 | = aligned_alloc (sizeof (void *), POOL_BLOCK_SIZE * POOL_BLOCK_COUNT); 243 | size_t bitmap_size 244 | = (POOL_BLOCK_COUNT + BLOCKS_PER_BITMAP - 1) / BLOCKS_PER_BITMAP; 245 | uint64_t *block_bitmap = calloc (bitmap_size, sizeof (uint64_t)); 246 | 247 | if (!pool_memory || !block_bitmap) 248 | { 249 | free (pool_memory); 250 | free (block_bitmap); 251 | free (pool); 252 | cleanup_strategy (strategy); 253 | free (strategy); 254 | return NULL; 255 | } 256 | 257 | secure_clear_memory (pool_memory, POOL_BLOCK_SIZE * POOL_BLOCK_COUNT); 258 | memset (block_bitmap, 0, bitmap_size * sizeof (uint64_t)); 259 | 260 | atomic_store_explicit (&pool->pool_memory, (uintptr_t) pool_memory, 261 | memory_order_release); 262 | atomic_store_explicit (&pool->block_bitmap, (uintptr_t) block_bitmap, 263 | memory_order_release); 264 | atomic_store_explicit (&pool->bitmap_size, bitmap_size, memory_order_release); 265 | atomic_store_explicit (&pool->thread_count, 0, memory_order_release); 266 | atomic_store_explicit (&pool->initialization_flag, 0, memory_order_release); 267 | 268 | atomic_init (&pool->metrics.blocks_used, 0); 269 | atomic_init (&pool->metrics.total_allocations, 0); 270 | atomic_init (&pool->metrics.failed_allocations, 0); 271 | atomic_init (&pool->metrics.concurrent_ops, 0); 272 | 273 | strategy->allocate = pool_allocate; 274 | strategy->deallocate = pool_deallocate; 275 | strategy->get_status = pool_get_status; 276 | strategy->validate = pool_validate; 277 | strategy->strategy_data = pool; 278 | 279 | return strategy; 280 | } 281 | 282 | void 283 | destroy_pool_strategy (MemoryStrategy *strategy) 284 | { 285 | if (!strategy || !strategy->strategy_data) 286 | { 287 | return; 288 | } 289 | 290 | MemoryPool *pool = (MemoryPool *) strategy->strategy_data; 291 | 292 | void *pool_memory 293 | = (void *) atomic_load_explicit (&pool->pool_memory, memory_order_acquire); 294 | void *block_bitmap 295 | = (void *) atomic_load_explicit (&pool->block_bitmap, memory_order_acquire); 296 | size_t bitmap_size 297 | = atomic_load_explicit (&pool->bitmap_size, memory_order_acquire); 298 | 299 | secure_clear_memory (pool_memory, POOL_BLOCK_SIZE * POOL_BLOCK_COUNT); 300 | secure_clear_memory (block_bitmap, bitmap_size * sizeof (uint64_t)); 301 | secure_clear_memory (pool, sizeof (MemoryPool)); 302 | 303 | strategy->strategy_data = NULL; 304 | 305 | free (pool_memory); 306 | free (block_bitmap); 307 | free (pool); 308 | 309 | cleanup_strategy (strategy); 310 | free (strategy); 311 | } 312 | 313 | static bool 314 | is_block_used (const uint64_t *bitmap, const size_t block) 315 | { 316 | if (!bitmap || block >= POOL_BLOCK_COUNT) 317 | { 318 | return false; 319 | } 320 | 321 | const size_t word_idx = block / BLOCKS_PER_BITMAP; 322 | const size_t bit_idx = block % BLOCKS_PER_BITMAP; 323 | 324 | atomic_thread_fence (memory_order_acquire); 325 | return (bitmap[word_idx] & (1ULL << bit_idx)) != 0; 326 | } 327 | 328 | static size_t 329 | blocks_needed (const size_t size) 330 | { 331 | if (size > SIZE_MAX - POOL_METADATA_SIZE) 332 | { 333 | return 0; 334 | } 335 | 336 | const size_t total_size = size + POOL_METADATA_SIZE; 337 | if (total_size > (SIZE_MAX - (POOL_BLOCK_SIZE - 1))) 338 | { 339 | return 0; 340 | } 341 | 342 | size_t blocks = (total_size + POOL_BLOCK_SIZE - 1) / POOL_BLOCK_SIZE; 343 | if (blocks == 0 || blocks > POOL_BLOCK_COUNT) 344 | { 345 | return 0; 346 | } 347 | 348 | return blocks; 349 | } 350 | 351 | static bool 352 | is_ptr_in_pool_range (const void *ptr, const void *pool_start, 353 | const size_t pool_size) 354 | { 355 | const uintptr_t ptr_addr = (uintptr_t) ptr; 356 | const uintptr_t start_addr = (uintptr_t) pool_start; 357 | 358 | if (pool_size > SIZE_MAX - start_addr) 359 | { 360 | return false; 361 | } 362 | 363 | const uintptr_t end_addr = start_addr + pool_size; 364 | return !(end_addr <= start_addr || ptr_addr < start_addr 365 | || ptr_addr >= end_addr); 366 | } 367 | 368 | static void 369 | secure_clear_memory (volatile void *memory, const size_t size) 370 | { 371 | if (!memory || size == 0 || size > POOL_BLOCK_SIZE * POOL_BLOCK_COUNT) 372 | { 373 | return; 374 | } 375 | 376 | volatile unsigned char *p = memory; 377 | for (size_t i = 0; i < size; i++) 378 | { 379 | p[i] = 0xFF; 380 | atomic_thread_fence (memory_order_release); 381 | p[i] = 0x00; 382 | atomic_thread_fence (memory_order_release); 383 | p[i] = 0xAA; 384 | atomic_thread_fence (memory_order_release); 385 | p[i] = 0x00; 386 | } 387 | 388 | atomic_thread_fence (memory_order_seq_cst); 389 | } 390 | 391 | static bool 392 | find_contiguous_blocks (const uint64_t *bitmap, const size_t bitmap_size, 393 | const size_t blocks_needed, size_t *start_block) 394 | { 395 | if (bitmap_size > SIZE_MAX / BLOCKS_PER_BITMAP) 396 | { 397 | return false; 398 | } 399 | 400 | size_t consecutive = 0; 401 | const size_t total_blocks = bitmap_size * BLOCKS_PER_BITMAP; 402 | 403 | if (total_blocks > POOL_BLOCK_COUNT) 404 | { 405 | return false; 406 | } 407 | 408 | for (size_t i = 0; i < total_blocks; i++) 409 | { 410 | const size_t word_idx = i / BLOCKS_PER_BITMAP; 411 | const size_t bit_idx = i % BLOCKS_PER_BITMAP; 412 | 413 | atomic_thread_fence (memory_order_acquire); 414 | 415 | if (!(bitmap[word_idx] & (1ULL << bit_idx))) 416 | { 417 | consecutive++; 418 | if (consecutive >= blocks_needed) 419 | { 420 | if (i < blocks_needed - 1) 421 | { 422 | return false; 423 | } 424 | *start_block = i - (blocks_needed - 1); 425 | return true; 426 | } 427 | } 428 | else 429 | { 430 | consecutive = 0; 431 | } 432 | } 433 | return false; 434 | } 435 | 436 | static void 437 | mark_blocks (uint64_t *bitmap, const size_t start_block, 438 | const size_t num_blocks, const bool used) 439 | { 440 | if (!bitmap || start_block >= POOL_BLOCK_COUNT || num_blocks == 0 441 | || num_blocks > POOL_BLOCK_COUNT 442 | || start_block + num_blocks > POOL_BLOCK_COUNT) 443 | { 444 | return; 445 | } 446 | 447 | for (size_t i = 0; i < num_blocks; i++) 448 | { 449 | const size_t block = start_block + i; 450 | const size_t word_idx = block / BLOCKS_PER_BITMAP; 451 | const size_t bit_idx = block % BLOCKS_PER_BITMAP; 452 | 453 | atomic_thread_fence (memory_order_acquire); 454 | 455 | if (used) 456 | { 457 | bitmap[word_idx] |= (1ULL << bit_idx); 458 | } 459 | else 460 | { 461 | bitmap[word_idx] &= ~(1ULL << bit_idx); 462 | } 463 | 464 | atomic_thread_fence (memory_order_release); 465 | } 466 | 467 | atomic_thread_fence (memory_order_seq_cst); 468 | } 469 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AgenC Framework – Whitepaper 2 | 3 | ## $TETSUO on Solana 4 | 5 | **Contract Address**: `8i51XNNpGaKaj4G4nDdmQh95v4FKAxw8mhtaRoKd9tE8` 6 | 7 | [![Twitter](https://img.shields.io/badge/Twitter-Follow%20%407etsuo-1DA1F2)](https://x.com/7etsuo) 8 | [![Discord](https://img.shields.io/badge/Discord-Join%20Our%20Community-7289DA)](https://discord.gg/tetsuo-ai) 9 | 10 | --- 11 | 12 | ![Agenc framework](https://github.com/user-attachments/assets/5cd95fb2-fb49-44b0-a420-4c519d144a94) 13 | 14 | --- 15 | 16 | ### 1. Introduction 17 | The AgenC AI Agent Framework in C is designed to handle perception, cognition, planning, and action execution. The framework supports single and multi-agent configurations, through communication and synchronization interfaces. 18 | 19 | --- 20 | 21 | #### What is an AI Agent Framework 22 | 23 | An AI Agent Framework is a structure for autonomous decision-making in AI systems, similar to how a human brain's nervous system coordinates sensing, thinking, and acting. 24 | 25 | By implementing the framework in C we get speed and compatibility across multiple hardware platforms. 26 | 27 | --- 28 | 29 | AgenC is an open-source AI agent framework built entirely in C. It aims to revolutionize edge computing and embedded AI by enabling sophisticated AI models to run on inexpensive, low-power hardware. 30 | 31 | ## Market Impact & Adoption Potential 32 | 33 | ### Shift in Edge Computing and IoT AI 34 | 35 | - **Closer-to-Device AI:** Enables AI processing near sensors and end-users, reducing reliance on cloud computation, lowering latency, and improving privacy. 36 | - **Expanding Markets:** With the Edge AI market projected to grow to over $270 billion by 2032, a lightweight framework is essential for unlocking new use cases—from smart home appliances to industrial IoT sensors. 37 | - **TinyML Adoption:** As device installs are expected to exceed 11 billion by 2027, a dedicated C agent framework positions AgenC to bring advanced AI to billions of resource-constrained devices. 38 | 39 | ### Open-Source Innovation & Industry Collaboration 40 | 41 | - **Collective Development:** Open-source contributions allow industries such as automotive, robotics, aerospace, and healthcare devices to optimize the framework for specialized needs. 42 | - **Rapid Evolution:** Community-driven development accelerates innovation, similar to how Linux and OpenCV evolved through broad collaboration. 43 | - **Democratizing AI Deployment:** Open availability helps small startups, research labs, and hobbyists deploy state-of-the-art AI on affordable hardware. 44 | 45 | ### Advancing AI in Embedded & Constrained Environments 46 | 47 | - **New Deployment Frontiers:** Brings advanced AI capabilities from high-end devices and data centers to microcontrollers and embedded systems. 48 | - **Real-World Examples:** Enables microcontrollers to perform tasks like real-time anomaly detection or drones to navigate using onboard neural networks. 49 | - **Expanding Use Cases:** Facilitates the creation of smart sensors, adaptive medical implants, and autonomous robotics that operate reliably in resource-limited environments. 50 | 51 | ## Technical Advantages of a C-Based AI Framework 52 | 53 | ### High Performance & Low-Level Efficiency 54 | 55 | - **Direct Hardware Utilization:** Compiled C code produces compact machine instructions with minimal overhead, avoiding the performance penalties of Python’s runtime interpretation and garbage collection. 56 | - **Optimized for Microcontrollers:** C/C++ implementations consistently outperform Python-based solutions in resource-constrained environments. 57 | 58 | ### Real-Time Processing & Low Latency 59 | 60 | - **Predictable Timing:** C provides deterministic timing essential for high-frequency control loops and latency-critical tasks. 61 | - **Stable Performance:** Custom lightweight C libraries have demonstrated reliable performance (e.g., stable 100Hz inference on microcontroller-based systems). 62 | 63 | ### Portability to Diverse Hardware 64 | 65 | - **Broad Compatibility:** C’s portability allows the framework to compile across architectures—from x86 servers to 8/16/32-bit microcontrollers—with minimal changes. 66 | - **Alignment with TinyML:** Supports deployment on bare-metal or simple RTOS setups, making it ideal for the vast number of microcontrollers in use today. 67 | 68 | ### Security & Minimal Attack Surface 69 | 70 | - **Reduced Dependencies:** A lean C framework minimizes the need for large runtimes and numerous external libraries, lowering potential vulnerability points. 71 | - **Simplified Auditing:** Fewer software layers simplify security audits and help maintain a minimal attack surface. 72 | 73 | ## Comparisons with Existing AI Frameworks 74 | 75 | ### Efficiency vs. TensorFlow, PyTorch, and JAX 76 | 77 | - **Eliminating the Python Overhead:** Unlike TensorFlow and PyTorch—which rely on Python for high-level orchestration—a pure C framework avoids issues like GIL contention, Python bytecode interpretation, and increased memory usage. 78 | - **Lean Runtime:** Provides a more straightforward compiled approach that emphasizes efficiency, particularly on edge devices. 79 | 80 | ### Usability and Development Experience 81 | 82 | - **Development Complexity:** While Python offers dynamic typing, interactive notebooks, and a rich ecosystem, C requires manual memory management and lower-level coding, resulting in a steeper learning curve. 83 | - **Enhanced Abstractions:** AgenC will supply robust abstractions and tools to improve usability, aiming to offer a development experience competitive with established frameworks. 84 | 85 | ### Maintainability and Complexity 86 | 87 | - **Engineering Rigor:** Building a framework in C demands strong systems engineering practices to prevent memory leaks, buffer overflows, and race conditions. 88 | - **Simplified Architecture:** Eliminating the need to bridge Python and C++ layers can result in a leaner, more maintainable runtime suitable for long-term deployments. 89 | 90 | ### Community and Ecosystem 91 | 92 | - **Initial Challenges:** Gaining traction against established frameworks like TensorFlow and PyTorch will require building a supportive community. 93 | - **New Contributor Base:** AgenC’s open-source nature is expected to attract embedded systems developers, robotics engineers, and low-level optimization experts who are underserved by current Python-centric tools. 94 | 95 | ## Conclusion 96 | 97 | An open-source AI agent framework in C will catalyze a major shift in AI deployment—from centralized data centers and high-end devices to billions of resource-constrained, edge computing devices. By leveraging the performance, portability, and efficiency of C, AgenC aims to unlock innovative applications in embedded and real-time AI, making advanced AI capabilities accessible in every corner of the physical world. 98 | 99 | --- 100 | 101 | #### Framework Components 102 | The AI Agent Framework needs these core components. 103 | 104 | - **Perception Systems**: These handle all input - sensors, data feeds, user input, anything the AI needs to understand its environment. They clean and structure the raw data into something useful. 105 | 106 | - **Cognitive System**: This is the "brain" that processes information and makes decisions. It manages different AI models working together (like LLMs and neural networks), stores memories of past experiences, and plans actions. 107 | 108 | - **Action System**: Takes decisions and turns them into real actions. It manages timing, prioritizes tasks, and monitors results. 109 | 110 | - **Resource Manager**: Controls system resources like memory and processing power, making sure everything runs efficiently. 111 | 112 | - **Communication System**: Handles how all parts talk to each other and how the framework communicates with the outside world. 113 | 114 | These components are tied together! The key is building them in a way that's fast. This is why C is ideal. 115 | 116 | --- 117 | 118 | #### Core Functions 119 | 120 | - **Data Input**: Collects and standardizes data from sources such as sensors, databases, or user input. 121 | 122 | - **Decision Coordination**: Orchestrates AI components (e.g., language models, neural networks) to generate decisions and learn from outcomes. 123 | 124 | - **Action Execution**: Manages resource allocation, prioritizes tasks, and processes feedback to refine system performance. 125 | 126 | - **Significance**: A ready-made framework eliminates the need to build basic infrastructure repeatedly, allowing developers to focus on creating specific AI capabilities and behaviors. 127 | 128 | --- 129 | 130 | #### Practical Applications 131 | 132 | - Factory robotics that adapt and improve assembly tasks 133 | 134 | - Self-driving systems that make split-second navigation decisions 135 | 136 | - Trading platforms that analyze markets and execute automated trades 137 | 138 | - Virtual assistants that interpret user needs and perform relevant actions 139 | 140 | This type of framework is used for building advanced AI capable of learning, adapting, and interacting with real-world environments. 141 | 142 | --- 143 | 144 | ### 2. High-Level Architecture 145 | The system is divided into key modules, each addressing specific concerns: 146 | 147 | 1. **Agent Core** Manages agent lifecycle, configuration, and overall health. Houses the Agent Manager, Command Dispatcher, System Diagnostics, Health Monitor, and Configuration Optimizer. 148 | 2. **Infrastructure** Provides logging, metrics collection, debugging facilities, testing frameworks, and deployment management. 149 | 3. **Security** Secures the input pipeline and system interactions via input validation, authentication, access control, encryption, and auditing. 150 | 4. **Perception** Collects and processes raw input from sensors. Normalizes data, detects events, and routes validated information to the next processing steps. 151 | 5. **Memory** Stores data and maintains caches, query processing, and context. Prunes obsolete information while accumulating new experiences. 152 | 6. **Knowledge** Manages ontologies, the knowledge graph, and supports information retrieval and conceptual linking for informed decision-making. 153 | 7. **Cognitive** Handles inference, decision-making, learning, and performance evaluation. Manages the belief system and model-related tasks. 154 | 8. **Planning** Schedules tasks, generates plans, evaluates strategies, and manages goals. Receives feedback for continuous plan refinement. 155 | 9. **Action** Executes planned tasks, validates actions, monitors results, and can roll back or reprioritize as needed. 156 | 10. **Resource Management** Monitors and balances resource usage, manages performance, and recovers from failures. 157 | 11. **Communication** Synchronizes states and events among internal and external components. Routes messages, handles protocols, and manages errors. 158 | 12. **Multi-Agent** Discovers other agents, provides collaboration protocols, shares resources, resolves conflicts, and negotiates to reach collective goals. 159 | 13. **Training** Coordinates training processes, modifies behavior, tracks performance metrics, and manages adaptation and model versioning. 160 | 161 | --- 162 | 163 | ### 3. UML Diagram Overview 164 | ![UML](https://github.com/user-attachments/assets/31be890b-c898-4116-951a-06735f2296ac) 165 | The UML diagram outlines each module’s components. The diagram illustrates: 166 | - **Inheritance and Aggregation**: Each main subsystem groups related components. 167 | - **Inter-module Dependencies**: Arrows indicate where a subsystem depends on or directly interacts with another (e.g., Perception depends on Memory and Knowledge). 168 | 169 | --- 170 | 171 | ### 4. Sequence Diagram Summary 172 | ![Sequence Diagram](https://github.com/user-attachments/assets/e2c6af24-f21a-4391-a3da-820382bf28a2) 173 | The Sequence Diagram traces a typical execution flow: 174 | 1. **Initialization**: Infrastructure and Security components start up and validate the system. 175 | 2. **Input Processing**: Perception normalizes validated inputs and stores relevant data in Memory. 176 | 3. **Cognitive Processing**: Cognitive requests contextual data from Knowledge and Memory, then prepares a decision. 177 | 4. **Planning & Execution**: Planning checks resources and coordinates with Multi-Agent systems if necessary, then delegates tasks to Action. 178 | 5. **Resource Allocation & Communication**: Action uses Resource Management to allocate resources and sends progress updates via Communication. 179 | 6. **Training & Memory Updates**: Results feed back into Training and Memory, keeping the system’s models and stored data updated. 180 | 181 | --- 182 | 183 | ### 5. State Diagram Summary 184 | ![sate](https://github.com/user-attachments/assets/7945db21-89e0-47ff-b37c-735a9627d258) 185 | The State Diagram describes system states from startup to shutdown: 186 | - **SystemInitialization** and **SecurityCheck**: The system transitions to **Ready** if security checks pass; otherwise it enters an **Error** state. 187 | - **InputProcessing** and **CognitiveProcessing**: Valid inputs transition the system into advanced phases of knowledge query and planning. 188 | - **Planning, ResourceCheck, MultiAgentCoordination, Execution**: These states determine resource availability, multi-agent interactions, and task execution. 189 | - **Training & MemoryUpdate**: The system refines its knowledge and memory based on execution outcomes, looping back to **Ready**. 190 | - **Error Handling**: Errors engage System Diagnostics followed by AutoRecoverySystem, returning the system to **Ready** if successful. 191 | 192 | --- 193 | 194 | ### 6. Swimlane Diagram Summary 195 | ![Swimlane](https://github.com/user-attachments/assets/c6882211-14d3-417e-a9b2-20b999363b10) 196 | The Swimlane Diagram organizes components under distinct subsystems (e.g., AgentCore, Security, Perception, Memory, etc.). It shows: 197 | - **Security** (Input Validator) acting before Perception receives data. 198 | - **Cognitive** invoking Knowledge and Memory queries. 199 | - **Planning** leveraging ResourceManagement and coordinating with MultiAgent. 200 | - **Action** interacting with Communication and reporting to Training. 201 | - **Infrastructure** providing logging and diagnostics capabilities throughout. 202 | - **Dotted Lines** indicate cross-cutting concerns (e.g., authentication, logging) that are accessed by every component. 203 | 204 | --- 205 | 206 | ### 7. Implementation Considerations 207 | **Language and Efficiency** 208 | - C offers control over memory and execution flow, it is high-performance and cross platform. 209 | - Modularity and clear function boundaries help maintain code clarity. 210 | 211 | **Concurrency and Resource Management** 212 | - Threading or event-driven models can be employed, with ResourceManagement for efficient load balancing and recovery from failures. 213 | 214 | **Security and Reliability** 215 | - Input validation and access control guard against unauthorized data or operations. 216 | - Monitoring and diagnostics for detection of anomalies. 217 | 218 | **Extendibility** 219 | - The architecture supports adding new modules or replacing sub-components (e.g., switching out a knowledge graph implementation without broad changes elsewhere). 220 | 221 | --- 222 | 223 | ### 8. Conclusion 224 | The AI Agent Framework in C integrates perception, memory, knowledge, cognition, planning, action, multi-agent collaboration, and training. By structuring these subsystems as discrete modules, we get performance, maintainability, and scalability. The provided diagrams align component interactions, giving a high level view of how data flows through the system. 225 | 226 | --- 227 | -------------------------------------------------------------------------------- /src/memory_interface/tests/test_fuzz_default_strategy.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | /** 3 | * @file test_fuzz_default_strategy.c 4 | * @brief Enhanced fuzzing tests for DefaultStrategy implementation 5 | */ 6 | 7 | #include "test_default_strategy.h" 8 | #include "../src/default_strategy.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define FUZZ_THREADS 8 // Reduced thread count 21 | #define FUZZ_ITERATIONS 1000 // Reduced iterations 22 | #define MAX_ALLOCATION_SIZE (64 * 1024) // Reduced to 64KB 23 | #define MIN_ALLOCATION_SIZE 1 24 | #define RANDOM_DELAY_MAX_US 1000 25 | #define ALLOCATION_PATTERN_COUNT 8 26 | #define REALLOCATION_PROBABILITY 15 27 | #define EARLY_FREE_PROBABILITY 10 28 | #define MEMORY_CHECK_PATTERN 0xAA 29 | #define CLEANUP_RETRY_COUNT 3 30 | 31 | typedef struct 32 | { 33 | DefaultStrategy *strategy; 34 | unsigned int seed; 35 | atomic_size_t total_allocated; 36 | atomic_size_t total_freed; 37 | atomic_size_t errors; 38 | atomic_size_t reallocations; 39 | atomic_bool should_stop; 40 | atomic_int active_threads; 41 | atomic_bool cleanup_phase; 42 | } fuzz_context_t; 43 | 44 | typedef struct 45 | { 46 | void *ptr; 47 | size_t size; 48 | uint32_t checksum; 49 | bool is_valid; 50 | } allocation_record_t; 51 | 52 | static void 53 | random_delay (unsigned int *seed) 54 | { 55 | if (rand_r (seed) % 4 == 0) 56 | { 57 | unsigned int delay 58 | = (rand_r (seed) % RANDOM_DELAY_MAX_US) * (1 << (rand_r (seed) % 4)); 59 | usleep (delay); 60 | } 61 | } 62 | 63 | static size_t 64 | get_random_size (unsigned int *seed) 65 | { 66 | int pattern = rand_r (seed) % ALLOCATION_PATTERN_COUNT; 67 | size_t size; 68 | 69 | switch (pattern) 70 | { 71 | case 0: // Tiny allocations (1-16 bytes) 72 | size = (rand_r (seed) % 16) + 1; 73 | break; 74 | case 1: // Small allocations (17-256 bytes) 75 | size = (rand_r (seed) % 240) + 17; 76 | break; 77 | case 2: // Medium allocations (257-4096 bytes) 78 | size = (rand_r (seed) % 3840) + 257; 79 | break; 80 | case 3: // Large allocations 81 | size = (rand_r (seed) % (32 * 1024)) + 4097; 82 | break; 83 | case 4: // Power of 2 sizes 84 | size = 1ULL << (rand_r (seed) % 12); // Reduced max power 85 | break; 86 | case 5: // Page boundary adjacent 87 | size = 4096 + ((rand_r (seed) % 128) - 64); 88 | break; 89 | case 6: // Cache line adjacent (64 bytes) 90 | size = 64 + ((rand_r (seed) % 16) - 8); 91 | break; 92 | case 7: // Prime numbers near power of 2 93 | size = (1ULL << (rand_r (seed) % 10)) + (rand_r (seed) % 17) - 8; 94 | break; 95 | default: 96 | size = 64; 97 | } 98 | 99 | return size < MIN_ALLOCATION_SIZE 100 | ? MIN_ALLOCATION_SIZE 101 | : (size > MAX_ALLOCATION_SIZE ? MAX_ALLOCATION_SIZE : size); 102 | } 103 | 104 | static uint32_t 105 | calculate_checksum (const void *ptr, size_t size) 106 | { 107 | const unsigned char *data = (const unsigned char *) ptr; 108 | uint32_t checksum = 0; 109 | 110 | for (size_t i = 0; i < size; i++) 111 | { 112 | checksum = ((checksum << 5) + checksum) + data[i]; 113 | } 114 | 115 | return checksum; 116 | } 117 | 118 | static bool 119 | verify_allocation (allocation_record_t *record) 120 | { 121 | if (!record->ptr || !record->is_valid) 122 | return false; 123 | 124 | const unsigned char *mem = (const unsigned char *) record->ptr; 125 | for (size_t i = 0; i < record->size; i++) 126 | { 127 | if (mem[i] != MEMORY_CHECK_PATTERN) 128 | { 129 | return false; 130 | } 131 | } 132 | 133 | uint32_t current_checksum = calculate_checksum (record->ptr, record->size); 134 | return current_checksum == record->checksum; 135 | } 136 | 137 | static void 138 | safe_deallocate (DefaultStrategy *strategy, allocation_record_t *record) 139 | { 140 | if (!record->ptr || !record->is_valid) 141 | return; 142 | 143 | atomic_thread_fence (memory_order_acquire); 144 | 145 | if (verify_allocation (record)) 146 | { 147 | default_deallocate (&strategy->base, record->ptr); 148 | record->ptr = NULL; 149 | record->is_valid = false; 150 | } 151 | 152 | atomic_thread_fence (memory_order_release); 153 | } 154 | 155 | static void * 156 | fuzz_worker (void *arg) 157 | { 158 | fuzz_context_t *ctx = (fuzz_context_t *) arg; 159 | allocation_record_t *allocations 160 | = calloc (FUZZ_ITERATIONS, sizeof (allocation_record_t)); 161 | if (!allocations) 162 | { 163 | atomic_fetch_add (&ctx->errors, 1); 164 | return NULL; 165 | } 166 | 167 | unsigned int local_seed 168 | = ctx->seed ^ (unsigned int) (uintptr_t) pthread_self (); 169 | size_t successful_allocs = 0; 170 | atomic_size_t thread_total_allocated = 0; 171 | atomic_size_t thread_total_freed = 0; 172 | 173 | atomic_fetch_add (&ctx->active_threads, 1); 174 | atomic_thread_fence (memory_order_seq_cst); 175 | 176 | while (!atomic_load (&ctx->should_stop) && !atomic_load (&ctx->cleanup_phase) 177 | && successful_allocs < FUZZ_ITERATIONS) 178 | { 179 | int operation = rand_r (&local_seed) % 100; 180 | 181 | if (operation < REALLOCATION_PROBABILITY && successful_allocs > 0) 182 | { 183 | size_t idx = rand_r (&local_seed) % successful_allocs; 184 | if (allocations[idx].is_valid) 185 | { 186 | atomic_thread_fence (memory_order_acquire); 187 | size_t new_size = get_random_size (&local_seed); 188 | void *new_ptr = default_allocate (&ctx->strategy->base, new_size); 189 | 190 | if (new_ptr) 191 | { 192 | if (verify_allocation (&allocations[idx])) 193 | { 194 | size_t copy_size = (new_size < allocations[idx].size) 195 | ? new_size 196 | : allocations[idx].size; 197 | memcpy (new_ptr, allocations[idx].ptr, copy_size); 198 | 199 | atomic_fetch_add (&thread_total_allocated, new_size); 200 | safe_deallocate (ctx->strategy, &allocations[idx]); 201 | atomic_fetch_add (&thread_total_freed, allocations[idx].size); 202 | 203 | allocations[idx].ptr = new_ptr; 204 | allocations[idx].size = new_size; 205 | memset (new_ptr, MEMORY_CHECK_PATTERN, new_size); 206 | allocations[idx].checksum = calculate_checksum (new_ptr, new_size); 207 | allocations[idx].is_valid = true; 208 | 209 | atomic_fetch_add (&ctx->reallocations, 1); 210 | } 211 | else 212 | { 213 | default_deallocate (&ctx->strategy->base, new_ptr); 214 | atomic_fetch_add (&ctx->errors, 1); 215 | } 216 | } 217 | atomic_thread_fence (memory_order_release); 218 | } 219 | } 220 | else if (operation < EARLY_FREE_PROBABILITY && successful_allocs > 0) 221 | { 222 | size_t idx = rand_r (&local_seed) % successful_allocs; 223 | if (allocations[idx].is_valid) 224 | { 225 | atomic_thread_fence (memory_order_acquire); 226 | if (verify_allocation (&allocations[idx])) 227 | { 228 | atomic_fetch_add (&thread_total_freed, allocations[idx].size); 229 | safe_deallocate (ctx->strategy, &allocations[idx]); 230 | } 231 | else 232 | { 233 | atomic_fetch_add (&ctx->errors, 1); 234 | } 235 | atomic_thread_fence (memory_order_release); 236 | } 237 | } 238 | else 239 | { 240 | size_t size = get_random_size (&local_seed); 241 | random_delay (&local_seed); 242 | 243 | atomic_thread_fence (memory_order_acquire); 244 | void *ptr = default_allocate (&ctx->strategy->base, size); 245 | 246 | if (ptr) 247 | { 248 | allocation_record_t *record = &allocations[successful_allocs]; 249 | record->ptr = ptr; 250 | record->size = size; 251 | record->is_valid = true; 252 | 253 | memset (ptr, MEMORY_CHECK_PATTERN, size); 254 | record->checksum = calculate_checksum (ptr, size); 255 | 256 | atomic_fetch_add (&thread_total_allocated, size); 257 | successful_allocs++; 258 | 259 | atomic_thread_fence (memory_order_release); 260 | random_delay (&local_seed); 261 | } 262 | } 263 | } 264 | 265 | atomic_thread_fence (memory_order_seq_cst); 266 | size_t cleanup_retries = 0; 267 | const size_t MAX_CLEANUP_RETRIES = 3; 268 | 269 | while (cleanup_retries < MAX_CLEANUP_RETRIES) 270 | { 271 | bool cleanup_failed = false; 272 | 273 | for (size_t i = 0; i < successful_allocs; i++) 274 | { 275 | if (allocations[i].is_valid) 276 | { 277 | if (verify_allocation (&allocations[i])) 278 | { 279 | atomic_fetch_add (&thread_total_freed, allocations[i].size); 280 | safe_deallocate (ctx->strategy, &allocations[i]); 281 | } 282 | else 283 | { 284 | atomic_fetch_add (&ctx->errors, 1); 285 | cleanup_failed = true; 286 | } 287 | } 288 | } 289 | 290 | if (!cleanup_failed) 291 | break; 292 | cleanup_retries++; 293 | usleep (1000 * (1 << cleanup_retries)); // Exponential backoff 294 | } 295 | 296 | atomic_thread_fence (memory_order_seq_cst); 297 | atomic_fetch_add (&ctx->total_allocated, thread_total_allocated); 298 | atomic_fetch_add (&ctx->total_freed, thread_total_freed); 299 | 300 | free (allocations); 301 | atomic_fetch_sub (&ctx->active_threads, 1); 302 | atomic_thread_fence (memory_order_seq_cst); 303 | 304 | return NULL; 305 | } 306 | 307 | void 308 | test_allocation_pattern_fuzzing (void) 309 | { 310 | printf ("Running enhanced allocation pattern fuzzing test...\n"); 311 | 312 | DefaultStrategy *strategy = create_default_strategy (); 313 | assert (strategy != NULL); 314 | 315 | fuzz_context_t ctx = {.strategy = strategy, 316 | .seed = (unsigned int) time (NULL), 317 | .total_allocated = 0, 318 | .total_freed = 0, 319 | .errors = 0, 320 | .reallocations = 0, 321 | .should_stop = false, 322 | .active_threads = 0, 323 | .cleanup_phase = false}; 324 | 325 | pthread_t threads[FUZZ_THREADS]; 326 | atomic_thread_fence (memory_order_seq_cst); 327 | 328 | for (int i = 0; i < FUZZ_THREADS; i++) 329 | { 330 | int rc = pthread_create (&threads[i], NULL, fuzz_worker, &ctx); 331 | if (rc != 0) 332 | { 333 | fprintf (stderr, "Failed to create thread %d: %s\n", i, strerror (rc)); 334 | atomic_store (&ctx.should_stop, true); 335 | break; 336 | } 337 | usleep (1000); 338 | } 339 | 340 | stats_report_t last_report = {0}; 341 | size_t unchanged_count = 0; 342 | while (atomic_load (&ctx.active_threads) > 0) 343 | { 344 | stats_report_t report; 345 | memory_stats_get_report (strategy->stats, &report); 346 | 347 | if (report.current_bytes == last_report.current_bytes 348 | && report.current_bytes > 0) 349 | { 350 | unchanged_count++; 351 | if (unchanged_count > 5) 352 | { // If usage is stuck for 500ms 353 | printf ("\nStuck memory usage detected, initiating cleanup...\n"); 354 | atomic_store (&ctx.cleanup_phase, true); 355 | atomic_store (&ctx.should_stop, true); 356 | break; 357 | } 358 | } 359 | else 360 | { 361 | unchanged_count = 0; 362 | } 363 | last_report = report; 364 | 365 | printf ("\rActive threads: %d, Current usage: %zu bytes, " 366 | "Peak: %zu bytes, Errors: %zu, Reallocations: %zu ", 367 | atomic_load (&ctx.active_threads), report.current_bytes, 368 | report.peak_bytes, (size_t) ctx.errors, (size_t) ctx.reallocations); 369 | fflush (stdout); 370 | 371 | if (report.current_bytes > MAX_ALLOCATION_SIZE * FUZZ_THREADS * 2) 372 | { 373 | printf ("\nExcessive memory usage detected, initiating cleanup...\n"); 374 | atomic_store (&ctx.cleanup_phase, true); 375 | } 376 | 377 | usleep (100000); 378 | } 379 | printf ("\n"); 380 | 381 | struct timespec timeout; 382 | clock_gettime (CLOCK_REALTIME, &timeout); 383 | timeout.tv_sec += 2; // 2 second timeout 384 | 385 | for (int i = 0; i < FUZZ_THREADS; i++) 386 | { 387 | int rc = pthread_timedjoin_np (threads[i], NULL, &timeout); 388 | if (rc == ETIMEDOUT) 389 | { 390 | printf ("Thread %d timed out during cleanup, forcing stop...\n", i); 391 | atomic_store (&ctx.should_stop, true); 392 | } 393 | } 394 | 395 | atomic_thread_fence (memory_order_seq_cst); 396 | 397 | stats_report_t final_report; 398 | bool cleanup_success = false; 399 | size_t retry_delay = 100000; // Start with 100ms 400 | 401 | const int MAX_GLOBAL_CLEANUP_RETRIES = 5; 402 | for (int cleanup_retry = 0; 403 | cleanup_retry < MAX_GLOBAL_CLEANUP_RETRIES && !cleanup_success; 404 | cleanup_retry++) 405 | { 406 | memory_stats_get_report (strategy->stats, &final_report); 407 | 408 | if (final_report.current_bytes == 0 409 | && final_report.active_allocation_count == 0) 410 | { 411 | cleanup_success = true; 412 | } 413 | else 414 | { 415 | usleep (retry_delay); 416 | retry_delay *= 2; // Exponential backoff 417 | } 418 | } 419 | 420 | printf ("\nFinal Results:\n"); 421 | printf ("Total Allocated: %zu bytes\n", (size_t) ctx.total_allocated); 422 | printf ("Total Freed: %zu bytes\n", (size_t) ctx.total_freed); 423 | printf ("Total Reallocations: %zu\n", (size_t) ctx.reallocations); 424 | printf ("Peak Usage: %zu bytes\n", get_peak_usage (strategy)); 425 | printf ("Error Count: %zu\n", (size_t) ctx.errors); 426 | printf ("Active Allocations: %u\n", final_report.active_allocation_count); 427 | printf ("Memory Leaks: %zu bytes\n", final_report.total_leaked_bytes); 428 | 429 | if (ctx.total_allocated != ctx.total_freed) 430 | { 431 | printf ("Memory tracking mismatch:\n"); 432 | printf ("Total allocated: %zu\n", (size_t) ctx.total_allocated); 433 | printf ("Total freed: %zu\n", (size_t) ctx.total_freed); 434 | printf ("Difference: %zd bytes\n", 435 | (ssize_t) ctx.total_allocated - (ssize_t) ctx.total_freed); 436 | } 437 | 438 | assert (ctx.total_allocated == ctx.total_freed); 439 | assert (final_report.current_bytes == 0); 440 | assert (final_report.active_allocation_count == 0); 441 | assert (final_report.total_leaked_bytes == 0); 442 | assert (ctx.errors == 0); 443 | 444 | destroy_default_strategy (strategy); 445 | printf ("Enhanced allocation pattern fuzzing test completed\n"); 446 | } 447 | 448 | void 449 | test_edge_case_fuzzing (void) 450 | { 451 | printf ("Running edge case fuzzing test...\n"); 452 | DefaultStrategy *strategy = create_default_strategy (); 453 | assert (strategy != NULL); 454 | 455 | atomic_thread_fence (memory_order_seq_cst); 456 | 457 | void *ptrs[1000] = {NULL}; 458 | size_t sizes[1000] = {0}; 459 | size_t alloc_count = 0; 460 | 461 | void *ptr = default_allocate (&strategy->base, SIZE_MAX); 462 | assert (ptr == NULL); 463 | 464 | ptr = default_allocate (&strategy->base, 0); 465 | assert (ptr == NULL); 466 | 467 | for (int i = 0; i < 1000 && alloc_count < 1000; i++) 468 | { 469 | sizes[alloc_count] = 1 << (i % 12); // Power of 2 sizes up to 4KB 470 | atomic_thread_fence (memory_order_acquire); 471 | 472 | ptrs[alloc_count] = default_allocate (&strategy->base, sizes[alloc_count]); 473 | if (ptrs[alloc_count]) 474 | { 475 | size_t allocated_size; 476 | memory_stats_get_allocation_size (strategy->stats, ptrs[alloc_count], 477 | &allocated_size); 478 | assert (allocated_size == sizes[alloc_count]); 479 | 480 | memset (ptrs[alloc_count], i % 256, sizes[alloc_count]); 481 | alloc_count++; 482 | } 483 | 484 | atomic_thread_fence (memory_order_release); 485 | } 486 | 487 | for (size_t i = 0; i < alloc_count; i++) 488 | { 489 | if (ptrs[i]) 490 | { 491 | atomic_thread_fence (memory_order_acquire); 492 | default_deallocate (&strategy->base, ptrs[i]); 493 | atomic_thread_fence (memory_order_release); 494 | } 495 | } 496 | 497 | atomic_thread_fence (memory_order_seq_cst); 498 | usleep (10000); // 10ms delay for final cleanup 499 | 500 | stats_report_t report; 501 | memory_stats_get_report (strategy->stats, &report); 502 | assert (report.current_bytes == 0); 503 | assert (report.active_allocation_count == 0); 504 | assert (report.total_leaked_bytes == 0); 505 | 506 | destroy_default_strategy (strategy); 507 | printf ("Edge case fuzzing test passed\n"); 508 | } 509 | 510 | void 511 | run_fuzz_tests (void) 512 | { 513 | printf ("\nRunning DefaultStrategy fuzzing tests...\n"); 514 | 515 | for (int i = 0; i < 3; i++) 516 | { 517 | printf ("\nFuzz test iteration %d:\n", i + 1); 518 | test_allocation_pattern_fuzzing (); 519 | test_edge_case_fuzzing (); 520 | usleep (100000); // Delay between iterations 521 | } 522 | 523 | printf ("\nAll fuzzing tests completed successfully\n"); 524 | } 525 | --------------------------------------------------------------------------------