Preserve value references across arena relocation during array copies

This commit is contained in:
2026-10-27 07:39:19 +01:00
parent f74af13f98
commit b1605b0e82
2 changed files with 42 additions and 10 deletions
+28 -8
View File
@@ -399,13 +399,22 @@ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) {
* destination are of the compatible data types.
*/
PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) {
/* Scalar destinations need not have initialized arena metadata. */
ph7_vm *pVm = (pSrc->nType & MEMOBJ_HASHMAP) ? pDest->pVm : 0;
sxu32 nDest = pVm ? pDest->nIdx : SXU32_HIGH;
sxi32 bArena = pVm && SySetAt(&pVm->aMemObj, nDest) == pDest;
if(pDest->nType == 0 || pDest->nType == MEMOBJ_NULL || pDest->nType == pSrc->nType) {
sxu32 nType = pSrc->nType;
PH7_MemObjStore(pSrc, pDest);
/* Array copies can move both source and destination arena slots. */
if(bArena) {
pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest);
}
if(pDest->nType == 0 || pDest->nType == MEMOBJ_NULL) {
if(pSrc->nType == MEMOBJ_NULL) {
if(nType == MEMOBJ_NULL) {
pDest->nType = MEMOBJ_VOID;
} else {
pDest->nType = pSrc->nType;
pDest->nType = nType;
}
}
} else if(pDest->nType & MEMOBJ_MIXED) {
@@ -413,6 +422,9 @@ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) {
/* mixed[] */
if(pSrc->nType & MEMOBJ_HASHMAP) {
PH7_MemObjStore(pSrc, pDest);
if(bArena) {
pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest);
}
pDest->nType |= MEMOBJ_MIXED;
} else if(pSrc->nType & MEMOBJ_NULL) {
PH7_MemObjToHashmap(pSrc);
@@ -946,12 +958,6 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
pObj = (ph7_class_instance *)pDest->x.pOther;
}
SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32)));
if(pSrcMap) {
ph7_hashmap *pMap;
pMap = PH7_NewHashmap(&(*pDest->pVm), 0, 0);
PH7_HashmapDup(pSrcMap, pMap);
pDest->x.pOther = pMap;
}
rc = SXRET_OK;
if(SyBlobLength(&pSrc->sBlob) > 0) {
SyBlobReset(&pDest->sBlob);
@@ -961,6 +967,20 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) {
SyBlobRelease(&pDest->sBlob);
}
}
if(pSrcMap) {
ph7_vm *pVm = pDest->pVm;
sxu32 nDest = pDest->nIdx;
sxi32 bArena = SySetAt(&pVm->aMemObj, nDest) == pDest;
ph7_hashmap *pMap;
/* Finish reading the source before recursive copies relocate aMemObj.
* Stack destinations have no arena slot and must not be rebound. */
pMap = PH7_NewHashmap(pVm, 0, 0);
PH7_HashmapDup(pSrcMap, pMap);
if(bArena) {
pDest = (ph7_value *)SySetAt(&pVm->aMemObj, nDest);
}
pDest->x.pOther = pMap;
}
if(pObj) {
PH7_ClassInstanceUnref(pObj);
}