After encountering some fairly incomprehensible issues with corrupted arguments to system functions, I managed to track down a script stack overflow with some valgrind assistance.
The issue occurs when a context's stack pointer is near the end of its stack block, and the context is prepared for a new nested function call after pushing the state. asCContext::Prepare does the following calculation for checking if a new stack block should be allocated:
// Determine the minimum stack size needed
int stackSize = m_argumentsSize + m_returnValueSize;
if( m_currentFunction->scriptData )
stackSize += m_currentFunction->scriptData->stackNeeded;
If an asFUNC_VIRTUAL function was passed to Prepare(), it will not have scriptData for obvious reasons, and if the function needs more stack than is remaining in the current block, it will overflow and read/write into invalid memory during execution.
The virtual function is resolved into its real counterpart when asCContext::Execute() hits, so I added a quick fix to ensure enough stack space is available there. I don't know if this is the way you would want it to be solved, but it fixes the encountered problems in our project.
}
if( realFunc && realFunc->signatureId == m_currentFunction->signatureId )
+ {
m_currentFunction = realFunc;
+
+ // Make sure our stack is large enough for local variables in this function
+ if( m_currentFunction->scriptData )
+ {
+ asDWORD* oldStack = m_regs.stackPointer;
+
+ int stackSize = m_argumentsSize + m_returnValueSize;
+ if( m_currentFunction->scriptData )
+ stackSize += m_currentFunction->scriptData->stackNeeded;
+ if( !ReserveStackSpace(stackSize) )
+ SetInternalException(TXT_NO_STACK_MEMORY);
+
+ if( oldStack != m_regs.stackPointer )
+ {
+ memcpy(m_regs.stackPointer, m_regs.stackFramePointer, sizeof(asDWORD)*(m_argumentsSize + m_returnValueSize));
+ m_regs.stackFramePointer = m_regs.stackPointer;
+ }
+ }
+ }
else
SetInternalException(TXT_NULL_POINTER_ACCESS);
}