Preserve runtime object identity and declaring-class scope in inherited method calls
Build / AerScript (push) Successful in 2m48s

This commit is contained in:
2026-10-24 00:18:24 +02:00
parent 04a74de51a
commit 18e6da6c08
+46 -23
View File
@@ -1391,6 +1391,19 @@ static ph7_value *VmNewOperandStack(
/* Forward declaration */ /* Forward declaration */
static sxi32 VmRegisterSpecialFunction(ph7_vm *pVm); static sxi32 VmRegisterSpecialFunction(ph7_vm *pVm);
static int VmClassMemberAccess(ph7_vm *pVm, ph7_class *pClass, sxi32 iProtection); static int VmClassMemberAccess(ph7_vm *pVm, ph7_class *pClass, sxi32 iProtection);
/* Exception frames retain the enclosing method's lexical scope. */
static ph7_class *VmMethodClass(ph7_vm *pVm) {
VmFrame *pFrame = pVm->pFrame;
ph7_vm_func *pVmFunc;
while(pFrame->pParent && (pFrame->iFlags & (VM_FRAME_EXCEPTION | VM_FRAME_CATCH | VM_FRAME_FINALLY))) {
pFrame = pFrame->pParent;
}
pVmFunc = (ph7_vm_func *)pFrame->pUserData;
if(pVmFunc == 0 || (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) == 0) {
return 0;
}
return (ph7_class *)pVmFunc->pUserData;
}
/* /*
* Prepare the Virtual Machine for byte-code execution. * Prepare the Virtual Machine for byte-code execution.
* This routine gets called by the PH7 engine after * This routine gets called by the PH7 engine after
@@ -4451,12 +4464,17 @@ static sxi32 VmByteCodeExec(
if(!pNos->x.pOther) { if(!pNos->x.pOther) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Call to non-instantiated object '$%z'", &sName); PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Call to non-instantiated object '$%z'", &sName);
} }
ph7_class *pClass, *pDerived; ph7_class *pClass, *pDerived, *pScope;
/* Class already instantiated */ /* Class already instantiated */
pThis = (ph7_class_instance *)pNos->x.pOther; pThis = (ph7_class_instance *)pNos->x.pOther;
/* Point to the instantiated class */ /* Point to the instantiated class */
pClass = pThis->pClass; pClass = pThis->pClass;
pScope = VmMethodClass(pVm);
if(pNos->iFlags == MEMOBJ_PARENTOBJ) { if(pNos->iFlags == MEMOBJ_PARENTOBJ) {
/* Parent lookup starts at the declaring class, not the receiver. */
if(pScope) {
pClass = pScope;
}
if(pClass->pBase == 0) { if(pClass->pBase == 0) {
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
"Attempt to call parent class from non-inheritance instance of class '%z'", &pClass->sName); "Attempt to call parent class from non-inheritance instance of class '%z'", &pClass->sName);
@@ -4470,7 +4488,15 @@ static sxi32 VmByteCodeExec(
if(sName.nByte > 0) { if(sName.nByte > 0) {
/* Extract the target method */ /* Extract the target method */
if(pNos->iFlags != MEMOBJ_PARENTOBJ) { if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
pMeth = PH7_ClassExtractMethod(pClass, sName.zString, sName.nByte); if(pScope && VmInstanceOf(pClass, pScope)) {
pMeth = PH7_ClassExtractMethod(pScope, sName.zString, sName.nByte);
if(pMeth && (pMeth->iProtection != PH7_CLASS_PROT_PRIVATE || pMeth->sFunc.pClass != pScope)) {
pMeth = 0;
}
}
if(pMeth == 0) {
pMeth = PH7_ClassExtractMethod(pClass, sName.zString, sName.nByte);
}
} }
if(pMeth == 0) { if(pMeth == 0) {
/* Browse hashtable from the beginning */ /* Browse hashtable from the beginning */
@@ -4510,7 +4536,16 @@ static sxi32 VmByteCodeExec(
if(sName.nByte > 0) { if(sName.nByte > 0) {
/* Extract the target attribute */ /* Extract the target attribute */
if(pNos->iFlags != MEMOBJ_PARENTOBJ) { if(pNos->iFlags != MEMOBJ_PARENTOBJ) {
pAttr = PH7_ClassExtractAttribute(pClass, sName.zString, sName.nByte); /* Private fields belong to their declaring class, even on a derived object. */
if(pScope && VmInstanceOf(pClass, pScope)) {
pAttr = PH7_ClassExtractAttribute(pScope, sName.zString, sName.nByte);
if(pAttr && pAttr->iProtection != PH7_CLASS_PROT_PRIVATE) {
pAttr = 0;
}
}
if(pAttr == 0) {
pAttr = PH7_ClassExtractAttribute(pClass, sName.zString, sName.nByte);
}
} }
if(pAttr == 0) { if(pAttr == 0) {
/* Browse hashtable from the beginning */ /* Browse hashtable from the beginning */
@@ -4903,7 +4938,6 @@ static sxi32 VmByteCodeExec(
if(pEntry) { if(pEntry) {
ph7_vm_func_arg *aFormalArg; ph7_vm_func_arg *aFormalArg;
ph7_class_instance *pThis; ph7_class_instance *pThis;
ph7_class *pClass;
ph7_value *pFrameStack; ph7_value *pFrameStack;
ph7_vm_func *pVmFunc; ph7_vm_func *pVmFunc;
ph7_class *pSelf; ph7_class *pSelf;
@@ -4915,7 +4949,6 @@ static sxi32 VmByteCodeExec(
pVmFunc = (ph7_vm_func *)pEntry->pUserData; pVmFunc = (ph7_vm_func *)pEntry->pUserData;
pThis = 0; pThis = 0;
pSelf = 0; pSelf = 0;
pClass = 0;
if(pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) { if(pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) {
/* Class method call */ /* Class method call */
ph7_value *pTarget = &pTos[-1]; ph7_value *pTarget = &pTos[-1];
@@ -4925,9 +4958,7 @@ static sxi32 VmByteCodeExec(
/* Instance already loaded */ /* Instance already loaded */
pThis = (ph7_class_instance *)pTarget->x.pOther; pThis = (ph7_class_instance *)pTarget->x.pOther;
pThis->iRef += 2; pThis->iRef += 2;
pClass = pThis->pClass; pSelf = pVmFunc->pClass;
pThis->pClass = pVmFunc->pClass;
pSelf = pThis->pClass;
} }
if(pSelf == 0) { if(pSelf == 0) {
if((pTarget->nType & MEMOBJ_STRING) && SyBlobLength(&pTarget->sBlob) > 0) { if((pTarget->nType & MEMOBJ_STRING) && SyBlobLength(&pTarget->sBlob) > 0) {
@@ -4957,6 +4988,9 @@ static sxi32 VmByteCodeExec(
if(pInstr->iP2 == 0) { if(pInstr->iP2 == 0) {
pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (int)(pTos - pArg)); pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (int)(pTos - pArg));
} }
if(pThis && (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD)) {
pSelf = pVmFunc->pClass;
}
/* Extract the formal argument set */ /* Extract the formal argument set */
aFormalArg = (ph7_vm_func_arg *)SySetBasePtr(&pVmFunc->aArgs); aFormalArg = (ph7_vm_func_arg *)SySetBasePtr(&pVmFunc->aArgs);
/* Create a new VM frame */ /* Create a new VM frame */
@@ -5256,10 +5290,6 @@ static sxi32 VmByteCodeExec(
SyMemBackendFree(&pVm->sAllocator, pFrameStack); SyMemBackendFree(&pVm->sAllocator, pFrameStack);
/* Leave the frame */ /* Leave the frame */
VmLeaveFrame(&(*pVm)); VmLeaveFrame(&(*pVm));
if(pClass != 0 && pClass != pThis->pClass) {
/* Restore original class */
pThis->pClass = pClass;
}
if(rc == PH7_ABORT) { if(rc == PH7_ABORT) {
/* Abort processing immediately */ /* Abort processing immediately */
goto Abort; goto Abort;
@@ -6209,26 +6239,19 @@ static int VmClassMemberAccess(
sxi32 iProtection /* Attribute protection level [i.e: public,protected or private] */ sxi32 iProtection /* Attribute protection level [i.e: public,protected or private] */
) { ) {
if(iProtection != PH7_CLASS_PROT_PUBLIC) { if(iProtection != PH7_CLASS_PROT_PUBLIC) {
VmFrame *pFrame = pVm->pFrame; ph7_class *pScope = VmMethodClass(pVm);
ph7_vm_func *pVmFunc; if(pScope == 0) {
while(pFrame->pParent && (pFrame->iFlags & (VM_FRAME_EXCEPTION | VM_FRAME_CATCH | VM_FRAME_FINALLY))) {
/* Safely ignore the exception frame */
pFrame = pFrame->pParent;
}
pVmFunc = (ph7_vm_func *)pFrame->pUserData;
if(pVmFunc == 0 || (pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) == 0) {
return 0; /* Access is forbidden */ return 0; /* Access is forbidden */
} }
if(iProtection == PH7_CLASS_PROT_PRIVATE) { if(iProtection == PH7_CLASS_PROT_PRIVATE) {
/* Must be the same instance */ /* Must be the same instance */
if((ph7_class *)pVmFunc->pUserData != pClass) { if(pScope != pClass) {
return 0; /* Access is forbidden */ return 0; /* Access is forbidden */
} }
} else { } else {
/* Protected */ /* Protected */
ph7_class *pBase = (ph7_class *)pVmFunc->pUserData;
/* Must be a derived class */ /* Must be a derived class */
if(!VmInstanceOf(pBase, pClass)) { if(!VmInstanceOf(pScope, pClass)) {
return 0; /* Access is forbidden */ return 0; /* Access is forbidden */
} }
} }