fix: cover eval error lifecycle regressions

pull/41/head
韩天峰 4 weeks ago
parent 9b0b3c1d83
commit c46a9ddbf2
  1. 40
      phpunit/src/ServerEnvironmentTest.php
  2. 10
      run-tests.php
  3. 4
      src/Translator.php
  4. 16
      tests/compiler/exception/main-eval-error-lifecycle.phpt

@ -43,18 +43,42 @@ class ServerEnvironmentTest extends TestCase
$method = new ReflectionMethod(Translator::class, 'registerServerEnvironment');
$code = $method->invoke($compiler, 'C:\\project\\"quoted"\\main.php');
$this->assertStringContainsString(
'const char *value = "' . $compiler->escapeString('C:\\project\\"quoted"\\main.php') . '";',
$code
);
$this->assertStringContainsString('php::Var &_SERVER = _global_var__SERVER;', $code);
$this->assertStringContainsString('php::Str php_self = "PHP_SELF";', $code);
$this->assertStringContainsString('php::Str script_name = "SCRIPT_NAME";', $code);
$this->assertStringContainsString('php::Str script_filename = "SCRIPT_FILENAME";', $code);
$this->assertStringContainsString('php::Str path_translated = "PATH_TRANSLATED";', $code);
$this->assertStringContainsString('php::Str document_root = "DOCUMENT_ROOT";', $code);
$this->assertStringContainsString('_SERVER.item("PHP_SELF", true) = value;', $code);
$this->assertStringContainsString('_SERVER.item("SCRIPT_NAME", true) = value;', $code);
$this->assertStringContainsString('_SERVER.item("SCRIPT_FILENAME", true) = value;', $code);
$this->assertStringContainsString('_SERVER.item("PATH_TRANSLATED", true) = value;', $code);
$this->assertStringContainsString('_SERVER.item("DOCUMENT_ROOT", true) = "";', $code);
$this->assertStringNotContainsString('php::Str', $code);
}
public function testCaseInsensitiveMainWrapperInitializesServerEnvironment(): void
{
global $translator;
$previousTranslator = $translator ?? null;
$file = $this->testDir . '/uppercase-main.php';
file_put_contents($file, "<?php\nfunction MAIN(): void {}\n");
try {
$compiler = CompilerTest::create($this->testDir);
$translator = $compiler;
$compiler->addFiles([$file]);
$compiler->prepareFile($file);
$cppFile = $compiler->convertFile($file);
$code = file_get_contents($cppFile);
} finally {
$translator = $previousTranslator;
}
$this->assertStringContainsString(
'php::Str value = "' . $compiler->escapeString('C:\\project\\"quoted"\\main.php') . '";',
'const char *value = "' . $compiler->escapeString(realpath($file)) . '";',
$code
);
$this->assertStringContainsString('_SERVER.item(path_translated, true) = value;', $code);
$this->assertStringContainsString('_SERVER.item(document_root, true) = "";', $code);
$this->assertStringContainsString('_SERVER.item("PHP_SELF", true) = value;', $code);
}
public function testServerGlobalIsForcedOnlyForBinaryBuilds(): void

@ -2427,7 +2427,8 @@ TEST $file
global $no_aot;
if (!$no_aot) {
try {
$bin_file = compile_php_file($test_file);
$aot_args = $test->hasSection('AOT_ARGS') ? trim($test->getSection('AOT_ARGS')) : '';
$bin_file = compile_php_file($test_file, $aot_args);
} catch (Throwable $e) {
$compileOutput = trim($e instanceof CompilationFailureException ? $e->getCompilerOutput() : '');
$message = $e->getMessage();
@ -3740,7 +3741,7 @@ class TestFile
private const ALLOWED_SECTIONS = [
'EXPECT', 'EXPECTF', 'EXPECTREGEX', 'EXPECTREGEX_EXTERNAL', 'EXPECT_EXTERNAL', 'EXPECTF_EXTERNAL', 'EXPECTHEADERS',
'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS',
'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS', 'AOT_ARGS',
'FILE', 'FILEEOF', 'FILE_EXTERNAL', 'REDIRECTTEST',
'CAPTURE_STDIO', 'STDIN', 'CGI', 'PHPDBG',
'INI', 'ENV', 'EXTENSIONS',
@ -4240,7 +4241,7 @@ function debug()
exit;
}
function compile_php_file(string $file): string
function compile_php_file(string $file, string $compiler_args = ''): string
{
global $compiler_path;
@ -4269,6 +4270,9 @@ function compile_php_file(string $file): string
if (IS_WINDOWS && str_ends_with($cmd, '.php')) {
$cmd = escapeshellarg(PHP_BINARY) . ' ' . $cmd;
}
if ($compiler_args !== '') {
$cmd .= ' ' . $compiler_args;
}
exec($cmd . ' ' . escapeshellarg($file) . ' 2>&1', $output, $exitCode);
clearstatcache(true, $binary_file);

@ -3215,7 +3215,9 @@ CODE;
$methodArgs = implode(', ', array_merge(['this_'], $implicitMethodArgs));
$callParams = $functionDef->argInfoList ? $methodArgs . ', ' . rtrim($callParams, ',') : $methodArgs;
} else {
if ($this->isBuildModeBin() && $functionDef->name === self::ENTRY_FUNCTION) {
$isEntryFunction = $this->hasFunction(self::ENTRY_FUNCTION)
&& $functionDef === $this->getFunction(self::ENTRY_FUNCTION);
if ($this->isBuildModeBin() && $isEntryFunction) {
// $_SERVER 的初始化必须置于 main 入口函数内,以确保在其被访问前,运行环境及超全局上下文已完全就绪。
$cppCode .= $this->registerServerEnvironment($functionDef->sourceFile);
}

@ -0,0 +1,16 @@
--TEST--
Uncaught main error does not access request memory after php::eval
--AOT_ARGS--
-O2
--FILE--
<?php
function main(): void
{
throw new RuntimeException('main lifecycle error');
}
?>
--EXPECTF--
Fatal error: Uncaught RuntimeException: main lifecycle error in %smain-eval-error-lifecycle.php:%d
Stack trace:
%A
Loading…
Cancel
Save