#include <stdio.h> #include <string.h> #include <kc.h> #include <kc_assert.h> #include <kc_ut.h> #include <kc_memory.h> #include "ut.h" // プロトタイプ宣言 static void test_memory_start(void); static void test_memory_dump(void); static void test_memory_set_listener(void); static void test_memory_entries(void); static void test_memory_freeif(void); static void test_memory_aligned(void); static void test_memory_calloc(void); static void test_memory_realloc(void); static void test_memory_raw_xxxxx(void); /** * memory_mark 単体テストスイート */ void suite_memory(void) { KcUt *ut = KcUt_get_instance(); ut->add(ut, UT_TESTCASE, "memory start", test_memory_start); ut->add(ut, UT_TESTCASE, "memory dump", test_memory_dump); ut->add(ut, UT_TESTCASE, "memory set_listener", test_memory_set_listener); ut->add(ut, UT_TESTCASE, "memory entries", test_memory_entries); ut->add(ut, UT_TESTCASE, "memory freeif", test_memory_freeif); ut->add(ut, UT_TESTCASE, "memory aligned", test_memory_aligned); ut->add(ut, UT_TESTCASE, "memory calloc", test_memory_calloc); ut->add(ut, UT_TESTCASE, "memory realloc", test_memory_realloc); ut->add(ut, UT_TESTCASE, "memory raw_xxxxx", test_memory_raw_xxxxx); } /** * メモリ管理開始。 * * @process メモリ管理開始(情報詳細出力あり) * @process メモリ管理開始(情報詳細出力無し) */ static void test_memory_start(void) { // NOP // ut.c にて、下記実施 // KcMemory_start(false); // KcMemory_start(true); } extern void KcMemory_dump_leak(void); static bool test_memory_dump_handler(const char *data) { printf("%s", data); return true; } /** * 確保中のメモリ情報出力。 * * @process dump を実行する。 * @result 確保中のメモリ情報が出力されること。 * * @param dump_leak を実行する。 * @result メモリリーク情報が出力されること。 * * @process 確保しているメモリがない状態で dump を実行する。 * @result メモリ情報が出力されないこと。 * * @process 出力用ハンドラを指定してメモリをダンプする。 * @result ハンドラに対してメモリ情報が渡されること。 */ static void test_memory_dump(void) { int *val = (int *)malloc(sizeof(int)); *val = 10; printf("---DUMP---\n"); KcMemory_dump(); printf("---DUMP LEAK---\n"); KcMemory_dump_leak(); free(val); printf("---DUMP---\n"); KcMemory_dump(); val = (int *)malloc(sizeof(int)); *val = 20; kc_memory_manager->dump( test_memory_dump_handler, 16, true, true, 8192); free(val); } /** * リスナ設定(NULL指定)。 * * @process リスナを登録する。(NULL指定) * @result リスナが設定されないこと。 */ static void test_memory_set_listener(void) { KcMemoryListener listener; listener.allocate = NULL; listener.free = NULL; listener.error = NULL; kc_memory_manager->set_listener(&listener); } // ハンドラ実行用 static int test_memory_entries_handler_counter = 0; static int test_memory_entries_handler_values[10]; static int test_memory_entries_handler_can_loop = 0; static bool test_memory_entries_handler(const KcMemoryEntry *entry, void *info) { assert_equals( test_memory_entries_handler_values[test_memory_entries_handler_counter], *((int *)entry->data)); test_memory_entries_handler_counter++; test_memory_entries_handler_can_loop--; assert_equals("X", (const char *)info); if (test_memory_entries_handler_can_loop <= 0) { return false; } return true; } /** * メモリエントリハンドラ実行 */ static void test_memory_entries(void) { int *val1 = (int *)malloc(sizeof(int)); int *val2 = (int *)malloc(sizeof(int)); int *val3 = (int *)malloc(sizeof(int)); *val1 = 123; *val2 = 456; *val3 = 789; test_memory_entries_handler_values[0] = 123; test_memory_entries_handler_values[1] = 456; test_memory_entries_handler_values[2] = 789; // 途中中断パターン test_memory_entries_handler_counter = 0; test_memory_entries_handler_can_loop = 2; kc_memory_manager->entries(test_memory_entries_handler, "X"); assert_equals(2, test_memory_entries_handler_counter); // 全てダンプパターン test_memory_entries_handler_counter = 0; test_memory_entries_handler_can_loop = 999; kc_memory_manager->entries(test_memory_entries_handler, "X"); assert_equals(3, test_memory_entries_handler_counter); free(val1); free(val2); free(val3); } bool test_memory_freeif_handler(const KcMemoryEntry *entry, void *info) { assert_equals("FREEIF", (const char *)info); if (strcmp("test_memory_freeif", entry->func) == 0) { int *data = (int *)entry->data; if (*data == 456) { return true; } } return false; } /** * 強制メモリ破棄 */ static void test_memory_freeif(void) { int *val1 = (int *)malloc(sizeof(int)); int *val2 = (int *)malloc(sizeof(int)); int *val3 = (int *)malloc(sizeof(int)); *val1 = 123; *val2 = 456; *val3 = 789; test_memory_entries_handler_values[0] = 123; test_memory_entries_handler_values[1] = 456; test_memory_entries_handler_values[2] = 789; kc_memory_manager->freeif(test_memory_freeif_handler, "FREEIF"); free(val1); // free(val2); free(val3); } // メモリ確保失敗動作確認用 static int UT_Memory_can_alloc_counter = 0; static bool UT_Memory_can_alloc( KcMemoryEntry *entry, size_t alignment, size_t size, KcMemoryMark mark, const char *file, const char *func, int line) { UNUSED_VARIABLE(entry); UNUSED_VARIABLE(alignment); UNUSED_VARIABLE(size); UNUSED_VARIABLE(mark); UNUSED_VARIABLE(file); UNUSED_VARIABLE(func); UNUSED_VARIABLE(line); UT_Memory_can_alloc_counter--; if (UT_Memory_can_alloc_counter < 0) { return false; } return true; } /** * アライメント指定メモリ確保 * * @process aligned_alloc によりメモリを確保する。 * @result メモリが確保されること。 * * @process メモリ確保が失敗する状態で、aligned_alloc を実行する。 * @result メモリ確保に失敗し、NULL が返されること。 */ static void test_memory_aligned(void) { int *val = (int *)aligned_alloc(sizeof(long long), sizeof(int)); assert_not_null(val); *val = 123; free(val); UT_Memory_can_alloc_counter = 0; _UT_KcMemory_can_alloc = UT_Memory_can_alloc; val = (int *)aligned_alloc(sizeof(long long), sizeof(int)); assert_null(val); _UT_KcMemory_can_alloc = NULL; } /** * calloc によるメモリ確保 * * @process calloc によりメモリを確保する。 * @result メモリが確保されること。内容がすべて 0 のこと。 * * @process メモリ確保が失敗する状態で、calloc を実行する。 * @result メモリ確保に失敗し、NULL が返されること。 */ static void test_memory_calloc(void) { int *val = (int *)calloc(10, sizeof(int)); for (int i = 0; i < 10; i++) { assert_equals(0, val[i]); } free(val); UT_Memory_can_alloc_counter = 0; _UT_KcMemory_can_alloc = UT_Memory_can_alloc; val = (int *)calloc(10, sizeof(int)); assert_null(val); _UT_KcMemory_can_alloc = NULL; } /** * realloc によるメモリ確保 * * @process NULL を指定して、realloc によりメモリを確保する。 * @result メモリが確保されること。 * * @process メモリ確保が失敗する状態で、calloc を実行する。 * @result メモリ確保に失敗し、NULL が返されること。 */ static void test_memory_realloc(void) { // NULL 指定 int *val = realloc(NULL, sizeof(int)); assert_not_null(val); *val = 123; free(val); // 管理外メモリによる realloc int *unmng_ptr = raw_malloc(sizeof(int) * 2); unmng_ptr[0] = 123; unmng_ptr[1] = 456; assert_equals(123, unmng_ptr[0]); assert_equals(456, unmng_ptr[1]); int *mng_ptr = (int *)realloc(unmng_ptr, sizeof(int) * 3); assert_null(mng_ptr); free(unmng_ptr); } /** * raw_xxxxx 関数動作確認。 */ static void test_memory_raw_xxxxx(void) { int *ptr = (int *)raw_malloc(sizeof(int)); assert_not_null(ptr); raw_free(ptr); ptr = raw_aligned_alloc(sizeof(int), sizeof(int)); assert_not_null(ptr); #if (KC_IS_WINDOWS) _aligned_free(ptr); #else raw_free(ptr); #endif ptr = raw_calloc(10, sizeof(int)); assert_not_null(ptr); ptr = raw_realloc(ptr, 20); assert_not_null(ptr); raw_free(ptr); }