Post Reply 
 
Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Darkstalkers Chronicle: The Chaos Tower
01-06-2014, 01:45 AM
Post: #10
RE: Darkstalkers Chronicle The Chaos Tower
It's hitting this:

Code:
    T *GetFast(SceUID handle)
    {
        const SceUID realHandle = handle - handleOffset;
        _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]); <-- BOOM
        return static_cast<T *>(pool[realHandle]);
    }

This means one of:

* The game is deleting a thread in a way that doesn't remove it from the thread queues.
* The game is writing somewhere that is corrupting PPSSPP's memory.
* A buffer overflow in PPSSPP is overwriting PPSSPP's memory.

But, your crash seems to indicate a crazy value of priority, which suggests one of the latter...

In sceKernelThread.cpp, find:

Code:
void __KernelChangeReadyState(Thread *thread, SceUID threadID, bool ready)
{
    // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc.
    _dbg_assert_msg_(SCEKERNEL, thread->GetUID() == threadID, "Incorrect threadID");
    int prio = thread->nt.currentPriority;

    if (thread->isReady())
    {
        if (!ready)
            threadReadyQueue.remove(prio, threadID);
    }
    else if (ready)
    {
        if (thread->isRunning())
            threadReadyQueue.push_front(prio, threadID);
        else
            threadReadyQueue.push_back(prio, threadID);
        thread->nt.status = THREADSTATUS_READY;
    }
}

Change to:

Code:
void __KernelChangeReadyState(Thread *thread, SceUID threadID, bool ready)
{
    // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc.
    _dbg_assert_msg_(SCEKERNEL, thread->GetUID() == threadID, "Incorrect threadID");
    int prio = thread->nt.currentPriority;
    if (prio < 0 || prio > 127) {
        NOTICE_LOG(HLE, "Wackjob crazy priority %d for thread %d", prio, threadID);
        DebugBreak();
        thread->nt.currentPriority = 127;
        return;
    }

    if (thread->isReady())
    {
        if (!ready)
            threadReadyQueue.remove(prio, threadID);
    }
    else if (ready)
    {
        if (thread->isRunning())
            threadReadyQueue.push_front(prio, threadID);
        else
            threadReadyQueue.push_back(prio, threadID);
        thread->nt.status = THREADSTATUS_READY;
    }
}

Also:

Code:
Thread *__KernelNextThread() {
    SceUID bestThread;

    // If the current thread is running, it's a valid candidate.
    Thread *cur = __GetCurrentThread();
    if (cur && cur->isRunning())
    {
        bestThread = threadReadyQueue.pop_first_better(cur->nt.currentPriority);
        if (bestThread != 0)
            __KernelChangeReadyState(cur, currentThread, true);
    }
    else
        bestThread = threadReadyQueue.pop_first();

    // Assume threadReadyQueue has not become corrupt.
    if (bestThread != 0)
        return kernelObjects.GetFast<Thread>(bestThread);
    else
        return 0;
}

Change to:

Code:
Thread *__KernelNextThread() {
    SceUID bestThread;

    // If the current thread is running, it's a valid candidate.
    Thread *cur = __GetCurrentThread();
    if (cur && cur->isRunning())
    {
        bestThread = threadReadyQueue.pop_first_better(cur->nt.currentPriority);
        if (bestThread != 0)
            __KernelChangeReadyState(cur, currentThread, true);
    }
    else
        bestThread = threadReadyQueue.pop_first();

    // Assume threadReadyQueue has not become corrupt.
    if (bestThread != 0) {
        u32 errorIgnored;
        Thread *t = kernelObjects.Get<Thread>(bestThread, errorIgnored);
        if (t == NULL && bestThread != 0) {
            NOTICE_LOG(HLE, "ACK ACK ACK ACK Invalid thread id %d on thread queue", bestThread);
            DebugBreak();
            // Try, try again?
            t = __KernelNextThread();
        }
        if (t == NULL) {
            NOTICE_LOG(HLE, "ACK ACK ACK ACK Thread queue empty");
            DebugBreak();
            // Just brute force it, hopefully...
            return kernelObjects.Get<Thread>(threadIdleID[0], errorIgnored);
        }
        return t;
    } else {
        return 0;
    }
}

(and run in the debugger.)

-[Unknown]
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RE: Darkstalkers Chronicle The Chaos Tower - [Unknown] - 01-06-2014 01:45 AM

Forum Jump: