summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnghelo Carvajal <angheloalf95@gmail.com>2026-04-20 13:32:24 -0400
committerGitHub <noreply@github.com>2026-04-20 10:32:24 -0700
commitfa85e7cda5de980151ab71279b6a1bf2eca9b23f (patch)
tree0ac0d5119e4aec4f965f31fd1991232a3c437965
parentffc67c3e0adf8fbc81618299a68b52efe31dd08b (diff)
[n64-jp-1.1] __osMalloc.c matched (#1845)
* match osmalloc * some names * format * Breakup osFree checks and move strings around * misc changes
-rw-r--r--include/libc64/os_malloc.h27
-rw-r--r--src/boot/libc64/__osMalloc.c313
-rw-r--r--src/code/gamealloc.c8
-rw-r--r--tools/disasm/n64-jp-1.1/variables.txt3
4 files changed, 319 insertions, 32 deletions
diff --git a/include/libc64/os_malloc.h b/include/libc64/os_malloc.h
index 78cbc233f..575529e1a 100644
--- a/include/libc64/os_malloc.h
+++ b/include/libc64/os_malloc.h
@@ -4,19 +4,32 @@
#include "ultra64.h"
#include "stddef.h"
+#include "unk.h"
+#include "versions.h"
+
+struct Arena;
+
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;
-} ArenaNode; // size = 0x10
+ #if MM_VERSION <= N64_JP_1_1
+ /* 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 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
@@ -31,4 +44,14 @@ 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, 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 0cd35afff..f22f143e9 100644
--- a/src/boot/libc64/__osMalloc.c
+++ b/src/boot/libc64/__osMalloc.c
@@ -19,6 +19,38 @@
#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)
+
+#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->filename = (f); \
+ node->line = (l); \
+ node->threadId = osGetThreadId(NULL); \
+ 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++; \
+ } \
+ } while (0)
+#endif
+
OSMesg sArenaLockMsg[1];
void __osMallocAddHeap(Arena* arena, void* heap, size_t size);
@@ -127,6 +159,107 @@ u8 __osMallocIsInitialized(Arena* arena) {
return arena->isInit;
}
+#if MM_VERSION < N64_US
+void* __osMallocDebug(Arena* arena, size_t size, const char* file, int line) {
+ 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, file, line, arena);
+
+ alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode));
+ break;
+ }
+ }
+
+ CHECK_ALLOC_FAILURE(arena, alloc);
+
+ ArenaImpl_Unlock(arena);
+
+ return alloc;
+}
+#endif
+
+#if MM_VERSION < N64_US
+void* __osMallocRDebug(Arena* arena, size_t size, const char* file, int line) {
+ 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, file, line, 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 +288,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 +313,9 @@ void* __osMalloc(Arena* arena, size_t size) {
}
iter->isFree = false;
+
+ SET_DEBUG_INFO(iter, NULL, 0, arena);
+
alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode));
break;
}
@@ -187,6 +323,8 @@ void* __osMalloc(Arena* arena, size_t size) {
iter = iter->next;
}
+ CHECK_ALLOC_FAILURE(arena, alloc);
+
ArenaImpl_Unlock(arena);
return alloc;
@@ -245,12 +383,17 @@ void* __osMallocR(Arena* arena, size_t size) {
}
iter->isFree = false;
+
+ SET_DEBUG_INFO(iter, NULL, 0, arena);
+
alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode));
break;
}
iter = iter->prev;
}
+ CHECK_ALLOC_FAILURE(arena, alloc);
+
ArenaImpl_Unlock(arena);
return alloc;
@@ -275,42 +418,140 @@ void __osFree(Arena* arena, void* ptr) {
ArenaImpl_Lock(arena);
+ if (ptr == NULL) {
+ goto cleanup;
+ }
+
node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode));
- if ((ptr != NULL) && (node->magic == NODE_MAGIC) && !node->isFree) {
- next = node->next;
- prev = node->prev;
- node->isFree = true;
+ if (!NODE_IS_VALID(node)) {
+#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;
+ }
- // 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 (!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;
+ }
- if (newNext != NULL) {
- newNext->prev = node;
- }
+ next = node->next;
+ prev = node->prev;
+ node->isFree = true;
- node->size += next->size + sizeof(ArenaNode);
+ SET_DEBUG_INFO(node, NULL, 0, arena);
- node->next = newNext;
- next = newNext;
+ // 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;
}
- // 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;
- }
+ 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);
+ prev->next = next;
+ prev->size += node->size + sizeof(ArenaNode);
+ }
+
+cleanup:
+ ArenaImpl_Unlock(arena);
+}
+
+#if MM_VERSION < N64_US
+void __osFreeDebug(Arena* arena, void* ptr, const char* file, int line) {
+ ArenaNode* node;
+ ArenaNode* next;
+ ArenaNode* prev;
+
+ ArenaImpl_Lock(arena);
+
+ if (ptr == NULL) {
+ goto cleanup;
+ }
+
+ node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode));
+
+ if (!NODE_IS_VALID(node)) {
+ // __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
/**
* Reallocates the pointer \p ptr.
@@ -354,18 +595,19 @@ 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) &&
+ 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 +626,23 @@ 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_US
+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.
*
@@ -442,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";
@@ -458,3 +709,9 @@ s32 __osCheckArena(Arena* arena) {
return err;
}
+
+#if MM_VERSION < N64_US
+u8 ArenaImpl_GetAllocFailures(Arena* arena) {
+ return arena->allocFailures;
+}
+#endif
diff --git a/src/code/gamealloc.c b/src/code/gamealloc.c
index 58894324b..e9be6beb0 100644
--- a/src/code/gamealloc.c
+++ b/src/code/gamealloc.c
@@ -5,7 +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;
}
}
diff --git a/tools/disasm/n64-jp-1.1/variables.txt b/tools/disasm/n64-jp-1.1/variables.txt
index d2600f527..aba1d6964 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