Fix corruption issue with string iterator was using an absolute pointer. Also adds a special relative pointer type for constructed strings on the stack.

This commit is contained in:
James Urquhart 2015-02-16 21:05:45 +00:00
parent 97ab694af8
commit 942c7a48f4
7 changed files with 151 additions and 29 deletions

View file

@ -87,7 +87,7 @@ struct IterStackRecord
struct StringPos
{
/// The raw string data on the string stack.
const char* mString;
StringStackPtr mString;
/// Current parsing position.
U32 mIndex;
@ -288,6 +288,12 @@ inline void ExprEvalState::setStringVariable(const char *val)
currentVariable->setStringValue(val);
}
inline void ExprEvalState::setStringStackPtrVariable(StringStackPtr str)
{
AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
currentVariable->setStringStackPtrValue(str);
}
inline void ExprEvalState::setCopyVariable()
{
if (copyVariable)
@ -493,15 +499,25 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
ConsoleValueRef ref = argv[i+1];
if (argv[i+1].isString())
gEvalState.setStringVariable(argv[i+1]);
else if (argv[i+1].isInt())
switch(argv[i+1].getType())
{
case ConsoleValue::TypeInternalInt:
gEvalState.setIntVariable(argv[i+1]);
else if (argv[i+1].isFloat())
break;
case ConsoleValue::TypeInternalFloat:
gEvalState.setFloatVariable(argv[i+1]);
else
break;
case ConsoleValue::TypeInternalStringStackPtr:
gEvalState.setStringStackPtrVariable(argv[i+1].getStringStackPtrValue());
break;
case ConsoleValue::TypeInternalStackString:
case ConsoleValue::TypeInternalString:
default:
gEvalState.setStringVariable(argv[i+1]);
break;
}
}
ip = ip + (fnArgc * 2) + (2 + 6 + 1);
curFloatTable = functionFloats;
curStringTable = functionStrings;
@ -583,7 +599,7 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
Con::gCurrentRoot = this->modPath;
}
const char * val;
const char *retValue;
StringStackPtr retValue;
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
ConsoleValueRef returnValue;
@ -1137,7 +1153,7 @@ breakContinue:
// We're falling thru here on purpose.
case OP_RETURN:
retValue = STR.getStringValue();
retValue = STR.getStringValuePtr();
if( iterDepth > 0 )
{
@ -1149,13 +1165,13 @@ breakContinue:
}
STR.rewind();
STR.setStringValue( retValue ); // Not nice but works.
retValue = STR.getStringValue();
STR.setStringValue( StringStackPtrRef(retValue).getPtr(&STR) ); // Not nice but works.
retValue = STR.getStringValuePtr();
}
// Previously the return value was on the stack and would be returned using STR.getStringValue().
// Now though we need to wrap it in a ConsoleValueRef
returnValue.value = CSTK.pushStackString(retValue);
returnValue.value = CSTK.pushStringStackPtr(retValue);
goto execFinished;
@ -1992,7 +2008,7 @@ breakContinue:
break;
case OP_PUSH:
STR.push();
CSTK.pushString(STR.getPreviousStringValue());
CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr());
break;
case OP_PUSH_UINT:
CSTK.pushUINT(intStack[_UINT]);
@ -2073,7 +2089,7 @@ breakContinue:
if( iter.mIsStringIter )
{
iter.mData.mStr.mString = STR.getStringValue();
iter.mData.mStr.mString = STR.getStringValuePtr();
iter.mData.mStr.mIndex = 0;
}
else
@ -2111,7 +2127,7 @@ breakContinue:
if( iter.mIsStringIter )
{
const char* str = iter.mData.mStr.mString;
const char* str = StringStackPtrRef(iter.mData.mStr.mString).getPtr(&STR);
U32 startIndex = iter.mData.mStr.mIndex;
U32 endIndex = startIndex;

View file

@ -1756,6 +1756,8 @@ const char *ConsoleValue::getStringValue()
{
if(type == TypeInternalString || type == TypeInternalStackString)
return sval;
else if (type == TypeInternalStringStackPtr)
return STR.mBuffer + (U32)sval;
if(type == TypeInternalFloat)
return Con::getData(TypeF32, &fval, 0);
else if(type == TypeInternalInt)
@ -1764,10 +1766,18 @@ const char *ConsoleValue::getStringValue()
return Con::getData(type, dataPtr, 0, enumTable);
}
StringStackPtr ConsoleValue::getStringStackPtr()
{
if (type == TypeInternalStringStackPtr)
return (U32)sval;
else
return (U32)-1;
}
bool ConsoleValue::getBoolValue()
{
if(type == TypeInternalString || type == TypeInternalStackString)
return dAtob(sval);
if(type == TypeInternalString || type == TypeInternalStackString || type == TypeInternalStringStackPtr)
return dAtob(getStringValue());
if(type == TypeInternalFloat)
return fval > 0;
else if(type == TypeInternalInt)
@ -1791,7 +1801,7 @@ void ConsoleValue::setIntValue(U32 val)
ival = val;
if(sval != typeValueEmpty)
{
if (type != TypeInternalStackString) dFree(sval);
if (type != TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalInt;
@ -1816,7 +1826,7 @@ void ConsoleValue::setFloatValue(F32 val)
ival = static_cast<U32>(val);
if(sval != typeValueEmpty)
{
if (type != TypeInternalStackString) dFree(sval);
if (type != TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalFloat;

View file

@ -44,6 +44,8 @@ struct ConsoleFunctionHeader;
class EngineEnumTable;
typedef EngineEnumTable EnumTable;
typedef U32 StringStackPtr;
template< typename T > S32 TYPEID();
@ -121,8 +123,9 @@ public:
enum
{
TypeInternalInt = -4,
TypeInternalFloat = -3,
TypeInternalInt = -5,
TypeInternalFloat = -4,
TypeInternalStringStackPtr = -3,
TypeInternalStackString = -2,
TypeInternalString = -1,
};
@ -166,6 +169,7 @@ public:
S32 getSignedIntValue();
F32 getFloatValue();
const char *getStringValue();
StringStackPtr getStringStackPtr();
bool getBoolValue();
void setIntValue(U32 val);
@ -173,6 +177,7 @@ public:
void setFloatValue(F32 val);
void setStringValue(const char *value);
void setStackStringValue(const char *value);
void setStringStackPtrValue(StringStackPtr ptr);
void setBoolValue(bool val);
void init()
@ -187,7 +192,7 @@ public:
void cleanup()
{
if (type <= TypeInternalString &&
sval != typeValueEmpty && type != TypeInternalStackString )
sval != typeValueEmpty && type != TypeInternalStackString && type != TypeInternalStringStackPtr)
dFree(sval);
sval = typeValueEmpty;
type = ConsoleValue::TypeInternalString;
@ -219,6 +224,7 @@ public:
static ConsoleValueRef fromValue(ConsoleValue *value) { ConsoleValueRef ref; ref.value = value; return ref; }
const char *getStringValue() { return value ? value->getStringValue() : ""; }
StringStackPtr getStringStackPtrValue() { return value ? value->getStringStackPtr() : 0; }
inline U32 getIntValue() { return value ? value->getIntValue() : 0; }
inline S32 getSignedIntValue() { return value ? value->getSignedIntValue() : 0; }
@ -231,10 +237,12 @@ public:
inline operator S32() { return getSignedIntValue(); }
inline operator F32() { return getFloatValue(); }
inline operator bool() { return getBoolValue(); }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStackString : true; }
inline bool isStringStackPtr() { return value ? value->type == ConsoleValue::TypeInternalStringStackPtr : false; }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStringStackPtr : true; }
inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
inline bool isFloat() { return value ? value->type == ConsoleValue::TypeInternalFloat : false; }
inline S32 getType() { return value ? value->type : -1; }
// Note: operators replace value
ConsoleValueRef& operator=(const ConsoleValueRef &other);

View file

@ -512,7 +512,7 @@ void ConsoleValue::setStringValue(const char * value)
*/
if (value == typeValueEmpty)
{
if (sval && sval != typeValueEmpty && type != TypeInternalStackString) dFree(sval);
if (sval && sval != typeValueEmpty && type != TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
@ -541,7 +541,7 @@ void ConsoleValue::setStringValue(const char * value)
// may as well pad to the next cache line
U32 newLen = ((stringLen + 1) + 15) & ~15;
if(sval == typeValueEmpty || type == TypeInternalStackString)
if(sval == typeValueEmpty || type == TypeInternalStackString || type == TypeInternalStringStackPtr)
sval = (char *) dMalloc(newLen);
else if(newLen > bufferLen)
sval = (char *) dRealloc(sval, newLen);
@ -556,7 +556,7 @@ void ConsoleValue::setStringValue(const char * value)
}
void ConsoleValue::setStackStringValue(const char * value)
void ConsoleValue::setStackStringValue(const char *value)
{
if (value == NULL) value = typeValueEmpty;
@ -564,7 +564,7 @@ void ConsoleValue::setStackStringValue(const char * value)
{
if (value == typeValueEmpty)
{
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString) dFree(sval);
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString && type != ConsoleValue::TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
@ -586,13 +586,42 @@ void ConsoleValue::setStackStringValue(const char * value)
}
type = TypeInternalStackString;
sval = (char*)value;
sval = (char*)value;
bufferLen = stringLen;
}
else
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
void ConsoleValue::setStringStackPtrValue(StringStackPtr ptrValue)
{
if(type <= ConsoleValue::TypeInternalString)
{
const char *value = StringStackPtrRef(ptrValue).getPtr(&STR);
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
U32 stringLen = dStrlen(value);
if(stringLen < 256)
{
fval = dAtof(value);
ival = dAtoi(value);
}
else
{
fval = 0.f;
ival = 0;
}
type = TypeInternalStringStackPtr;
sval = (char*)(value - STR.mBuffer);
bufferLen = stringLen;
}
else
{
const char *value = StringStackPtrRef(ptrValue).getPtr(&STR);
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
}
S32 Dictionary::getIntVariable(StringTableEntry name, bool *entValid)
{
@ -651,7 +680,8 @@ Dictionary::Entry* Dictionary::addVariable( const char *name,
Entry *ent = add(StringTable->insert(name));
if ( ent->value.type <= ConsoleValue::TypeInternalString &&
ent->value.sval != typeValueEmpty && ent->value.type != ConsoleValue::TypeInternalStackString )
ent->value.sval != typeValueEmpty &&
ent->value.type != ConsoleValue::TypeInternalStackString && ent->value.type != ConsoleValue::TypeInternalStringStackPtr )
dFree(ent->value.sval);
ent->value.type = type;

View file

@ -367,6 +367,22 @@ public:
notify->trigger();
}
void setStringStackPtrValue(StringStackPtr newValue)
{
if( mIsConstant )
{
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
value.setStringStackPtrValue(newValue);
// Fire off the notification if we have one.
if ( notify )
notify->trigger();
}
void setStringValue(const char *newValue)
{
if( mIsConstant )
@ -495,6 +511,7 @@ public:
void setIntVariable(S32 val);
void setFloatVariable(F64 val);
void setStringVariable(const char *str);
void setStringStackPtrVariable(StringStackPtr str);
void setCopyVariable();
void pushFrame(StringTableEntry frameName, Namespace *ns);

View file

@ -90,6 +90,8 @@ void ConsoleValueStack::pushValue(ConsoleValue &variable)
mStack[mStackPos++].setIntValue((S32)variable.getIntValue());
case ConsoleValue::TypeInternalFloat:
mStack[mStackPos++].setFloatValue((F32)variable.getFloatValue());
case ConsoleValue::TypeInternalStringStackPtr:
mStack[mStackPos++].setStringStackPtrValue(variable.getStringStackPtr());
default:
mStack[mStackPos++].setStringValue(variable.getStringValue());
}
@ -151,6 +153,19 @@ ConsoleValue *ConsoleValueStack::pushStackString(const char *value)
return &mStack[mStackPos-1];
}
ConsoleValue *ConsoleValueStack::pushStringStackPtr(StringStackPtr value)
{
if (mStackPos == ConsoleValueStack::MaxStackDepth) {
AssertFatal(false, "Console Value Stack is empty");
return NULL;
}
//Con::printf("[%i]CSTK pushStringStackPtr %s", mStackPos, StringStackPtrRef(value).getPtr(&STR));
mStack[mStackPos++].setStringStackPtrValue(value);
return &mStack[mStackPos-1];
}
ConsoleValue *ConsoleValueStack::pushUINT(U32 value)
{
if (mStackPos == ConsoleValueStack::MaxStackDepth) {

View file

@ -35,8 +35,21 @@
#include "console/console.h"
#endif
typedef U32 StringStackPtr;
struct StringStack;
/// Helper class which stores a relative pointer in the StringStack buffer
class StringStackPtrRef
{
public:
StringStackPtrRef() : mOffset(0) {;}
StringStackPtrRef(StringStackPtr offset) : mOffset(offset) {;}
StringStackPtr mOffset;
/// Get pointer to string in stack stk
inline char *getPtr(StringStack *stk);
};
/// Core stack for interpreter operations.
///
@ -199,6 +212,16 @@ struct StringStack
return mBuffer + mStartOffsets[mStartStackSize-1];
}
inline StringStackPtr getStringValuePtr()
{
return (getStringValue() - mBuffer);
}
inline StringStackPtr getPreviousStringValuePtr()
{
return (getPreviousStringValue() - mBuffer);
}
/// Advance the start stack, placing a zero length string on the top.
///
/// @note You should use StringStack::push, not this, if you want to
@ -322,6 +345,7 @@ public:
ConsoleValue *pushString(const char *value);
ConsoleValue *pushStackString(const char *value);
ConsoleValue *pushStringStackPtr(StringStackPtr ptr);
ConsoleValue *pushUINT(U32 value);
ConsoleValue *pushFLT(float value);
@ -345,4 +369,6 @@ public:
extern StringStack STR;
extern ConsoleValueStack CSTK;
inline char* StringStackPtrRef::getPtr(StringStack *stk) { return stk->mBuffer + mOffset; }
#endif