diff --git a/include/test_runner.h b/include/test_runner.h index f61f26b66e..9e0d96ff5b 100644 --- a/include/test_runner.h +++ b/include/test_runner.h @@ -20,6 +20,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId); void TestRunner_Battle_AISetScore(const char *file, u32 line, u32 battlerId, u32 moveIndex, s32 score); void TestRunner_Battle_AIAdjustScore(const char *file, u32 line, u32 battlerId, u32 moveIndex, s32 score); void TestRunner_Battle_InvalidNoHPMon(u32 battlerId, u32 partyIndex); +void TestRunner_CheckMemory(void); void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordIndex, u32 actionType); diff --git a/test/test_runner.c b/test/test_runner.c index 7a81d1dc9f..f279835c4b 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -104,6 +104,62 @@ static u32 AssignCostToRunner(void) return minCostProcess; } +void TestRunner_CheckMemory(void) +{ + if (gTestRunnerState.result == TEST_RESULT_PASS + && !gTestRunnerState.expectLeaks) + { + int i; + const struct MemBlock *head = HeapHead(); + const struct MemBlock *block = head; + do + { + if (block->magic != MALLOC_SYSTEM_ID + || !(EWRAM_START <= (uintptr_t)block->next && (uintptr_t)block->next < EWRAM_END) + || (block->next <= block && block->next != head)) + { + Test_MgbaPrintf("gHeap corrupted block at %p", block); + gTestRunnerState.result = TEST_RESULT_ERROR; + break; + } + + if (block->allocated) + { + const char *location = MemBlockLocation(block); + if (location) + { + const char *cmpString = "src/generational_changes.c"; + for (u32 charIndex = 0; charIndex < 26; charIndex++) + { + if (cmpString[charIndex] != location[charIndex]) + { + Test_MgbaPrintf("%s: %d bytes not freed", location, block->size); + gTestRunnerState.result = TEST_RESULT_FAIL; + break; + } + } + } + else + { + Test_MgbaPrintf(": %d bytes not freed", block->size); + gTestRunnerState.result = TEST_RESULT_FAIL; + } + } + block = block->next; + } + while (block != head); + + for (i = 0; i < NUM_TASKS; i++) + { + if (gTasks[i].isActive) + { + Test_MgbaPrintf(":L%s:%d - %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); + gTestRunnerState.result = TEST_RESULT_FAIL; + } + } + } +} + void CB2_TestRunner(void) { top: @@ -242,45 +298,7 @@ top: gTestRunnerState.tearDown = FALSE; } - if (gTestRunnerState.result == TEST_RESULT_PASS - && !gTestRunnerState.expectLeaks) - { - int i; - const struct MemBlock *head = HeapHead(); - const struct MemBlock *block = head; - do - { - if (block->magic != MALLOC_SYSTEM_ID - || !(EWRAM_START <= (uintptr_t)block->next && (uintptr_t)block->next < EWRAM_END) - || (block->next <= block && block->next != head)) - { - Test_MgbaPrintf("gHeap corrupted block at %p", block); - gTestRunnerState.result = TEST_RESULT_ERROR; - break; - } - - if (block->allocated) - { - const char *location = MemBlockLocation(block); - if (location) - Test_MgbaPrintf("%s: %d bytes not freed", location, block->size); - else - Test_MgbaPrintf(": %d bytes not freed", block->size); - gTestRunnerState.result = TEST_RESULT_FAIL; - } - block = block->next; - } - while (block != head); - - for (i = 0; i < NUM_TASKS; i++) - { - if (gTasks[i].isActive) - { - Test_MgbaPrintf(":L%s:%d - %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); - gTestRunnerState.result = TEST_RESULT_FAIL; - } - } - } + TestRunner_CheckMemory(); if (gTestRunnerState.test->runner == &gAssumptionsRunner) { diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 1c137558a4..399cb8a852 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -1347,6 +1347,7 @@ static void TearDownBattle(void) static void CB2_BattleTest_NextParameter(void) { + TestRunner_CheckMemory(); if (++STATE->runParameter >= STATE->parameters) { SetMainCallback2(CB2_TestRunner); diff --git a/tools/mgba-rom-test-hydra/main.c b/tools/mgba-rom-test-hydra/main.c index 55ba664e75..8eb66debcb 100644 --- a/tools/mgba-rom-test-hydra/main.c +++ b/tools/mgba-rom-test-hydra/main.c @@ -111,6 +111,8 @@ static const struct Symbol *lookup_address(uint32_t address) // available by default. void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { + if (haystacklen < needlelen) + return NULL; const char *haystack_ = haystack; const char *needle_ = needle; for (size_t i = 0; i < haystacklen - needlelen; i++)