From 8a5daf211cf488b3228bc988e1c265dcf4b6bc0d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 5 Mar 2017 20:40:07 +0100 Subject: [PATCH] - added version check for member variables. --- src/dobjtype.cpp | 10 +++++ src/scripting/backend/codegen.cpp | 53 ++++++++++++++++++++++----- src/scripting/backend/codegen.h | 4 +- src/scripting/backend/vmbuilder.cpp | 2 +- src/scripting/symbols.h | 1 + src/scripting/zscript/zcc-parse.lemon | 2 +- src/scripting/zscript/zcc_parser.cpp | 3 +- 7 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 13b1c7ed9..a5dc66a5b 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1316,6 +1316,7 @@ PPointer::PPointer(PType *pointsat, bool isconst) : PBasicType(sizeof(void *), alignof(void *)), PointedType(pointsat), IsConst(isconst) { mDescriptiveName.Format("Pointer<%s%s>", pointsat->DescriptiveName(), isconst? "readonly " : ""); + mVersion = pointsat->mVersion; SetOps(); } @@ -1518,6 +1519,7 @@ PClassPointer::PClassPointer(PClass *restrict) // This means we can use the cheapoer non-barriered opcodes here. loadOp = OP_LOS; storeOp = OP_SP; + mVersion = restrict->mVersion; } //========================================================================== @@ -2522,6 +2524,14 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue else BitValue = -1; } +VersionInfo PField::GetVersion() +{ + VersionInfo Highest = { 0,0,0 }; + if (!(Flags & VARF_Deprecated)) Highest = mVersion; + if (Type->mVersion > Highest) Highest = Type->mVersion; + return Highest; +} + /* PProperty *****************************************************************/ IMPLEMENT_CLASS(PProperty, false, false) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 1b1672545..db834d146 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -89,15 +89,25 @@ static const FLOP FxFlops[] = { NAME_TanH, FLOP_TANH, [](double v) { return g_tanh(v); } }, }; + //========================================================================== // // FCompileContext // //========================================================================== -FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump) - : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg) +FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver) + : ReturnProto(ret), Function(fnc), Class(nullptr), FromDecorate(fromdecorate), StateIndex(stateindex), StateCount(statecount), Lump(lump), CurGlobals(cg), Version(ver) { + if (Version >= MakeVersion(2, 3)) + { + VersionString.Format("ZScript version %d.%d.%d", Version.major, Version.minor, Version.revision); + } + else + { + VersionString = "DECORATE"; + } + if (fnc != nullptr) Class = fnc->OwningClass; } @@ -5955,6 +5965,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } else if (sym->IsKindOf(RUNTIME_CLASS(PField))) { + PField *vsym = static_cast(sym); + + if (vsym->GetVersion() > ctx.Version) + { + ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", sym->SymbolName.GetChars(), ctx.VersionString.GetChars()); + delete this; + return nullptr; + } + // internally defined global variable ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global variable\n", Identifier.GetChars()); newex = new FxGlobalVariable(static_cast(sym), ScriptPosition); @@ -6014,7 +6033,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct if (!objtype->IsKindOf(RUNTIME_CLASS(PClassActor))) { ScriptPosition.Message(MSG_ERROR, "'Default' requires an actor type."); - delete this; + delete object; + object = nullptr; return nullptr; } @@ -6036,19 +6056,28 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct else if (sym->IsKindOf(RUNTIME_CLASS(PField))) { PField *vsym = static_cast(sym); - - // We have 4 cases to consider here: - // 1. The symbol is a static/meta member (not implemented yet) which is always accessible. - // 2. This is a static function - // 3. This is an action function with a restricted self pointer - // 4. This is a normal member or unrestricted action function. - if (vsym->Flags & VARF_Deprecated && !ctx.FromDecorate) + if (vsym->GetVersion() > ctx.Version) + { + ScriptPosition.Message(MSG_ERROR, "%s not accessible to %s", sym->SymbolName.GetChars(), ctx.VersionString.GetChars()); + delete object; + object = nullptr; + return nullptr; + } + if ((vsym->Flags & VARF_Deprecated) && sym->mVersion >= ctx.Version) { ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars()); } + + // We have 4 cases to consider here: + // 1. The symbol is a static/meta member which is always accessible. + // 2. This is a static function + // 3. This is an action function with a restricted self pointer + // 4. This is a normal member or unrestricted action function. if ((vsym->Flags & VARF_Private) && symtbl != &classctx->Symbols) { ScriptPosition.Message(MSG_ERROR, "Private member %s not accessible", vsym->SymbolName.GetChars()); + delete object; + object = nullptr; return nullptr; } PClass* cls_ctx = dyn_cast(classctx); @@ -6060,6 +6089,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct if (!cls_ctx || !cls_target) { ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars()); + delete object; + object = nullptr; return nullptr; } @@ -6079,6 +6110,8 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PStruct *classct if (!cls_ctx->IsDescendantOf(cls_target)) { ScriptPosition.Message(MSG_ERROR, "Protected member %s not accessible", vsym->SymbolName.GetChars()); + delete object; + object = nullptr; return nullptr; } } diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 000688341..5c6fb8ddd 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -86,8 +86,10 @@ struct FCompileContext bool Unsafe = false; TDeletingArray FunctionArgs; PNamespace *CurGlobals; + VersionInfo Version; + FString VersionString; - FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump); + FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver); FCompileContext(PNamespace *spc, PStruct *cls, bool fromdecorate); // only to be used to resolve constants! PSymbol *FindInClass(FName identifier, PSymbolTable *&symt); diff --git a/src/scripting/backend/vmbuilder.cpp b/src/scripting/backend/vmbuilder.cpp index e3942c33c..df53e51ed 100644 --- a/src/scripting/backend/vmbuilder.cpp +++ b/src/scripting/backend/vmbuilder.cpp @@ -857,7 +857,7 @@ void FFunctionBuildList::Build() assert(item.Code != NULL); // We don't know the return type in advance for anonymous functions. - FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump); + FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump, item.Version); // Allocate registers for the function's arguments and create local variable nodes before starting to resolve it. VMFunctionBuilder buildit(item.Func->GetImplicitArgs()); diff --git a/src/scripting/symbols.h b/src/scripting/symbols.h index 6f9519065..648462168 100644 --- a/src/scripting/symbols.h +++ b/src/scripting/symbols.h @@ -77,6 +77,7 @@ class PField : public PSymbol HAS_OBJECT_POINTERS public: PField(FName name, PType *type, uint32_t flags = 0, size_t offset = 0, int bitvalue = 0); + VersionInfo GetVersion(); size_t Offset; PType *Type; diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index c012d71e9..58d87557a 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -1030,7 +1030,7 @@ decl_flags(X) ::= decl_flags(F) DEPRECATED(B) LPAREN STRCONST(A) RPAREN. X->Version = A.String->GetChars(); } -decl_flags(X) ::= decl_flags(F) VERSION(B) LPAREN STRINGCONST(A) RPAREN. +decl_flags(X) ::= decl_flags(F) VERSION(B) LPAREN STRCONST(A) RPAREN. { if (F == nullptr) { diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 521ac9f67..6df435f6c 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -386,8 +386,7 @@ static void DoParse(int lumpnum) } else { - state.ParseVersion.major = 2; // 2.3 is the first version of ZScript. - state.ParseVersion.minor = 3; + state.ParseVersion = MakeVersion(2, 3); // 2.3 is the first version of ZScript. sc.RestorePos(saved); } }