From 0866c0a4b5604ac975311ec3fa030ff02002a0d0 Mon Sep 17 00:00:00 2001 From: HelgeffegleH Date: Sun, 9 Oct 2022 16:18:06 +0200 Subject: [PATCH] Fixed var's object being deleted before variable being marked as uninitialised. Reason, the var might be read directly or indirectly, under the false impression that the variable is set (with the object as its value), from the objects __delete routine. --- source/MdFunc.cpp | 3 +-- source/script_object.cpp | 6 ++++-- source/var.cpp | 8 ++------ source/var.h | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/source/MdFunc.cpp b/source/MdFunc.cpp index f847cdaa7..a122ae38a 100644 --- a/source/MdFunc.cpp +++ b/source/MdFunc.cpp @@ -458,8 +458,7 @@ bool MdFunc::Call(ResultToken &aResultToken, ExprTokenType *aParam[], int aParam { // Although 0 or "" is a fairly conventional default, it might not be safe. // For error-detection and to avoid unexpected behaviour, "unset" the var. - var->Assign(); - var->MarkUninitialized(); + var->Uninitialize(); } } diff --git a/source/script_object.cpp b/source/script_object.cpp index 094876aa1..f5a725f57 100644 --- a/source/script_object.cpp +++ b/source/script_object.cpp @@ -2089,9 +2089,11 @@ ResultType Array::GetEnumItem(UINT &aIndex, Var *aVal, Var *aReserved, int aVarC switch (item.symbol) { default: - aVal->AssignString(item.string, item.string.Length()); if (item.symbol == SYM_MISSING) - aVal->MarkUninitialized(); + aVal->Uninitialize(); + else + aVal->AssignString(item.string, item.string.Length()); + break; case SYM_INTEGER: aVal->Assign(item.n_int64); break; case SYM_FLOAT: aVal->Assign(item.n_double); break; diff --git a/source/var.cpp b/source/var.cpp index 92a2c67b2..da0fe9e80 100644 --- a/source/var.cpp +++ b/source/var.cpp @@ -43,8 +43,7 @@ ResultType Var::Assign(Var &aVar) if (source_var.mAttrib & VAR_ATTRIB_UNINITIALIZED) { - target_var.Assign(); - target_var.MarkUninitialized(); + target_var.Uninitialize(); return OK; } @@ -84,10 +83,7 @@ ResultType Var::Assign(ExprTokenType &aToken) default: ASSERT(!"Unhandled symbol"); case SYM_MISSING: - if (!Assign()) - return FAIL; - MarkUninitialized(); - return OK; + return Uninitialize() ? OK : FAIL; } // Since above didn't return, it can only be SYM_STRING. return Assign(aToken.marker, aToken.marker_length); diff --git a/source/var.h b/source/var.h index 32949e857..0fb6eb498 100644 --- a/source/var.h +++ b/source/var.h @@ -926,9 +926,23 @@ class Var void MarkUninitialized() { - Var &var = *ResolveAlias(); + Var& var = *ResolveAlias(); var.mAttrib |= VAR_ATTRIB_UNINITIALIZED; } + ResultType Uninitialize() + { + Var& var = *ResolveAlias(); + auto obj = (var.mAttrib & VAR_ATTRIB_IS_OBJECT) ? mObject : nullptr; + if (obj) + obj -> AddRef(); + auto result = var.Assign(); + if (result) + var.MarkUninitialized(); + if (obj) + obj->Release(); + + return result; + } }; // class Var #pragma pack(pop) // Calling pack with no arguments restores the default value (which is 8, but "the alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.")