iT2D 1.4 - Returning very long strings from a function causes crash EXC_BAD_ACCESS in audio driver - RESOLVED
by William Grupp · in iTorque 2D · 08/24/2010 (8:52 pm) · 5 replies
Build: 1.4, 1.3
Platform: Simulator/iPhone/iPod
Target: On Device or Simulator
Issues: Returning a long string from a function call causes a "EXC_BAD_ACCESS" crash. The
crash is usually in the alx audio driver code but the actual location changes depending on
how long the return string is.
Sample function:
The issue is also seen if you do a string assignment as the last line of a function with no
return statement.
The issue is in the function: Namespace::Entry::execute in Namespace.cc. This function returns a value
from a static buffer that is fixed at 32 bytes. If the ret string returned by the torque script
function is longer than 32 bytes, the dStrcpy call will write past the end of returnBuffer2.
With a long enough string, the data effected reaches the audio driver.
existing code:
Suggested Fix: Increase the size of the returnBuffer2. Provide a warning when the ret string is
too large to be handled by the increased size. Use dStrncpy to prevent the string copy from
writing past the end of the buffer.
I would also suggest make a global define for the longest sized string that would be allowed
in torque script and have some warnings when that size is exceeded.
Platform: Simulator/iPhone/iPod
Target: On Device or Simulator
Issues: Returning a long string from a function call causes a "EXC_BAD_ACCESS" crash. The
crash is usually in the alx audio driver code but the actual location changes depending on
how long the return string is.
Sample function:
function myStuff::foo(%this)
{
return "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
}The issue is also seen if you do a string assignment as the last line of a function with no
return statement.
The issue is in the function: Namespace::Entry::execute in Namespace.cc. This function returns a value
from a static buffer that is fixed at 32 bytes. If the ret string returned by the torque script
function is longer than 32 bytes, the dStrcpy call will write past the end of returnBuffer2.
With a long enough string, the data effected reaches the audio driver.
existing code:
const char *Namespace::Entry::execute(S32 argc, const char **argv, ExprEvalState *state)
{
if(mType == ScriptFunctionType)
{
if(mFunctionOffset) {
recursionCount++;
//pass in recursionCount, the number of times this entry has been called
const char * ret = mCode->exec(mFunctionOffset, argv[0], mNamespace, argc, argv, false, mPackage, recursionCount );
recursionCount--;
//Luma: We need to return the return value here, but it must be in a static variable to remain valid
static char returnBuffer2[32];
dStrcpy(returnBuffer2, ret);
return returnBuffer2;
}
else
return "";
}
...Suggested Fix: Increase the size of the returnBuffer2. Provide a warning when the ret string is
too large to be handled by the increased size. Use dStrncpy to prevent the string copy from
writing past the end of the buffer.
const char *Namespace::Entry::execute(S32 argc, const char **argv, ExprEvalState *state)
{
if(mType == ScriptFunctionType)
{
if(mFunctionOffset) {
recursionCount++;
//pass in recursionCount, the number of times this entry has been called
const char * ret = mCode->exec(mFunctionOffset, argv[0], mNamespace, argc, argv, false, mPackage, recursionCount );
recursionCount--;
//Luma: We need to return the return value here, but it must be in a static variable to remain valid
static char returnBuffer2[4096];
AssertFatal( dStrlen(ret) < sizeof(returnBuffer2), "Namespace::Entry::execute -> Size of returned string too large for return buffer" );
dStrncpy(returnBuffer2, ret, (sizeof(returnBuffer2)-1));
return returnBuffer2;
}
else
return "";
}
...I would also suggest make a global define for the longest sized string that would be allowed
in torque script and have some warnings when that size is exceeded.
About the author
#2
Well, yea, it is kinda strong ;)
But, AssertFatal has no effect in shipping builds and there is no way
to know what data you are missing by truncating the ret string at the
buffer size.
The 'better' way would be to use a Vector that would resize as needed.
I'll leave that for the experts.
08/24/2010 (10:08 pm)
Quote:AssertFatal is a "warning" in the same sense that your left arm hurting before a heart attack imo :)
Well, yea, it is kinda strong ;)
But, AssertFatal has no effect in shipping builds and there is no way
to know what data you are missing by truncating the ret string at the
buffer size.
The 'better' way would be to use a Vector that would resize as needed.
I'll leave that for the experts.
#3
08/24/2010 (10:15 pm)
Nice William, seeing that hardcoded 32 freaks me out a little. I'm going to go back and repro my old bug and see if I can cause the assert here with a small buffer size. I'm still learning my away around the engine code, I appreciate the thread response!
#4
08/27/2010 (6:24 pm)
Logged as ITGB-87 in Jira bug tracker.
#5
02/10/2011 (10:42 am)
Fixed in 1.4.1.
Associate Craig Fortune
Only copying the right amount of chars over seems like a good and obvious fix - the best kind of fix!