Script: Prevent writes to constant arrays

qteditor
Günther Brammer 2016-05-02 00:34:18 +02:00
parent 06b5f0e5ce
commit 99f704fbb8
6 changed files with 32 additions and 10 deletions

View File

@ -2262,9 +2262,9 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
{
if(Pos->GetSize() != 3)
throw C4AulExecError("CreateParticleAtBone: Pos is not a three-vector");
x.x = (*Pos)[0].getInt();
x.y = (*Pos)[1].getInt();
x.z = (*Pos)[2].getInt();
x.x = (*Pos).GetItem(0).getInt();
x.y = (*Pos).GetItem(1).getInt();
x.z = (*Pos).GetItem(2).getInt();
}
else { x.x = x.y = x.z = 0.0f; }
@ -2272,9 +2272,9 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
{
if(Dir->GetSize() != 3)
throw C4AulExecError("CreateParticleAtBone: Dir is not a three-vector");
dir.x = (*Dir)[0].getInt() / 10.0f;
dir.y = (*Dir)[1].getInt() / 10.0f;
dir.z = (*Dir)[2].getInt() / 10.0f;
dir.x = (*Dir).GetItem(0).getInt() / 10.0f;
dir.y = (*Dir).GetItem(1).getInt() / 10.0f;
dir.z = (*Dir).GetItem(2).getInt() / 10.0f;
}
else { dir.x = dir.y = dir.z = 0.0f; }
// Apply the bone transformation to them, to go from bone coordinates

View File

@ -514,6 +514,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos)
// Typcheck to determine whether it's an array or a proplist
if(CheckArrayAccess(pStruct, pIndex) == C4V_Array)
{
if (pStruct->_getArray()->IsFrozen())
throw C4AulExecError("array write: array is readonly");
pStruct->_getArray()->SetItem(pIndex->_getInt(), *pValue);
}
else
@ -566,6 +568,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos)
throw C4AulExecError(FormatString("array slice: end index of type %s, int expected", EndIndex.GetTypeName()).getData());
C4ValueArray *pArray = Array._getArray();
if (pArray->IsFrozen()) throw C4AulExecError("array write: array is readonly");
pArray->SetSlice(StartIndex._getInt(), EndIndex._getInt(), Value);
// Set value as result, remove both indices and first copy of value

View File

@ -2655,6 +2655,8 @@ C4Value C4AulParse::Parse_ConstExpression(C4PropListStatic * parent, C4String *
++size;
}
}
if (Type == PARSER)
r._getArray()->Freeze();
Shift();
break;
}

View File

@ -837,6 +837,7 @@ static Nillable<C4String *> FnGetConstantNameByValue(C4PropList * _this, int val
static bool FnSortArray(C4PropList * _this, C4ValueArray *pArray, bool descending)
{
if (!pArray) throw C4AulExecError("SortArray: no array given");
if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
// sort array by its members
pArray->Sort(descending);
return true;
@ -846,6 +847,7 @@ static bool FnSortArrayByProperty(C4PropList * _this, C4ValueArray *pArray, C4St
{
if (!pArray) throw C4AulExecError("SortArrayByProperty: no array given");
if (!prop_name) throw C4AulExecError("SortArrayByProperty: no property name given");
if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
// sort array by property
if (!pArray->SortByProperty(prop_name, descending)) throw C4AulExecError("SortArrayByProperty: not all array elements are proplists");
return true;
@ -855,6 +857,7 @@ static bool FnSortArrayByArrayElement(C4PropList * _this, C4ValueArray *pArray,
{
if (!pArray) throw C4AulExecError("SortArrayByArrayElement: no array given");
if (element_index<0) throw C4AulExecError("SortArrayByArrayElement: element index must be >=0");
if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
// sort array by array element
if (!pArray->SortByArrayElement(element_index, descending)) throw C4AulExecError("SortArrayByArrayElement: not all array elements are arrays of sufficient length");
return true;

View File

@ -22,18 +22,18 @@
#include "object/C4Object.h"
C4ValueArray::C4ValueArray()
: iSize(0), iCapacity(0), pData(NULL)
: pData(NULL), iSize(0), iCapacity(0), constant(false)
{
}
C4ValueArray::C4ValueArray(int32_t inSize)
: iSize(0), iCapacity(0), pData(NULL)
: pData(NULL), iSize(0), iCapacity(0), constant(false)
{
SetSize(inSize);
}
C4ValueArray::C4ValueArray(const C4ValueArray &ValueArray2)
: iSize(0), iCapacity(0), pData(NULL)
: pData(NULL), iSize(0), iCapacity(0), constant(false)
{
SetSize(ValueArray2.GetSize());
for (int32_t i = 0; i < iSize; i++)
@ -77,6 +77,7 @@ public:
void C4ValueArray::Sort(class C4SortObject &rSort)
{
assert(!constant);
if (rSort.PrepareCache(this))
{
// Initialize position array
@ -110,6 +111,7 @@ struct C4ValueArraySortStringscomp
void C4ValueArray::SortStrings()
{
assert(!constant);
std::stable_sort(pData, pData+iSize, C4ValueArraySortStringscomp());
}
@ -126,6 +128,7 @@ struct C4ValueArraySortcomp
void C4ValueArray::Sort(bool descending)
{
assert(!constant);
// sort by whatever type the values have
std::stable_sort(pData, pData+iSize, C4ValueArraySortcomp());
if (descending) std::reverse(pData, pData+iSize);
@ -146,6 +149,7 @@ struct C4ValueArraySortPropertycomp
bool C4ValueArray::SortByProperty(C4String *prop_name, bool descending)
{
assert(!constant);
// expect this to be an array of proplists and sort by given property
// make sure we're all proplists before
for (int32_t i=0; i<iSize; ++i)
@ -170,6 +174,7 @@ struct C4ValueArraySortArrayElementcomp
bool C4ValueArray::SortByArrayElement(int32_t element_idx, bool descending)
{
assert(element_idx>=0);
assert(!constant);
// expect this to be an array of arrays and sort by given element
// make sure we're all arrays before
for (int32_t i=0; i<iSize; ++i)
@ -189,6 +194,7 @@ C4Value &C4ValueArray::operator[](int32_t iElem)
{
assert(iElem < MaxSize);
assert(iElem >= 0);
assert(!constant);
if (iElem >= iSize && iElem < MaxSize) this->SetSize(iElem + 1);
// out-of-memory? This might not get caught, but it's better than a segfault
assert(iElem < iSize);
@ -198,6 +204,7 @@ C4Value &C4ValueArray::operator[](int32_t iElem)
void C4ValueArray::SetItem(int32_t iElem, const C4Value &Value)
{
assert(!constant);
// enlarge
if (iElem < -iSize)
throw C4AulExecError("array access: index out of range");
@ -214,6 +221,7 @@ void C4ValueArray::SetItem(int32_t iElem, const C4Value &Value)
void C4ValueArray::SetSize(int32_t inSize)
{
if(inSize == iSize) return;
assert(!constant);
// array not larger than allocated memory? Well, just ignore the additional allocated mem then
if (inSize <= iCapacity)

View File

@ -57,6 +57,11 @@ public:
void SetItem(int32_t iElemNr, const C4Value &Value); // interface for script
void SetSize(int32_t inSize); // (enlarge only!)
// for arrays declared in script constants
void Freeze() { constant = true; }
void Thaw() { constant = false; }
bool IsFrozen() const { return constant; }
void Denumerate(C4ValueNumbers *);
// comparison
@ -77,8 +82,9 @@ public:
bool SortByArrayElement(int32_t array_idx, bool descending=false); // checks that this is an array of all arrays and sorts by array elements at index. returns false if an element is not an array or smaller than array_idx+1
private:
int32_t iSize, iCapacity;
C4Value* pData;
int32_t iSize, iCapacity;
bool constant; // if true, this array is not changeable
};
#endif