Restrict require to global scope and track required files independently
Build / AerScript (push) Successful in 40s

This commit is contained in:
2026-10-24 23:53:53 +02:00
parent b513add46b
commit c42b0ae010
5 changed files with 76 additions and 23 deletions
-1
View File
@@ -4998,7 +4998,6 @@ static const LangConstruct aLangConstruct[] = {
{ PH7_KEYWORD_GOTO, PH7_CompileGoto }, /* goto statement */
{ PH7_KEYWORD_CONST, PH7_CompileConstant }, /* const statement */
{ PH7_KEYWORD_INCLUDE, PH7_CompileInclude }, /* include statement */
{ PH7_KEYWORD_REQUIRE, PH7_CompileInclude }, /* require statement */
};
/*
* Return a pointer to the global scope handler routine associated
+5 -1
View File
@@ -3024,7 +3024,11 @@ PH7_PRIVATE void *PH7_StreamOpenHandle(ph7_vm *pVm, const ph7_io_stream *pStream
if(rc == PH7_OK) {
if(bPushInclude) {
/* Mark as included */
PH7_VmPushFilePath(pVm, sFilePath, -1, FALSE, pNew);
rc = PH7_VmPushFilePath(pVm, sFilePath, -1, FALSE, pNew);
if(rc != SXRET_OK) {
PH7_StreamCloseHandle(pStream, pHandle);
return 0;
}
}
}
} else {
+69 -20
View File
@@ -1507,6 +1507,10 @@ PH7_PRIVATE sxi32 PH7_VmInit(
SySetInit(&pVm->aFiles, &pVm->sAllocator, sizeof(SyString));
SySetInit(&pVm->aPaths, &pVm->sAllocator, sizeof(SyString));
SySetInit(&pVm->aIncluded, &pVm->sAllocator, sizeof(SyString));
rc = SyHashInit(&pVm->hRequired, &pVm->sAllocator, SyStrHash, (int (*)(const void *, const void *, sxu32))SyMemcmp);
if(rc != SXRET_OK) {
goto Err;
}
SySetInit(&pVm->aOB, &pVm->sAllocator, sizeof(VmObEntry));
SySetInit(&pVm->aIOstream, &pVm->sAllocator, sizeof(ph7_io_stream *));
/* Error callbacks containers */
@@ -2361,6 +2365,8 @@ PH7_PRIVATE sxi32 PH7_VmThrowError(
sxu32 nLine;
SyString sFileName;
SyString *pFile;
/* Included global code has no execution trace to populate this set. */
SySetInit(&pDebug, &pVm->sAllocator, sizeof(VmDebugTrace));
if((pVm->nMagic == PH7_VM_EXEC) && (VmExtractDebugTrace(&(*pVm), &pDebug) == SXRET_OK) && (SySetUsed(&pDebug) > 0)) {
/* Extract file name and line number from debug trace */
SySetGetNextEntry(&pDebug, (void **)&pTrace);
@@ -9329,11 +9335,17 @@ static sxi32 VmEvalChunk(
int iFlags /* Code evaluation flag */
) {
SySet *pByteCode, aByteCode;
sxi32 rc = SXRET_OK;
sxi32 bRequire = (iFlags & (PH7_AERSCRIPT_CODE | PH7_AERSCRIPT_FILE)) ==
(PH7_AERSCRIPT_CODE | PH7_AERSCRIPT_FILE);
ProcConsumer xErr = 0;
void *pErrData = 0;
/* Initialize bytecode container */
SySetInit(&aByteCode, &pVm->sAllocator, sizeof(VmInstr));
SySetAlloc(&aByteCode, 0x20);
rc = SySetAlloc(&aByteCode, 0x20);
if(rc != SXRET_OK && bRequire) {
return rc;
}
/* Log compile-time errors */
xErr = pVm->pEngine->xConf.xErr;
pErrData = pVm->pEngine->xConf.pErrData;
@@ -9346,13 +9358,17 @@ static sxi32 VmEvalChunk(
PH7_VmPushFilePath(pVm, "[MEMORY]", -1, TRUE, 0);
}
/* Compile the chunk */
PH7_CompileAerScript(pVm, pChunk, iFlags);
rc = PH7_CompileAerScript(pVm, pChunk, iFlags);
if(rc != SXRET_OK && bRequire) {
goto Cleanup;
}
ph7_value sResult; /* Return value */
SyHashEntry *pEntry;
/* Initialize and install static and constants class attributes */
SyHashResetLoopCursor(&pVm->hClass);
while((pEntry = SyHashGetNextEntry(&pVm->hClass)) != 0) {
if(VmMountUserClass(&(*pVm), (ph7_class *)pEntry->pUserData) != SXRET_OK) {
rc = VmMountUserClass(&(*pVm), (ph7_class *)pEntry->pUserData);
if(rc != SXRET_OK) {
if(pCtx) {
ph7_result_bool(pCtx, 0);
}
@@ -9360,6 +9376,7 @@ static sxi32 VmEvalChunk(
}
}
if(SXRET_OK != PH7_VmEmitInstr(pVm, 0, PH7_OP_DONE, 0, 0, 0, 0)) {
rc = SXERR_MEM;
/* Out of memory */
if(pCtx) {
ph7_result_bool(pCtx, 0);
@@ -9369,7 +9386,7 @@ static sxi32 VmEvalChunk(
/* Assume a boolean true return value */
PH7_MemObjInitFromBool(pVm, &sResult, 1);
/* Execute the compiled chunk */
VmLocalExec(pVm, &aByteCode, &sResult);
rc = VmLocalExec(pVm, &aByteCode, &sResult);
if(pCtx) {
/* Set the execution result */
ph7_result_value(pCtx, &sResult);
@@ -9379,7 +9396,7 @@ Cleanup:
/* Cleanup the mess left behind */
pVm->pByteContainer = pByteCode;
SySetRelease(&aByteCode);
return SXRET_OK;
return bRequire ? rc : SXRET_OK;
}
/*
* value eval(string $code)
@@ -9477,7 +9494,14 @@ PH7_PRIVATE sxi32 PH7_VmPushFilePath(ph7_vm *pVm, const char *zPath, int nLen, s
*pNew = 1;
}
}
SySetPut(&pVm->aFiles, (const void *)&sPath);
rc = SySetPut(&pVm->aFiles, (const void *)&sPath);
if(rc != SXRET_OK) {
if(!bMain && *pNew) {
SySetPop(&pVm->aIncluded);
}
SyMemBackendFree(&pVm->sAllocator, zDup);
return rc;
}
return SXRET_OK;
}
/*
@@ -9487,8 +9511,8 @@ PH7_PRIVATE sxi32 PH7_VmPushFilePath(ph7_vm *pVm, const char *zPath, int nLen, s
* Note that the PHP script to evaluate can be a local or remote file.In
* either cases the [PH7_StreamReadWholeFile()] function handle all the underlying
* operations.
* Refer to the implementation of the include(),include_once() language
* constructs for more information.
* Include evaluates a method chunk; require evaluates global code once per VM,
* independently of the include history.
*/
static sxi32 VmExecIncludedFile(
ph7_vm *pVm, /* Underlying Virtual Machine */
@@ -9500,6 +9524,8 @@ static sxi32 VmExecIncludedFile(
SyBlob sContents;
void *pHandle;
int isNew;
SyString sRequired;
SyHashEntry *pRequired = 0;
/* Initialize fields */
SyBlobInit(&sContents, &pVm->sAllocator);
isNew = 0;
@@ -9514,21 +9540,44 @@ static sxi32 VmExecIncludedFile(
return SXERR_IO;
}
rc = SXRET_OK; /* Stupid cc warning */
if(iFlags & PH7_AERSCRIPT_CODE && !isNew) {
/* Already included (required) */
rc = SXERR_EXISTS;
} else {
/* Read the whole file contents */
rc = PH7_StreamReadWholeFile(pHandle, pStream, &sContents);
if(iFlags & PH7_AERSCRIPT_CODE) {
/* The loader owns these bytes until VM release. Do not use the spelling
* from the statement, or the independent include history, as the key. */
sRequired = *(SyString *)SySetPeek(&pVm->aFiles);
pRequired = SyHashGet(&pVm->hRequired, sRequired.zString, sRequired.nByte);
if(pRequired) {
PH7_VmThrowError(pVm, PH7_CTX_WARNING, pRequired->pUserData ?
"File is already being required: '%z'" : "File already required: '%z'", &sRequired);
rc = SXERR_EXISTS;
goto Cleanup;
}
/* Publish before compilation/execution so recursive require cannot
* redeclare the same file. Failed evaluations are not remembered. */
rc = SyHashInsert(&pVm->hRequired, sRequired.zString, sRequired.nByte, pVm);
if(rc != SXRET_OK) {
goto Cleanup;
}
pRequired = SyHashGet(&pVm->hRequired, sRequired.zString, sRequired.nByte);
}
/* Read the whole file contents */
rc = PH7_StreamReadWholeFile(pHandle, pStream, &sContents);
if(rc == SXRET_OK) {
SyString sScript;
sxu32 nMagic = pVm->nMagic;
/* Compile and execute the script */
SyStringInitFromBuf(&sScript, SyBlobData(&sContents), SyBlobLength(&sContents));
pVm->nMagic = PH7_VM_INCL;
rc = VmEvalChunk(pVm, 0, &sScript, iFlags);
pVm->nMagic = (iFlags & PH7_AERSCRIPT_CODE) ? nMagic : PH7_VM_EXEC;
}
if(pRequired) {
if(rc == SXRET_OK) {
SyString sScript;
/* Compile and execute the script */
SyStringInitFromBuf(&sScript, SyBlobData(&sContents), SyBlobLength(&sContents));
pVm->nMagic = PH7_VM_INCL;
VmEvalChunk(pVm, 0, &sScript, iFlags);
pVm->nMagic = PH7_VM_EXEC;
pRequired->pUserData = 0;
} else {
SyHashDeleteEntry(&pVm->hRequired, sRequired.zString, sRequired.nByte, 0);
}
}
Cleanup:
/* Close the handle */
PH7_StreamCloseHandle(pStream, pHandle);
/* Release the working buffer */
+1
View File
@@ -1208,6 +1208,7 @@ struct ph7_vm {
SySet aFiles; /* Stack of processed files */
SySet aPaths; /* Set of import paths */
SySet aIncluded; /* Set of included files */
SyHash hRequired; /* Resolved require paths, including pending evaluations */
SySet aOB; /* Stackable output buffers */
SySet aAutoLoad; /* Stack of class autoload callbacks */
SySet aShutdown; /* Stack of shutdown user callbacks */
+1 -1
View File
@@ -1,10 +1,10 @@
require 'data/includes/base_class.aer';
require 'data/includes/test_class.aer';
class Program extends BaseClass {
void main() {
$this->run();
require 'data/includes/test_class.aer';
object $test = new Test();
var_dump($test);
}