Add debug asserts for invalid MEMPTR

Also fixed some corruptions this uncovered
This commit is contained in:
Exzap 2023-06-15 22:18:53 +02:00
parent 7886b594a2
commit 808d1bb424
13 changed files with 193 additions and 156 deletions

1
.gitignore vendored
View File

@ -38,6 +38,7 @@ bin/debugger/*
bin/sdcard/* bin/sdcard/*
bin/screenshots/* bin/screenshots/*
bin/dump/* bin/dump/*
bin/cafeLibs/*
!bin/shaderCache/info.txt !bin/shaderCache/info.txt
bin/shaderCache/* bin/shaderCache/*

View File

@ -263,4 +263,6 @@ namespace MMU
uint16 ReadMMIO_32(PAddr address); uint16 ReadMMIO_32(PAddr address);
uint16 ReadMMIO_16(PAddr address); uint16 ReadMMIO_16(PAddr address);
} }
#define MMU_IsInPPCMemorySpace(__ptr) ((const uint8*)(__ptr) >= memory_base && (const uint8*)(__ptr) < (memory_base + 0x100000000))

View File

@ -211,6 +211,7 @@ namespace coreinit
void __OSInitiateAlarm(OSAlarm_t* alarm, uint64 startTime, uint64 period, MPTR handlerFunc, bool isPeriodic) void __OSInitiateAlarm(OSAlarm_t* alarm, uint64 startTime, uint64 period, MPTR handlerFunc, bool isPeriodic)
{ {
cemu_assert_debug(MMU_IsInPPCMemorySpace(alarm));
cemu_assert_debug(__OSHasSchedulerLock()); cemu_assert_debug(__OSHasSchedulerLock());
uint64 nextTime = startTime; uint64 nextTime = startTime;

View File

@ -50,7 +50,7 @@ namespace coreinit
MEMList g_list3; MEMList g_list3;
std::array<uint32, 3> gHeapFillValues{ 0xC3C3C3C3, 0xF3F3F3F3, 0xD3D3D3D3 }; std::array<uint32, 3> gHeapFillValues{ 0xC3C3C3C3, 0xF3F3F3F3, 0xD3D3D3D3 };
OSSpinLock gHeapGlobalLock; SysAllocator<OSSpinLock> gHeapGlobalLock;
MEMHeapBase* gDefaultHeap; MEMHeapBase* gDefaultHeap;
bool MEMHeapTable_Add(MEMHeapBase* heap) bool MEMHeapTable_Add(MEMHeapBase* heap)

View File

@ -263,9 +263,7 @@ namespace coreinit
thread = (OSThread_t*)memory_getPointerFromVirtualOffset(coreinit_allocFromSysArea(sizeof(OSThread_t), 32)); thread = (OSThread_t*)memory_getPointerFromVirtualOffset(coreinit_allocFromSysArea(sizeof(OSThread_t), 32));
memset(thread, 0x00, sizeof(OSThread_t)); memset(thread, 0x00, sizeof(OSThread_t));
// init signatures // init signatures
thread->context.magic0 = OS_CONTEXT_MAGIC_0; thread->SetMagic();
thread->context.magic1 = OS_CONTEXT_MAGIC_1;
thread->magic = 'tHrD';
thread->type = threadType; thread->type = threadType;
thread->state = (entryPoint != MPTR_NULL) ? OSThread_t::THREAD_STATE::STATE_READY : OSThread_t::THREAD_STATE::STATE_NONE; thread->state = (entryPoint != MPTR_NULL) ? OSThread_t::THREAD_STATE::STATE_READY : OSThread_t::THREAD_STATE::STATE_NONE;
thread->entrypoint = _swapEndianU32(entryPoint); thread->entrypoint = _swapEndianU32(entryPoint);
@ -563,7 +561,10 @@ namespace coreinit
// adds the thread to each core's run queue if in runable state // adds the thread to each core's run queue if in runable state
void __OSAddReadyThreadToRunQueue(OSThread_t* thread) void __OSAddReadyThreadToRunQueue(OSThread_t* thread)
{ {
cemu_assert_debug(MMU_IsInPPCMemorySpace(thread));
cemu_assert_debug(thread->IsValidMagic());
cemu_assert_debug(__OSHasSchedulerLock()); cemu_assert_debug(__OSHasSchedulerLock());
if (thread->state != OSThread_t::THREAD_STATE::STATE_READY) if (thread->state != OSThread_t::THREAD_STATE::STATE_READY)
return; return;
if (thread->suspendCounter != 0) if (thread->suspendCounter != 0)
@ -703,10 +704,18 @@ namespace coreinit
} }
else if (prevAffinityMask != affinityMask) else if (prevAffinityMask != affinityMask)
{ {
__OSRemoveThreadFromRunQueues(thread); if(thread->state != OSThread_t::THREAD_STATE::STATE_NONE)
thread->attr = (thread->attr & ~7) | (affinityMask & 7); {
thread->context.setAffinity(affinityMask); __OSRemoveThreadFromRunQueues(thread);
__OSAddReadyThreadToRunQueue(thread); thread->attr = (thread->attr & ~7) | (affinityMask & 7);
thread->context.setAffinity(affinityMask);
__OSAddReadyThreadToRunQueue(thread);
}
else
{
thread->attr = (thread->attr & ~7) | (affinityMask & 7);
thread->context.setAffinity(affinityMask);
}
} }
__OSUnlockScheduler(); __OSUnlockScheduler();
return true; return true;

View File

@ -404,6 +404,18 @@ struct OSThread_t
return 0; return 0;
} }
void SetMagic()
{
context.magic0 = OS_CONTEXT_MAGIC_0;
context.magic1 = OS_CONTEXT_MAGIC_1;
magic = 'tHrD';
}
bool IsValidMagic() const
{
return magic == 'tHrD' && context.magic0 == OS_CONTEXT_MAGIC_0 && context.magic1 == OS_CONTEXT_MAGIC_1;
}
/* +0x000 */ OSContext_t context; /* +0x000 */ OSContext_t context;
/* +0x320 */ uint32be magic; // 'tHrD' /* +0x320 */ uint32be magic; // 'tHrD'
/* +0x324 */ betype<THREAD_STATE> state; /* +0x324 */ betype<THREAD_STATE> state;

View File

@ -82,7 +82,7 @@ namespace erreula
struct ErrEula_t struct ErrEula_t
{ {
coreinit::OSMutex mutex; SysAllocator<coreinit::OSMutex> mutex;
uint32 regionType; uint32 regionType;
uint32 langType; uint32 langType;
MEMPTR<coreinit::FSClient_t> fsClient; MEMPTR<coreinit::FSClient_t> fsClient;

View File

@ -23,7 +23,7 @@ memset(bossRequest, 0, sizeof(iosuBossCemuRequest_t)); \
memset(bossBufferVector, 0, sizeof(ioBufferVector_t)); \ memset(bossBufferVector, 0, sizeof(ioBufferVector_t)); \
bossBufferVector->buffer = (uint8*)bossRequest; bossBufferVector->buffer = (uint8*)bossRequest;
coreinit::OSMutex g_mutex; SysAllocator<coreinit::OSMutex> g_mutex;
sint32 g_initCounter = 0; sint32 g_initCounter = 0;
bool g_isInitialized = false; bool g_isInitialized = false;

View File

@ -54,7 +54,7 @@ namespace padscore
WPADState_t g_wpad_state = kWPADStateMaster; WPADState_t g_wpad_state = kWPADStateMaster;
struct { struct {
coreinit::OSAlarm_t alarm; SysAllocator<coreinit::OSAlarm_t> alarm;
bool kpad_initialized = false; bool kpad_initialized = false;
struct WPADData struct WPADData

View File

@ -163,7 +163,7 @@ namespace vpad
struct struct
{ {
coreinit::OSAlarm_t alarm; SysAllocator<coreinit::OSAlarm_t> alarm;
struct struct
{ {

View File

@ -37,7 +37,10 @@ public:
if (ptr == nullptr) if (ptr == nullptr)
m_value = 0; m_value = 0;
else else
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base); {
cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);
}
} }
constexpr MEMPTR(const MEMPTR& memptr) constexpr MEMPTR(const MEMPTR& memptr)
@ -63,10 +66,13 @@ public:
MEMPTR& operator=(T* ptr) MEMPTR& operator=(T* ptr)
{ {
if (ptr == nullptr) if (ptr == nullptr)
m_value = 0; m_value = 0;
else else
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base); {
cemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);
m_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);
}
return *this; return *this;
} }

View File

@ -296,6 +296,61 @@ inline unsigned char _addcarry_u64(unsigned char carry, unsigned long long a, un
#endif #endif
// asserts
inline void cemu_assert(bool _condition)
{
if ((_condition) == false)
{
DEBUG_BREAK;
}
}
#ifndef CEMU_DEBUG_ASSERT
//#define cemu_assert_debug(__cond) -> Forcing __cond not to be evaluated currently has unexpected side-effects
inline void cemu_assert_debug(bool _condition)
{
}
inline void cemu_assert_unimplemented()
{
}
inline void cemu_assert_suspicious()
{
}
inline void cemu_assert_error()
{
DEBUG_BREAK;
}
#else
inline void cemu_assert_debug(bool _condition)
{
if ((_condition) == false)
DEBUG_BREAK;
}
inline void cemu_assert_unimplemented()
{
DEBUG_BREAK;
}
inline void cemu_assert_suspicious()
{
DEBUG_BREAK;
}
inline void cemu_assert_error()
{
DEBUG_BREAK;
}
#endif
#define assert_dbg() DEBUG_BREAK // old style unconditional generic assert
// MEMPTR // MEMPTR
#include "Common/MemPtr.h" #include "Common/MemPtr.h"
@ -380,58 +435,6 @@ bool match_any_of(T1 value, T2 compareTo, Types&&... others)
#endif #endif
} }
inline void cemu_assert(bool _condition)
{
if ((_condition) == false)
{
DEBUG_BREAK;
}
}
#ifndef CEMU_DEBUG_ASSERT
//#define cemu_assert_debug(__cond) -> Forcing __cond not to be evaluated currently has unexpected side-effects
inline void cemu_assert_debug(bool _condition)
{
}
inline void cemu_assert_unimplemented()
{
}
inline void cemu_assert_suspicious()
{
}
inline void cemu_assert_error()
{
DEBUG_BREAK;
}
#else
inline void cemu_assert_debug(bool _condition)
{
if ((_condition) == false)
DEBUG_BREAK;
}
inline void cemu_assert_unimplemented()
{
DEBUG_BREAK;
}
inline void cemu_assert_suspicious()
{
DEBUG_BREAK;
}
inline void cemu_assert_error()
{
DEBUG_BREAK;
}
#endif
#define assert_dbg() DEBUG_BREAK // old style unconditional generic assert
// Some string conversion helpers because C++20 std::u8string is too cumbersome to use in practice // Some string conversion helpers because C++20 std::u8string is too cumbersome to use in practice
// mixing string types generally causes loads of issues and many of the libraries we use dont expose interfaces for u8string // mixing string types generally causes loads of issues and many of the libraries we use dont expose interfaces for u8string

View File

@ -173,100 +173,103 @@ void DebugPPCThreadsWindow::RefreshThreadList()
const int scrollPos = m_thread_list->GetScrollPos(0); const int scrollPos = m_thread_list->GetScrollPos(0);
m_thread_list->DeleteAllItems(); m_thread_list->DeleteAllItems();
__OSLockScheduler(); if(activeThreadCount > 0)
srwlock_activeThreadList.LockWrite(); {
for (sint32 i = 0; i < activeThreadCount; i++) __OSLockScheduler();
{ srwlock_activeThreadList.LockWrite();
MPTR threadItrMPTR = activeThread[i]; for (sint32 i = 0; i < activeThreadCount; i++)
OSThread_t* cafeThread = (OSThread_t*)memory_getPointerFromVirtualOffset(threadItrMPTR); {
MPTR threadItrMPTR = activeThread[i];
OSThread_t* cafeThread = (OSThread_t*)memory_getPointerFromVirtualOffset(threadItrMPTR);
char tempStr[512]; char tempStr[512];
sprintf(tempStr, "%08X", threadItrMPTR); sprintf(tempStr, "%08X", threadItrMPTR);
wxListItem item; wxListItem item;
item.SetId(i); item.SetId(i);
item.SetText(tempStr); item.SetText(tempStr);
m_thread_list->InsertItem(item); m_thread_list->InsertItem(item);
m_thread_list->SetItemData(item, (long)threadItrMPTR); m_thread_list->SetItemData(item, (long)threadItrMPTR);
// entry point // entry point
sprintf(tempStr, "%08X", _swapEndianU32(cafeThread->entrypoint)); sprintf(tempStr, "%08X", _swapEndianU32(cafeThread->entrypoint));
m_thread_list->SetItem(i, 1, tempStr); m_thread_list->SetItem(i, 1, tempStr);
// stack base (low) // stack base (low)
sprintf(tempStr, "%08X - %08X", _swapEndianU32(cafeThread->stackEnd), _swapEndianU32(cafeThread->stackBase)); sprintf(tempStr, "%08X - %08X", _swapEndianU32(cafeThread->stackEnd), _swapEndianU32(cafeThread->stackBase));
m_thread_list->SetItem(i, 2, tempStr); m_thread_list->SetItem(i, 2, tempStr);
// pc // pc
RPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(cafeThread->context.srr0); RPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(cafeThread->context.srr0);
if (symbol) if (symbol)
sprintf(tempStr, "%s (0x%08x)", (const char*)symbol->symbolName, cafeThread->context.srr0); sprintf(tempStr, "%s (0x%08x)", (const char*)symbol->symbolName, cafeThread->context.srr0);
else else
sprintf(tempStr, "%08X", cafeThread->context.srr0); sprintf(tempStr, "%08X", cafeThread->context.srr0);
m_thread_list->SetItem(i, 3, tempStr); m_thread_list->SetItem(i, 3, tempStr);
// lr // lr
sprintf(tempStr, "%08X", _swapEndianU32(cafeThread->context.lr)); sprintf(tempStr, "%08X", _swapEndianU32(cafeThread->context.lr));
m_thread_list->SetItem(i, 4, tempStr); m_thread_list->SetItem(i, 4, tempStr);
// state // state
OSThread_t::THREAD_STATE threadState = cafeThread->state; OSThread_t::THREAD_STATE threadState = cafeThread->state;
wxString threadStateStr = "UNDEFINED"; wxString threadStateStr = "UNDEFINED";
if (cafeThread->suspendCounter != 0) if (cafeThread->suspendCounter != 0)
threadStateStr = "SUSPENDED"; threadStateStr = "SUSPENDED";
else if (threadState == OSThread_t::THREAD_STATE::STATE_NONE) else if (threadState == OSThread_t::THREAD_STATE::STATE_NONE)
threadStateStr = "NONE"; threadStateStr = "NONE";
else if (threadState == OSThread_t::THREAD_STATE::STATE_READY) else if (threadState == OSThread_t::THREAD_STATE::STATE_READY)
threadStateStr = "READY"; threadStateStr = "READY";
else if (threadState == OSThread_t::THREAD_STATE::STATE_RUNNING) else if (threadState == OSThread_t::THREAD_STATE::STATE_RUNNING)
threadStateStr = "RUNNING"; threadStateStr = "RUNNING";
else if (threadState == OSThread_t::THREAD_STATE::STATE_WAITING) else if (threadState == OSThread_t::THREAD_STATE::STATE_WAITING)
threadStateStr = "WAITING"; threadStateStr = "WAITING";
else if (threadState == OSThread_t::THREAD_STATE::STATE_MORIBUND) else if (threadState == OSThread_t::THREAD_STATE::STATE_MORIBUND)
threadStateStr = "MORIBUND"; threadStateStr = "MORIBUND";
m_thread_list->SetItem(i, 5, threadStateStr); m_thread_list->SetItem(i, 5, threadStateStr);
// affinity // affinity
uint8 affinity = cafeThread->attr&7; uint8 affinity = cafeThread->attr&7;
uint8 affinityReal = cafeThread->context.affinity; uint8 affinityReal = cafeThread->context.affinity;
if(affinity != affinityReal) if(affinity != affinityReal)
sprintf(tempStr, "(!) %d%d%d real: %d%d%d", (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1, (affinityReal >> 0) & 1, (affinityReal >> 1) & 1, (affinityReal >> 2) & 1); sprintf(tempStr, "(!) %d%d%d real: %d%d%d", (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1, (affinityReal >> 0) & 1, (affinityReal >> 1) & 1, (affinityReal >> 2) & 1);
else else
sprintf(tempStr, "%d%d%d", (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1); sprintf(tempStr, "%d%d%d", (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1);
m_thread_list->SetItem(i, 6, tempStr); m_thread_list->SetItem(i, 6, tempStr);
// priority // priority
sint32 effectivePriority = cafeThread->effectivePriority; sint32 effectivePriority = cafeThread->effectivePriority;
sprintf(tempStr, "%d", effectivePriority); sprintf(tempStr, "%d", effectivePriority);
m_thread_list->SetItem(i, 7, tempStr); m_thread_list->SetItem(i, 7, tempStr);
// last awake in cycles // last awake in cycles
uint64 lastWakeUpTime = cafeThread->wakeUpTime; uint64 lastWakeUpTime = cafeThread->wakeUpTime;
sprintf(tempStr, "%" PRIu64, lastWakeUpTime); sprintf(tempStr, "%" PRIu64, lastWakeUpTime);
m_thread_list->SetItem(i, 8, tempStr); m_thread_list->SetItem(i, 8, tempStr);
// awake time in cycles // awake time in cycles
uint64 awakeTime = cafeThread->totalCycles; uint64 awakeTime = cafeThread->totalCycles;
sprintf(tempStr, "%" PRIu64, awakeTime); sprintf(tempStr, "%" PRIu64, awakeTime);
m_thread_list->SetItem(i, 9, tempStr); m_thread_list->SetItem(i, 9, tempStr);
// thread name // thread name
const char* threadName = "NULL"; const char* threadName = "NULL";
if (!cafeThread->threadName.IsNull()) if (!cafeThread->threadName.IsNull())
threadName = cafeThread->threadName.GetPtr(); threadName = cafeThread->threadName.GetPtr();
m_thread_list->SetItem(i, 10, threadName); m_thread_list->SetItem(i, 10, threadName);
// GPR // GPR
sprintf(tempStr, "r3 %08x r4 %08x r5 %08x r6 %08x r7 %08x", _r(3), _r(4), _r(5), _r(6), _r(7)); sprintf(tempStr, "r3 %08x r4 %08x r5 %08x r6 %08x r7 %08x", _r(3), _r(4), _r(5), _r(6), _r(7));
m_thread_list->SetItem(i, 11, tempStr); m_thread_list->SetItem(i, 11, tempStr);
// waiting condition / extra info // waiting condition / extra info
coreinit::OSMutex* mutex = cafeThread->waitingForMutex; coreinit::OSMutex* mutex = cafeThread->waitingForMutex;
if (mutex) if (mutex)
sprintf(tempStr, "Mutex 0x%08x (Held by thread 0x%08X Lock-Count: %d)", memory_getVirtualOffsetFromPointer(mutex), mutex->owner.GetMPTR(), (uint32)mutex->lockCount); sprintf(tempStr, "Mutex 0x%08x (Held by thread 0x%08X Lock-Count: %d)", memory_getVirtualOffsetFromPointer(mutex), mutex->owner.GetMPTR(), (uint32)mutex->lockCount);
else else
sprintf(tempStr, ""); sprintf(tempStr, "");
// OSSetThreadCancelState // OSSetThreadCancelState
if (cafeThread->requestFlags & OSThread_t::REQUEST_FLAG_CANCEL) if (cafeThread->requestFlags & OSThread_t::REQUEST_FLAG_CANCEL)
strcat(tempStr, "[Cancel requested]"); strcat(tempStr, "[Cancel requested]");
m_thread_list->SetItem(i, 12, tempStr); m_thread_list->SetItem(i, 12, tempStr);
if(selected_thread != 0 && selected_thread == (long)threadItrMPTR) if(selected_thread != 0 && selected_thread == (long)threadItrMPTR)
m_thread_list->SetItemState(i, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED); m_thread_list->SetItemState(i, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED);
} }
srwlock_activeThreadList.UnlockWrite(); srwlock_activeThreadList.UnlockWrite();
__OSUnlockScheduler(); __OSUnlockScheduler();
}
m_thread_list->SetScrollPos(0, scrollPos, true); m_thread_list->SetScrollPos(0, scrollPos, true);
} }