From cb094cfad9251af00ff891282951412728cfa86f Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Mon, 25 Aug 2025 17:11:44 -0400 Subject: [PATCH 1/5] match osmalloc --- include/libc64/os_malloc.h | 18 +++ src/boot/libc64/__osMalloc.c | 235 +++++++++++++++++++++++++++++++++-- src/code/gamealloc.c | 3 + 3 files changed, 248 insertions(+), 8 deletions(-) diff --git a/include/libc64/os_malloc.h b/include/libc64/os_malloc.h index 78cbc233f3..30b54cf270 100644 --- a/include/libc64/os_malloc.h +++ b/include/libc64/os_malloc.h @@ -4,12 +4,23 @@ #include "ultra64.h" #include "stddef.h" +#include "unk.h" +#include "versions.h" + typedef struct ArenaNode { /* 0x0 */ s16 magic; // Should always be 0x7373 /* 0x2 */ s16 isFree; /* 0x4 */ size_t size; /* 0x8 */ struct ArenaNode* next; /* 0xC */ struct ArenaNode* prev; + #if MM_VERSION <= N64_JP_1_1 + /* 0x10 */ s32 unk_10; + /* 0x14 */ s32 unk_14; + /* 0x18 */ OSId unk_18; + /* 0x1C */ void *unk_1C; + /* 0x20 */ OSTime unk_20; + /* 0x28 */ UNK_TYPE1 unk_28[0x8]; + #endif } ArenaNode; // size = 0x10 typedef struct Arena { @@ -31,4 +42,11 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize); void __osGetSizes(Arena* arena, size_t* outMaxFree, size_t* outFree, size_t* outAlloc); s32 __osCheckArena(Arena* arena); +#if MM_VERSION <= N64_JP_1_1 +void *__osMallocDebug(Arena *arena, size_t size, s32 arg2, s32 arg3); +void *__osMallocRDebug(Arena *arena, size_t size, s32 arg2, s32 arg3); + +void *__osReallocDebug(Arena* arena, void* ptr, size_t newSize, const char* file, int line); +#endif + #endif diff --git a/src/boot/libc64/__osMalloc.c b/src/boot/libc64/__osMalloc.c index 0cd35afffc..005bb1b7f9 100644 --- a/src/boot/libc64/__osMalloc.c +++ b/src/boot/libc64/__osMalloc.c @@ -19,6 +19,35 @@ #define BLOCK_FREE_MAGIC (0xEF) #define BLOCK_FREE_MAGIC_32 (0xEFEFEFEF) +#if MM_VERSION >= N64_US +#define SET_DEBUG_INFO(node, f, l, a) ((void)0) + +#define CHECK_CORRECT_ARENA(node, arena) (true) + +#define CHECK_ALLOC_FAILURE(arena, ptr) (void)0 +#else +#define SET_DEBUG_INFO(node, f, l, a) \ + { \ + node->unk_10 = (f); \ + node->unk_14 = (l); \ + node->unk_18 = osGetThreadId(NULL); \ + node->unk_1C = (a); \ + node->unk_20 = osGetTime(); \ + } (void) 0 + +#define CHECK_CORRECT_ARENA(node, arena) ((node)->unk_1C == (arena)) + +s32 D_800984A0_unknown = 0; + +#define CHECK_ALLOC_FAILURE(arena, ptr) \ + do { \ + if ((ptr) == NULL) { \ + D_800984A0_unknown++; \ + (arena)->unk20++; \ + } \ + } while (0) +#endif + OSMesg sArenaLockMsg[1]; void __osMallocAddHeap(Arena* arena, void* heap, size_t size); @@ -127,6 +156,105 @@ u8 __osMallocIsInitialized(Arena* arena) { return arena->isInit; } +#if MM_VERSION <= N64_JP_1_1 +void *__osMallocDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { + ArenaNode *iter; + ArenaNode *newNode; + void *alloc = NULL; + + ArenaImpl_Lock(arena); + + size = ALIGN16(size); + + for (iter = arena->head; iter != NULL; iter = iter->next) { + if (iter->isFree && (iter->size >= size)) { + size_t blockSize = ALIGN16(size) + sizeof(ArenaNode); + + if (blockSize < iter->size) { + ArenaNode* next; + + newNode = (ArenaNode*)((uintptr_t)iter + blockSize); + newNode->next = iter->next; + newNode->prev = iter; + newNode->size = iter->size - blockSize; + newNode->isFree = true; + newNode->magic = NODE_MAGIC; + + iter->next = newNode; + iter->size = size; + + next = newNode->next; + if (next != NULL) { + next->prev = newNode; + } + } + + iter->isFree = false; + + SET_DEBUG_INFO(iter, arg2, arg3, arena); + + alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); + break; + } + } + + CHECK_ALLOC_FAILURE(arena, alloc); + + ArenaImpl_Unlock(arena); + + return alloc; +} + +void *__osMallocRDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { + ArenaNode *iter; + ArenaNode *newNode; + size_t blockSize; + void *alloc = NULL; + + size = ALIGN16(size); + + ArenaImpl_Lock(arena); + + for (iter = ArenaImpl_GetLastBlock(arena); iter != NULL; iter = iter->prev) { + if (iter->isFree && (iter->size >= size)) { + blockSize = ALIGN16(size) + sizeof(ArenaNode); + + if (blockSize < iter->size) { + ArenaNode *next; + + newNode = (ArenaNode*)(((uintptr_t)iter + iter->size) - size); + newNode->next = iter->next; + newNode->prev = iter; + newNode->size = size; + newNode->magic = NODE_MAGIC; + + iter->next = newNode; + iter->size -= blockSize; + + next = newNode->next; + if (next != NULL) { + next->prev = newNode; + } + iter = newNode; + } + + iter->isFree = false; + + SET_DEBUG_INFO(iter, arg2, arg3, arena); + + alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); + break; + } + } + + CHECK_ALLOC_FAILURE(arena, alloc); + + ArenaImpl_Unlock(arena); + + return alloc; +} +#endif + /** * Allocates at least \p size bytes of memory using the given \p arena. * The block of memory will be allocated at the start of the first sufficiently large free block. @@ -155,7 +283,7 @@ void* __osMalloc(Arena* arena, size_t size) { // Iterate over the arena looking for a big enough space of memory. while (iter != NULL) { - if (iter->isFree && iter->size >= size) { + if (iter->isFree && (iter->size >= size)) { size_t blockSize = ALIGN16(size) + sizeof(ArenaNode); // If the block is larger than the requested size, then split it and just use the required size of the @@ -180,6 +308,9 @@ void* __osMalloc(Arena* arena, size_t size) { } iter->isFree = false; + + SET_DEBUG_INFO(iter, 0, 0, arena); + alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); break; } @@ -187,6 +318,8 @@ void* __osMalloc(Arena* arena, size_t size) { iter = iter->next; } + CHECK_ALLOC_FAILURE(arena, alloc); + ArenaImpl_Unlock(arena); return alloc; @@ -245,12 +378,17 @@ void* __osMallocR(Arena* arena, size_t size) { } iter->isFree = false; + + SET_DEBUG_INFO(iter, 0, 0, arena); + alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); break; } iter = iter->prev; } + CHECK_ALLOC_FAILURE(arena, alloc); + ArenaImpl_Unlock(arena); return alloc; @@ -275,16 +413,25 @@ void __osFree(Arena* arena, void* ptr) { ArenaImpl_Lock(arena); + // __osFree:Unauthorized release(%08x)\n + (void) "__osFree:不正解放(%08x)\n"; + // __osFree:Double release(%08x)\n + (void) "__osFree:二重解放(%08x)\n"; + // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n + (void) "__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; + node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree) { + if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree && CHECK_CORRECT_ARENA(node, arena)) { next = node->next; prev = node->prev; node->isFree = true; + SET_DEBUG_INFO(node, 0, 0, arena); + // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the // two nodes into one. - if ((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size && next->isFree) { + if (((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size) && next->isFree) { ArenaNode* newNext = next->next; if (newNext != NULL) { @@ -312,6 +459,62 @@ void __osFree(Arena* arena, void* ptr) { ArenaImpl_Unlock(arena); } +// TODO +#if MM_VERSION <= N64_JP_1_1 +void __osFreeDebug(Arena* arena, void* ptr, s32 arg2, s32 arg3) { + ArenaNode* node; + ArenaNode* next; + ArenaNode* prev; + + ArenaImpl_Lock(arena); + + // __osFree:Unauthorized release(%08x)\n + (void) "__osFree:不正解放(%08x)\n"; + // __osFree:Double release(%08x)\n + (void) "__osFree:二重解放(%08x)\n"; + // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n + (void) "__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; + + node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); + + if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree && CHECK_CORRECT_ARENA(node, arena)) { + next = node->next; + prev = node->prev; + node->isFree = true; + + SET_DEBUG_INFO(node, arg2, arg3, arena); + + // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the + // two nodes into one. + if (((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size) && next->isFree) { + ArenaNode* newNext = next->next; + + if (newNext != NULL) { + newNext->prev = node; + } + + node->size += next->size + sizeof(ArenaNode); + + node->next = newNext; + next = newNext; + } + + // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge + // the two nodes into one. + if ((prev != NULL) && prev->isFree && ((uintptr_t)node == (uintptr_t)prev + sizeof(ArenaNode) + prev->size)) { + if (next != NULL) { + next->prev = prev; + } + + prev->next = next; + prev->size += node->size + sizeof(ArenaNode); + } + } + + ArenaImpl_Unlock(arena); +} +#endif + /** * Reallocates the pointer \p ptr. * \p ptr must be either a pointer previously allocated by `__osMalloc`, `__osMallocR` or `__osRealloc` and @@ -354,18 +557,18 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { newSize = ALIGN16(newSize); - // Only reallocate the memory if the new size isn't smaller than the actual node size - if ((newSize != node->size) && (node->size < newSize)) { + if (newSize == node->size) { + // Do nothing + } else if (node->size < newSize) { ArenaNode* next = node->next; diff = newSize - node->size; // Checks if the next node is contiguous to the current allocated node and it has enough space to fit the // new requested size - if (((uintptr_t)next == (uintptr_t)node + node->size + sizeof(ArenaNode)) && (next->isFree) && - (next->size >= diff)) { + if (((uintptr_t)next == (uintptr_t)node + node->size + sizeof(ArenaNode)) && next->isFree && (next->size >= diff)) { ArenaNode* next2 = next->next; - next->size = (next->size - diff); + next->size = next->size - diff; if (next2 != NULL) { // Update the previous element of the linked list next2->prev = (void*)((uintptr_t)next + diff); @@ -384,14 +587,24 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { } ptr = newPtr; } + } else if (newSize < node->size) { + } } + CHECK_ALLOC_FAILURE(arena, ptr); + ArenaImpl_Unlock(arena); return ptr; } +#if MM_VERSION <= N64_JP_1_1 +void *__osReallocDebug(Arena* arena, void* ptr, size_t newSize, const char* file, int line) { + return __osRealloc(arena, ptr, newSize); +} +#endif + /** * Gets the size of the largest free block, the total free space and the total allocated space. * @@ -458,3 +671,9 @@ s32 __osCheckArena(Arena* arena) { return err; } + +#if MM_VERSION <= N64_JP_1_1 +u8 ArenaImpl_GetAllocFailures(Arena* arena) { + return arena->unk20; +} +#endif diff --git a/src/code/gamealloc.c b/src/code/gamealloc.c index 58894324b0..06bd527202 100644 --- a/src/code/gamealloc.c +++ b/src/code/gamealloc.c @@ -5,7 +5,10 @@ void GameAlloc_Log(GameAlloc* this) { GameAllocEntry* iter = this->base.next; + (void)"this = %08x\n"; + while (iter != &this->base) { + (void)"ptr = %08x size = %d\n"; iter = iter->next; } } From 71533cf8ca63469367c8a834fd2633489bc8667b Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Mon, 25 Aug 2025 17:28:08 -0400 Subject: [PATCH 2/5] some names --- include/libc64/os_malloc.h | 25 +++++++++------- src/boot/libc64/__osMalloc.c | 41 ++++++++++++++------------- tools/disasm/n64-jp-1.1/variables.txt | 3 +- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/include/libc64/os_malloc.h b/include/libc64/os_malloc.h index 30b54cf270..575529e1a7 100644 --- a/include/libc64/os_malloc.h +++ b/include/libc64/os_malloc.h @@ -7,6 +7,8 @@ #include "unk.h" #include "versions.h" +struct Arena; + typedef struct ArenaNode { /* 0x0 */ s16 magic; // Should always be 0x7373 /* 0x2 */ s16 isFree; @@ -14,20 +16,20 @@ typedef struct ArenaNode { /* 0x8 */ struct ArenaNode* next; /* 0xC */ struct ArenaNode* prev; #if MM_VERSION <= N64_JP_1_1 - /* 0x10 */ s32 unk_10; - /* 0x14 */ s32 unk_14; - /* 0x18 */ OSId unk_18; - /* 0x1C */ void *unk_1C; - /* 0x20 */ OSTime unk_20; + /* 0x10 */ const char* filename; + /* 0x14 */ int line; + /* 0x18 */ OSId threadId; + /* 0x1C */ struct Arena *arena; + /* 0x20 */ OSTime time; /* 0x28 */ UNK_TYPE1 unk_28[0x8]; #endif -} ArenaNode; // size = 0x10 +} ArenaNode; // size = 0x10 N64 US, size = 0x30 N64 JP 1.1 typedef struct Arena { /* 0x00 */ ArenaNode* head; /* 0x04 */ void* start; /* 0x08 */ OSMesgQueue lock; - /* 0x20 */ u8 unk20; + /* 0x20 */ u8 allocFailures; /* 0x21 */ u8 isInit; /* 0x22 */ u8 flag; } Arena; // size = 0x24 @@ -43,10 +45,13 @@ void __osGetSizes(Arena* arena, size_t* outMaxFree, size_t* outFree, size_t* out s32 __osCheckArena(Arena* arena); #if MM_VERSION <= N64_JP_1_1 -void *__osMallocDebug(Arena *arena, size_t size, s32 arg2, s32 arg3); -void *__osMallocRDebug(Arena *arena, size_t size, s32 arg2, s32 arg3); - +void *__osMallocDebug(Arena *arena, size_t size, const char* file, int line); +void *__osMallocRDebug(Arena *arena, size_t size, const char* file, int line); +void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line); void *__osReallocDebug(Arena* arena, void* ptr, size_t newSize, const char* file, int line); +u8 ArenaImpl_GetAllocFailures(Arena* arena); + +extern s32 gTotalAllocFailures; #endif #endif diff --git a/src/boot/libc64/__osMalloc.c b/src/boot/libc64/__osMalloc.c index 005bb1b7f9..7705368ee3 100644 --- a/src/boot/libc64/__osMalloc.c +++ b/src/boot/libc64/__osMalloc.c @@ -28,22 +28,22 @@ #else #define SET_DEBUG_INFO(node, f, l, a) \ { \ - node->unk_10 = (f); \ - node->unk_14 = (l); \ - node->unk_18 = osGetThreadId(NULL); \ - node->unk_1C = (a); \ - node->unk_20 = osGetTime(); \ + node->filename = (f); \ + node->line = (l); \ + node->threadId = osGetThreadId(NULL); \ + node->arena = (a); \ + node->time = osGetTime(); \ } (void) 0 -#define CHECK_CORRECT_ARENA(node, arena) ((node)->unk_1C == (arena)) +#define CHECK_CORRECT_ARENA(node, arena) ((node)->arena == (arena)) -s32 D_800984A0_unknown = 0; +s32 gTotalAllocFailures = 0; // "Arena_failcnt" #define CHECK_ALLOC_FAILURE(arena, ptr) \ do { \ if ((ptr) == NULL) { \ - D_800984A0_unknown++; \ - (arena)->unk20++; \ + gTotalAllocFailures++; \ + (arena)->allocFailures++; \ } \ } while (0) #endif @@ -157,7 +157,7 @@ u8 __osMallocIsInitialized(Arena* arena) { } #if MM_VERSION <= N64_JP_1_1 -void *__osMallocDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { +void *__osMallocDebug(Arena *arena, size_t size, const char* file, int line) { ArenaNode *iter; ArenaNode *newNode; void *alloc = NULL; @@ -191,7 +191,7 @@ void *__osMallocDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { iter->isFree = false; - SET_DEBUG_INFO(iter, arg2, arg3, arena); + SET_DEBUG_INFO(iter, file, line, arena); alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); break; @@ -204,8 +204,10 @@ void *__osMallocDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { return alloc; } +#endif -void *__osMallocRDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { +#if MM_VERSION <= N64_JP_1_1 +void *__osMallocRDebug(Arena *arena, size_t size, const char* file, int line) { ArenaNode *iter; ArenaNode *newNode; size_t blockSize; @@ -240,7 +242,7 @@ void *__osMallocRDebug(Arena *arena, size_t size, s32 arg2, s32 arg3) { iter->isFree = false; - SET_DEBUG_INFO(iter, arg2, arg3, arena); + SET_DEBUG_INFO(iter, file, line, arena); alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); break; @@ -309,7 +311,7 @@ void* __osMalloc(Arena* arena, size_t size) { iter->isFree = false; - SET_DEBUG_INFO(iter, 0, 0, arena); + SET_DEBUG_INFO(iter, NULL, 0, arena); alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); break; @@ -379,7 +381,7 @@ void* __osMallocR(Arena* arena, size_t size) { iter->isFree = false; - SET_DEBUG_INFO(iter, 0, 0, arena); + SET_DEBUG_INFO(iter, NULL, 0, arena); alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); break; @@ -427,7 +429,7 @@ void __osFree(Arena* arena, void* ptr) { prev = node->prev; node->isFree = true; - SET_DEBUG_INFO(node, 0, 0, arena); + SET_DEBUG_INFO(node, NULL, 0, arena); // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the // two nodes into one. @@ -459,9 +461,8 @@ void __osFree(Arena* arena, void* ptr) { ArenaImpl_Unlock(arena); } -// TODO #if MM_VERSION <= N64_JP_1_1 -void __osFreeDebug(Arena* arena, void* ptr, s32 arg2, s32 arg3) { +void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) { ArenaNode* node; ArenaNode* next; ArenaNode* prev; @@ -482,7 +483,7 @@ void __osFreeDebug(Arena* arena, void* ptr, s32 arg2, s32 arg3) { prev = node->prev; node->isFree = true; - SET_DEBUG_INFO(node, arg2, arg3, arena); + SET_DEBUG_INFO(node, file, line, arena); // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the // two nodes into one. @@ -674,6 +675,6 @@ s32 __osCheckArena(Arena* arena) { #if MM_VERSION <= N64_JP_1_1 u8 ArenaImpl_GetAllocFailures(Arena* arena) { - return arena->unk20; + return arena->allocFailures; } #endif diff --git a/tools/disasm/n64-jp-1.1/variables.txt b/tools/disasm/n64-jp-1.1/variables.txt index 7ae8402e4c..e02197fde7 100644 --- a/tools/disasm/n64-jp-1.1/variables.txt +++ b/tools/disasm/n64-jp-1.1/variables.txt @@ -40,8 +40,7 @@ qNaN0x10000 = 0x80098484; // type:f32 size:0x4 sNaN0x3FFFFF = 0x80098488; // size:0x4 D_8009848C_unknown = 0x8009848C; sRandInt = 0x80098490; // size:0x4 -D_80098494_unknown = 0x80098494; -D_800984A0_unknown = 0x800984A0; +gTotalAllocFailures = 0x800984A0; // size:0x4 osViModeNtscHpf1 = 0x800984B0; // size:0x50 osViModePalLan1 = 0x80098500; // size:0x50 D_80098550_unknown = 0x80098550; // type:s16 From 9baafcb26d6e1ca5ccb509834f6c2f78f75c1d12 Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Tue, 9 Dec 2025 10:25:26 -0300 Subject: [PATCH 3/5] format --- src/boot/libc64/__osMalloc.c | 63 +++++++++++++++++++----------------- src/code/gamealloc.c | 5 +++ 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/boot/libc64/__osMalloc.c b/src/boot/libc64/__osMalloc.c index 7705368ee3..f416da950e 100644 --- a/src/boot/libc64/__osMalloc.c +++ b/src/boot/libc64/__osMalloc.c @@ -26,25 +26,26 @@ #define CHECK_ALLOC_FAILURE(arena, ptr) (void)0 #else -#define SET_DEBUG_INFO(node, f, l, a) \ - { \ - node->filename = (f); \ - node->line = (l); \ +#define SET_DEBUG_INFO(node, f, l, a) \ + { \ + node->filename = (f); \ + node->line = (l); \ node->threadId = osGetThreadId(NULL); \ - node->arena = (a); \ - node->time = osGetTime(); \ - } (void) 0 + node->arena = (a); \ + node->time = osGetTime(); \ + } \ + (void)0 #define CHECK_CORRECT_ARENA(node, arena) ((node)->arena == (arena)) s32 gTotalAllocFailures = 0; // "Arena_failcnt" #define CHECK_ALLOC_FAILURE(arena, ptr) \ - do { \ - if ((ptr) == NULL) { \ - gTotalAllocFailures++; \ - (arena)->allocFailures++; \ - } \ + do { \ + if ((ptr) == NULL) { \ + gTotalAllocFailures++; \ + (arena)->allocFailures++; \ + } \ } while (0) #endif @@ -157,10 +158,10 @@ u8 __osMallocIsInitialized(Arena* arena) { } #if MM_VERSION <= N64_JP_1_1 -void *__osMallocDebug(Arena *arena, size_t size, const char* file, int line) { - ArenaNode *iter; - ArenaNode *newNode; - void *alloc = NULL; +void* __osMallocDebug(Arena* arena, size_t size, const char* file, int line) { + ArenaNode* iter; + ArenaNode* newNode; + void* alloc = NULL; ArenaImpl_Lock(arena); @@ -207,11 +208,11 @@ void *__osMallocDebug(Arena *arena, size_t size, const char* file, int line) { #endif #if MM_VERSION <= N64_JP_1_1 -void *__osMallocRDebug(Arena *arena, size_t size, const char* file, int line) { - ArenaNode *iter; - ArenaNode *newNode; +void* __osMallocRDebug(Arena* arena, size_t size, const char* file, int line) { + ArenaNode* iter; + ArenaNode* newNode; size_t blockSize; - void *alloc = NULL; + void* alloc = NULL; size = ALIGN16(size); @@ -222,7 +223,7 @@ void *__osMallocRDebug(Arena *arena, size_t size, const char* file, int line) { blockSize = ALIGN16(size) + sizeof(ArenaNode); if (blockSize < iter->size) { - ArenaNode *next; + ArenaNode* next; newNode = (ArenaNode*)(((uintptr_t)iter + iter->size) - size); newNode->next = iter->next; @@ -415,12 +416,14 @@ void __osFree(Arena* arena, void* ptr) { ArenaImpl_Lock(arena); +#if MM_VERSION <= N64_JP_1_1 // __osFree:Unauthorized release(%08x)\n - (void) "__osFree:不正解放(%08x)\n"; + (void)"__osFree:不正解放(%08x)\n"; // __osFree:Double release(%08x)\n - (void) "__osFree:二重解放(%08x)\n"; + (void)"__osFree:二重解放(%08x)\n"; // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n - (void) "__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; + (void)"__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; +#endif node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); @@ -470,11 +473,11 @@ void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) { ArenaImpl_Lock(arena); // __osFree:Unauthorized release(%08x)\n - (void) "__osFree:不正解放(%08x)\n"; + (void)"__osFree:不正解放(%08x)\n"; // __osFree:Double release(%08x)\n - (void) "__osFree:二重解放(%08x)\n"; + (void)"__osFree:二重解放(%08x)\n"; // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n - (void) "__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; + (void)"__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); @@ -566,7 +569,8 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { diff = newSize - node->size; // Checks if the next node is contiguous to the current allocated node and it has enough space to fit the // new requested size - if (((uintptr_t)next == (uintptr_t)node + node->size + sizeof(ArenaNode)) && next->isFree && (next->size >= diff)) { + if (((uintptr_t)next == (uintptr_t)node + node->size + sizeof(ArenaNode)) && next->isFree && + (next->size >= diff)) { ArenaNode* next2 = next->next; next->size = next->size - diff; @@ -589,7 +593,6 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { ptr = newPtr; } } else if (newSize < node->size) { - } } @@ -601,7 +604,7 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { } #if MM_VERSION <= N64_JP_1_1 -void *__osReallocDebug(Arena* arena, void* ptr, size_t newSize, const char* file, int line) { +void* __osReallocDebug(Arena* arena, void* ptr, size_t newSize, const char* file, int line) { return __osRealloc(arena, ptr, newSize); } #endif diff --git a/src/code/gamealloc.c b/src/code/gamealloc.c index 06bd527202..e9be6beb06 100644 --- a/src/code/gamealloc.c +++ b/src/code/gamealloc.c @@ -5,10 +5,15 @@ void GameAlloc_Log(GameAlloc* this) { GameAllocEntry* iter = this->base.next; +#if MM_VERSION <= N64_JP_1_1 (void)"this = %08x\n"; +#endif while (iter != &this->base) { +#if MM_VERSION <= N64_JP_1_1 (void)"ptr = %08x size = %d\n"; +#endif + iter = iter->next; } } From 138d7e6ed2a5ac04a9c2c77476643f9e85b7f2ee Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Sat, 13 Dec 2025 17:41:24 -0300 Subject: [PATCH 4/5] Breakup osFree checks and move strings around --- src/boot/libc64/__osMalloc.c | 188 ++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 78 deletions(-) diff --git a/src/boot/libc64/__osMalloc.c b/src/boot/libc64/__osMalloc.c index f416da950e..7dd9ad1b2a 100644 --- a/src/boot/libc64/__osMalloc.c +++ b/src/boot/libc64/__osMalloc.c @@ -416,51 +416,69 @@ void __osFree(Arena* arena, void* ptr) { ArenaImpl_Lock(arena); -#if MM_VERSION <= N64_JP_1_1 - // __osFree:Unauthorized release(%08x)\n - (void)"__osFree:不正解放(%08x)\n"; - // __osFree:Double release(%08x)\n - (void)"__osFree:二重解放(%08x)\n"; - // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n - (void)"__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; -#endif + if (ptr == NULL) { + goto cleanup; + } node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree && CHECK_CORRECT_ARENA(node, arena)) { - next = node->next; - prev = node->prev; - node->isFree = true; - - SET_DEBUG_INFO(node, NULL, 0, arena); - - // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the - // two nodes into one. - if (((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size) && next->isFree) { - ArenaNode* newNext = next->next; - - if (newNext != NULL) { - newNext->prev = node; - } - - node->size += next->size + sizeof(ArenaNode); - - node->next = newNext; - next = newNext; - } - - // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge - // the two nodes into one. - if ((prev != NULL) && prev->isFree && ((uintptr_t)node == (uintptr_t)prev + sizeof(ArenaNode) + prev->size)) { - if (next != NULL) { - next->prev = prev; - } - - prev->next = next; - prev->size += node->size + sizeof(ArenaNode); - } + if (node->magic != NODE_MAGIC) { +#if MM_VERSION < N64_US + // __osFree:Unauthorized release(%08x)\n + (void)"__osFree:不正解放(%08x)\n"; +#endif + goto cleanup; } + if (node->isFree) { +#if MM_VERSION < N64_US + // __osFree:Double release(%08x)\n + (void)"__osFree:二重解放(%08x)\n"; +#endif + goto cleanup; + } + + if (!CHECK_CORRECT_ARENA(node, arena)) { +#if MM_VERSION < N64_US + // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n + (void)"__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; +#endif + goto cleanup; + } + + next = node->next; + prev = node->prev; + node->isFree = true; + + SET_DEBUG_INFO(node, NULL, 0, arena); + + // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the + // two nodes into one. + if (((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size) && next->isFree) { + ArenaNode* newNext = next->next; + + if (newNext != NULL) { + newNext->prev = node; + } + + node->size += next->size + sizeof(ArenaNode); + + node->next = newNext; + next = newNext; + } + + // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge + // the two nodes into one. + if ((prev != NULL) && prev->isFree && ((uintptr_t)node == (uintptr_t)prev + sizeof(ArenaNode) + prev->size)) { + if (next != NULL) { + next->prev = prev; + } + + prev->next = next; + prev->size += node->size + sizeof(ArenaNode); + } + +cleanup: ArenaImpl_Unlock(arena); } @@ -472,49 +490,63 @@ void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) { ArenaImpl_Lock(arena); - // __osFree:Unauthorized release(%08x)\n - (void)"__osFree:不正解放(%08x)\n"; - // __osFree:Double release(%08x)\n - (void)"__osFree:二重解放(%08x)\n"; - // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n - (void)"__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; + if (ptr == NULL) { + goto cleanup; + } node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree && CHECK_CORRECT_ARENA(node, arena)) { - next = node->next; - prev = node->prev; - node->isFree = true; - - SET_DEBUG_INFO(node, file, line, arena); - - // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the - // two nodes into one. - if (((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size) && next->isFree) { - ArenaNode* newNext = next->next; - - if (newNext != NULL) { - newNext->prev = node; - } - - node->size += next->size + sizeof(ArenaNode); - - node->next = newNext; - next = newNext; - } - - // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge - // the two nodes into one. - if ((prev != NULL) && prev->isFree && ((uintptr_t)node == (uintptr_t)prev + sizeof(ArenaNode) + prev->size)) { - if (next != NULL) { - next->prev = prev; - } - - prev->next = next; - prev->size += node->size + sizeof(ArenaNode); - } + if (node->magic != NODE_MAGIC) { + // __osFree:Unauthorized release(%08x)\n + (void)"__osFree:不正解放(%08x)\n"; + goto cleanup; } + if (node->isFree) { + // __osFree:Double release(%08x)\n + (void)"__osFree:二重解放(%08x)\n"; + goto cleanup; + } + + if (!CHECK_CORRECT_ARENA(node, arena)) { + // __osFree:arena(%08x) and __osMallocのarena(%08x) do not match\n + (void)"__osFree:arena(%08x)が__osMallocのarena(%08x)と一致しない\n"; + goto cleanup; + } + + next = node->next; + prev = node->prev; + node->isFree = true; + + SET_DEBUG_INFO(node, file, line, arena); + + // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the + // two nodes into one. + if (((uintptr_t)next == (uintptr_t)node + sizeof(ArenaNode) + node->size) && next->isFree) { + ArenaNode* newNext = next->next; + + if (newNext != NULL) { + newNext->prev = node; + } + + node->size += next->size + sizeof(ArenaNode); + + node->next = newNext; + next = newNext; + } + + // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge + // the two nodes into one. + if ((prev != NULL) && prev->isFree && ((uintptr_t)node == (uintptr_t)prev + sizeof(ArenaNode) + prev->size)) { + if (next != NULL) { + next->prev = prev; + } + + prev->next = next; + prev->size += node->size + sizeof(ArenaNode); + } + +cleanup: ArenaImpl_Unlock(arena); } #endif From 13288384ca6b632116e3fe1e2b55381a575aa85c Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Sat, 13 Dec 2025 17:46:27 -0300 Subject: [PATCH 5/5] misc changes --- src/boot/libc64/__osMalloc.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/boot/libc64/__osMalloc.c b/src/boot/libc64/__osMalloc.c index 7dd9ad1b2a..f22f143e9f 100644 --- a/src/boot/libc64/__osMalloc.c +++ b/src/boot/libc64/__osMalloc.c @@ -19,6 +19,8 @@ #define BLOCK_FREE_MAGIC (0xEF) #define BLOCK_FREE_MAGIC_32 (0xEFEFEFEF) +#define NODE_IS_VALID(node) ((node)->magic == NODE_MAGIC) + #if MM_VERSION >= N64_US #define SET_DEBUG_INFO(node, f, l, a) ((void)0) @@ -157,7 +159,7 @@ u8 __osMallocIsInitialized(Arena* arena) { return arena->isInit; } -#if MM_VERSION <= N64_JP_1_1 +#if MM_VERSION < N64_US void* __osMallocDebug(Arena* arena, size_t size, const char* file, int line) { ArenaNode* iter; ArenaNode* newNode; @@ -207,7 +209,7 @@ void* __osMallocDebug(Arena* arena, size_t size, const char* file, int line) { } #endif -#if MM_VERSION <= N64_JP_1_1 +#if MM_VERSION < N64_US void* __osMallocRDebug(Arena* arena, size_t size, const char* file, int line) { ArenaNode* iter; ArenaNode* newNode; @@ -422,7 +424,7 @@ void __osFree(Arena* arena, void* ptr) { node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - if (node->magic != NODE_MAGIC) { + if (!NODE_IS_VALID(node)) { #if MM_VERSION < N64_US // __osFree:Unauthorized release(%08x)\n (void)"__osFree:不正解放(%08x)\n"; @@ -482,7 +484,7 @@ cleanup: ArenaImpl_Unlock(arena); } -#if MM_VERSION <= N64_JP_1_1 +#if MM_VERSION < N64_US void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) { ArenaNode* node; ArenaNode* next; @@ -496,7 +498,7 @@ void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) { node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - if (node->magic != NODE_MAGIC) { + if (!NODE_IS_VALID(node)) { // __osFree:Unauthorized release(%08x)\n (void)"__osFree:不正解放(%08x)\n"; goto cleanup; @@ -635,7 +637,7 @@ void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { return ptr; } -#if MM_VERSION <= N64_JP_1_1 +#if MM_VERSION < N64_US void* __osReallocDebug(Arena* arena, void* ptr, size_t newSize, const char* file, int line) { return __osRealloc(arena, ptr, newSize); } @@ -691,7 +693,7 @@ s32 __osCheckArena(Arena* arena) { (void)"アリーナの内容をチェックしています... (%08x)\n"; for (iter = arena->head; iter != NULL; iter = iter->next) { - if (iter->magic != NODE_MAGIC) { + if (!NODE_IS_VALID(iter)) { // "Oops!!" (void)"おおっと!! (%08x %08x)\n"; @@ -708,7 +710,7 @@ s32 __osCheckArena(Arena* arena) { return err; } -#if MM_VERSION <= N64_JP_1_1 +#if MM_VERSION < N64_US u8 ArenaImpl_GetAllocFailures(Arena* arena) { return arena->allocFailures; }