Browse Source

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

James Urquhart 10 years ago
parent
commit
942c7a48f4

+ 30 - 14
Engine/source/console/compiledEval.cpp

@@ -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;

+ 14 - 4
Engine/source/console/console.cpp

@@ -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;

+ 13 - 5
Engine/source/console/console.h

@@ -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);

+ 36 - 6
Engine/source/console/consoleInternal.cpp

@@ -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;

+ 17 - 0
Engine/source/console/consoleInternal.h

@@ -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);

+ 15 - 0
Engine/source/console/stringStack.cpp

@@ -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) {

+ 26 - 0
Engine/source/console/stringStack.h

@@ -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