Validate Program entry points and resolve accessible zero-argument constructors
Build / AerScript (push) Successful in 38s
Build / AerScript (push) Successful in 38s
This commit is contained in:
+54
-20
@@ -944,6 +944,7 @@ static sxi32 VmOverloadDominates(const sxi32 *aFirst, const sxi32 *aSecond, sxu3
|
|||||||
#define VM_INCLUDE_JUMP 4
|
#define VM_INCLUDE_JUMP 4
|
||||||
#define VM_INCLUDE_EXCEPTION 5
|
#define VM_INCLUDE_EXCEPTION 5
|
||||||
#define VM_RETURN_VOID 6
|
#define VM_RETURN_VOID 6
|
||||||
|
#define VM_CALL_ENTRY 2
|
||||||
static sxi32 VmExecIncludedFile(ph7_vm *pVm, SyString *pPath, int iFlags, ph7_value *pResult, ph7_include *pInclude);
|
static sxi32 VmExecIncludedFile(ph7_vm *pVm, SyString *pPath, int iFlags, ph7_value *pResult, ph7_include *pInclude);
|
||||||
static sxi32 VmLocalExec(ph7_vm *pVm, SySet *pByteCode, ph7_value *pResult);
|
static sxi32 VmLocalExec(ph7_vm *pVm, SySet *pByteCode, ph7_value *pResult);
|
||||||
static sxi32 VmClassMemberAccess(ph7_vm *pVm, ph7_class *pClass, sxi32 iProtection);
|
static sxi32 VmClassMemberAccess(ph7_vm *pVm, ph7_class *pClass, sxi32 iProtection);
|
||||||
@@ -5721,9 +5722,11 @@ Resume:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Select an appropriate function to call, if not entry point */
|
/* Only the explicitly validated entry point bypasses overload resolution. */
|
||||||
if((pInstr->iP2 & 1) == 0) {
|
if((pInstr->iP2 & 1) == 0) {
|
||||||
pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (sxi32)(pTos - pArg), pLookup, pThis == 0, bParent, pInstr->iP2 & 2);
|
pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (sxi32)(pTos - pArg), pLookup, pThis == 0, bParent, pInstr->iP2 & 2);
|
||||||
|
} else {
|
||||||
|
pVmFunc = (ph7_vm_func *)pInstr->p3;
|
||||||
}
|
}
|
||||||
if(pThis && (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD)) {
|
if(pThis && (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD)) {
|
||||||
pSelf = pVmFunc->pClass;
|
pSelf = pVmFunc->pClass;
|
||||||
@@ -6329,6 +6332,46 @@ static void VmInvokeShutdownCallbacks(ph7_vm *pVm) {
|
|||||||
}
|
}
|
||||||
SySetReset(&pVm->aShutdown);
|
SySetReset(&pVm->aShutdown);
|
||||||
}
|
}
|
||||||
|
/* Apply the usual C3 identical-signature hiding, but never choose between
|
||||||
|
* different public main signatures based on the CLI arguments. */
|
||||||
|
static ph7_class_method *VmEntryPoint(ph7_vm *pVm, ph7_class *pClass) {
|
||||||
|
ph7_class_method *pMain = 0;
|
||||||
|
sxu32 i;
|
||||||
|
for(i = 0; i < SySetUsed(&pClass->aMro); i++) {
|
||||||
|
ph7_class *pOwner = *(ph7_class **)SySetAt(&pClass->aMro, i);
|
||||||
|
ph7_class_method *pMethod = PH7_ClassExtractMethod(pOwner, "main", sizeof("main") - 1);
|
||||||
|
SyHashEntry *pEntry;
|
||||||
|
ph7_vm_func *pFunc;
|
||||||
|
if(!pMethod || pMethod->sFunc.pClass != pOwner) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pEntry = SyHashGet(&pVm->hFunction, pMethod->sVmName.zString, pMethod->sVmName.nByte);
|
||||||
|
for(pFunc = pEntry ? (ph7_vm_func *)pEntry->pUserData : 0; pFunc; pFunc = pFunc->pNextName) {
|
||||||
|
pMethod = (ph7_class_method *)pFunc;
|
||||||
|
if(pMethod->iProtection != PH7_CLASS_PROT_PUBLIC || (pMethod->iFlags & PH7_CLASS_ATTR_VIRTUAL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(pMain && !PH7_VmSameSignature(&pMain->sFunc, pFunc)) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Ambiguous program entry point 'Program::main()'");
|
||||||
|
}
|
||||||
|
if(!pMain) {
|
||||||
|
pMain = pMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!pMain) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "Cannot find a public program entry point 'Program::main()'");
|
||||||
|
}
|
||||||
|
if(pMain->sFunc.nType != MEMOBJ_INT && pMain->sFunc.nType != MEMOBJ_VOID) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "The 'Program::main()' return value can be either Integer or Void");
|
||||||
|
}
|
||||||
|
if(SySetUsed(&pMain->sFunc.aArgs) > 1 ||
|
||||||
|
(SySetUsed(&pMain->sFunc.aArgs) == 1 &&
|
||||||
|
((ph7_vm_func_arg *)SySetBasePtr(&pMain->sFunc.aArgs))->nType != (MEMOBJ_STRING | MEMOBJ_HASHMAP))) {
|
||||||
|
PH7_VmThrowError(pVm, PH7_CTX_ERR, "The 'Program::main()' parameters must be () or (string[])");
|
||||||
|
}
|
||||||
|
return pMain;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Execute as much of a PH7 bytecode program as we can then return.
|
* Execute as much of a PH7 bytecode program as we can then return.
|
||||||
* This function is a wrapper around [VmByteCodeExec()].
|
* This function is a wrapper around [VmByteCodeExec()].
|
||||||
@@ -6338,6 +6381,7 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) {
|
|||||||
ph7_class *pClass;
|
ph7_class *pClass;
|
||||||
ph7_class_instance *pInstance;
|
ph7_class_instance *pInstance;
|
||||||
ph7_class_method *pMethod;
|
ph7_class_method *pMethod;
|
||||||
|
ph7_class_method *pMain;
|
||||||
ph7_value *pArgs, *sArgv;
|
ph7_value *pArgs, *sArgv;
|
||||||
ph7_value pResult;
|
ph7_value pResult;
|
||||||
char *zDup, *zParam;
|
char *zDup, *zParam;
|
||||||
@@ -6355,6 +6399,8 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) {
|
|||||||
if(!pClass) {
|
if(!pClass) {
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot find an entry 'Program' class");
|
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot find an entry 'Program' class");
|
||||||
}
|
}
|
||||||
|
/* Reject invalid entry points before running the Program constructor. */
|
||||||
|
pMain = VmEntryPoint(pVm, pClass);
|
||||||
pInstance = PH7_NewClassInstance(&(*pVm), pClass);
|
pInstance = PH7_NewClassInstance(&(*pVm), pClass);
|
||||||
if(pInstance == 0) {
|
if(pInstance == 0) {
|
||||||
PH7_VmMemoryError(&(*pVm));
|
PH7_VmMemoryError(&(*pVm));
|
||||||
@@ -6363,7 +6409,7 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) {
|
|||||||
pMethod = PH7_ClassExtractMethod(pClass, "__construct", sizeof("__construct") - 1);
|
pMethod = PH7_ClassExtractMethod(pClass, "__construct", sizeof("__construct") - 1);
|
||||||
if(pMethod) {
|
if(pMethod) {
|
||||||
/* Call the class constructor */
|
/* Call the class constructor */
|
||||||
PH7_VmCallClassMethod(&(*pVm), pInstance, pMethod, 0, 0, 0);
|
VmCallClassMethod(pVm, pInstance, pMethod, 0, 0, 0, FALSE);
|
||||||
}
|
}
|
||||||
/* Enable garbage collector */
|
/* Enable garbage collector */
|
||||||
pInstance->iRef--;
|
pInstance->iRef--;
|
||||||
@@ -6383,20 +6429,14 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) {
|
|||||||
zParam = SyStrtok(NULL, " ");
|
zParam = SyStrtok(NULL, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Extract script entry point */
|
pMethod = pMain;
|
||||||
pMethod = PH7_ClassExtractMethod(pClass, "main", sizeof("main") - 1);
|
|
||||||
if(!pMethod) {
|
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot find a program entry point 'Program::main()'");
|
|
||||||
}
|
|
||||||
if(pMethod->sFunc.nType != MEMOBJ_INT && pMethod->sFunc.nType != MEMOBJ_VOID) {
|
|
||||||
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "The 'Program::main()' return value can be either Integer or Void");
|
|
||||||
}
|
|
||||||
/* A set of arguments is stored in array of strings */
|
/* A set of arguments is stored in array of strings */
|
||||||
pArgs->nType |= MEMOBJ_STRING;
|
pArgs->nType |= MEMOBJ_STRING;
|
||||||
/* Initialize variable for return value */
|
/* Initialize variable for return value */
|
||||||
PH7_MemObjInit(pVm, &pResult);
|
PH7_MemObjInit(pVm, &pResult);
|
||||||
/* Call entry point */
|
/* Call entry point */
|
||||||
PH7_VmCallClassMethod(&(*pVm), pInstance, pMethod, &pResult, 1, &pArgs);
|
VmCallClassMethod(pVm, pInstance, pMethod, &pResult,
|
||||||
|
(int)SySetUsed(&pMethod->sFunc.aArgs), &pArgs, VM_CALL_ENTRY);
|
||||||
if(!pVm->iExitStatus) {
|
if(!pVm->iExitStatus) {
|
||||||
if(pMethod->sFunc.nType == MEMOBJ_INT) {
|
if(pMethod->sFunc.nType == MEMOBJ_INT) {
|
||||||
pVm->iExitStatus = ph7_value_to_int(&pResult);
|
pVm->iExitStatus = ph7_value_to_int(&pResult);
|
||||||
@@ -7442,7 +7482,7 @@ static int vm_builtin_is_subclass_of(ph7_context *pCtx, int nArg, ph7_value **ap
|
|||||||
ph7_value *pResult, /* Store method return value here. NULL otherwise */
|
ph7_value *pResult, /* Store method return value here. NULL otherwise */
|
||||||
int nArg, /* Total number of given arguments */
|
int nArg, /* Total number of given arguments */
|
||||||
ph7_value **apArg, /* Method arguments */
|
ph7_value **apArg, /* Method arguments */
|
||||||
sxi32 bInternal /* VM-owned lifecycle call, not source new */
|
sxi32 bInternal /* VM-owned lifecycle call, or VM_CALL_ENTRY */
|
||||||
) {
|
) {
|
||||||
ph7_value *aStack;
|
ph7_value *aStack;
|
||||||
VmInstr aInstr[2];
|
VmInstr aInstr[2];
|
||||||
@@ -7466,7 +7506,7 @@ static int vm_builtin_is_subclass_of(ph7_context *pCtx, int nArg, ph7_value **ap
|
|||||||
aStack[i].nIdx = apArg[i]->nIdx;
|
aStack[i].nIdx = apArg[i]->nIdx;
|
||||||
}
|
}
|
||||||
iCursor = nArg + 1;
|
iCursor = nArg + 1;
|
||||||
iEntry = bInternal ? 2 : 0;
|
iEntry = bInternal == VM_CALL_ENTRY ? 3 : (bInternal ? 2 : 0);
|
||||||
if(pThis) {
|
if(pThis) {
|
||||||
/*
|
/*
|
||||||
* Push the class instance so that the '$this' variable will be available.
|
* Push the class instance so that the '$this' variable will be available.
|
||||||
@@ -7474,12 +7514,6 @@ static int vm_builtin_is_subclass_of(ph7_context *pCtx, int nArg, ph7_value **ap
|
|||||||
pThis->iRef++; /* Increment reference count */
|
pThis->iRef++; /* Increment reference count */
|
||||||
aStack[i].x.pOther = pThis;
|
aStack[i].x.pOther = pThis;
|
||||||
aStack[i].nType = MEMOBJ_OBJ;
|
aStack[i].nType = MEMOBJ_OBJ;
|
||||||
if(bInternal && SyStrncmp(pThis->pClass->sName.zString, "Program", 7) == 0) {
|
|
||||||
if((SyStrncmp(pMethod->sFunc.sName.zString, "main", 4) == 0) || (SyStrncmp(pMethod->sFunc.sName.zString, "__construct", 11) == 0)) {
|
|
||||||
/* Do not overload entry point */
|
|
||||||
iEntry |= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pSeed = VmMethodSeed(pVm, pThis ? pThis->pClass : pMethod->sFunc.pClass,
|
pSeed = VmMethodSeed(pVm, pThis ? pThis->pClass : pMethod->sFunc.pClass,
|
||||||
&pMethod->sFunc.sName, pMethod, FALSE);
|
&pMethod->sFunc.sName, pMethod, FALSE);
|
||||||
@@ -7505,7 +7539,7 @@ static int vm_builtin_is_subclass_of(ph7_context *pCtx, int nArg, ph7_value **ap
|
|||||||
aInstr[0].pScope = 0;
|
aInstr[0].pScope = 0;
|
||||||
aInstr[0].iP1 = nArg; /* Total number of given arguments */
|
aInstr[0].iP1 = nArg; /* Total number of given arguments */
|
||||||
aInstr[0].iP2 = iEntry;
|
aInstr[0].iP2 = iEntry;
|
||||||
aInstr[0].p3 = 0;
|
aInstr[0].p3 = (iEntry & 1) ? &pMethod->sFunc : 0;
|
||||||
aInstr[0].bExec = FALSE;
|
aInstr[0].bExec = FALSE;
|
||||||
aInstr[0].iLine = 1;
|
aInstr[0].iLine = 1;
|
||||||
aInstr[0].pFile = (SyString *)&sFileName;
|
aInstr[0].pFile = (SyString *)&sFileName;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require 'data/includes/test_class.aer';
|
|||||||
|
|
||||||
class Program extends BaseClass {
|
class Program extends BaseClass {
|
||||||
|
|
||||||
void main() {
|
public void main() {
|
||||||
$this->run();
|
$this->run();
|
||||||
object $test = new Test();
|
object $test = new Test();
|
||||||
var_dump($test);
|
var_dump($test);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ class Test2 extends Test1 {
|
|||||||
|
|
||||||
class Program {
|
class Program {
|
||||||
|
|
||||||
void main() {
|
public void main() {
|
||||||
int[] $q = {1, 2, 3};
|
int[] $q = {1, 2, 3};
|
||||||
float $t = 4;
|
float $t = 4;
|
||||||
object $x = new Test1();
|
object $x = new Test1();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class Sudoku {
|
|||||||
|
|
||||||
class Program {
|
class Program {
|
||||||
|
|
||||||
void main() {
|
public void main() {
|
||||||
int[] $board = {
|
int[] $board = {
|
||||||
{3, 0, 6, 5, 0, 8, 4, 0, 0},
|
{3, 0, 6, 5, 0, 8, 4, 0, 0},
|
||||||
{5, 2, 0, 0, 0, 0, 0, 0, 0},
|
{5, 2, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
|||||||
Reference in New Issue
Block a user