feat(runtime): enhance AOT exception reporting with source file location

- Add sourceFile and startLine properties to FunctionDef entity
- Track PHP source file and line number during preprocessing
- Generate proper file location context for AOT runtime exceptions
- Implement entry script prefixing with correct line numbers
- Update eval calls to include source file information
- Create test case for main file location reporting in exceptions
pull/17/head
韩天峰 2 months ago
parent d54268fd8d
commit c494622ae4
  1. 7
      examples/error.php
  2. 4
      src/Entity/FunctionDef.php
  3. 2
      src/Preprocessor.php
  4. 11
      src/Translator.php
  5. 21
      tests/aot/exception/main-file-location.phpt

@ -0,0 +1,7 @@
<?php
function main()
{
throw new Exception("test");
}

@ -28,6 +28,10 @@ class FunctionDef
public bool $returnTypeUndeclared = false; public bool $returnTypeUndeclared = false;
public bool $returnsByRef = false; public bool $returnsByRef = false;
public bool $generator = false; public bool $generator = false;
/** Source file containing this function definition. */
public string $sourceFile = '';
/** First source line of this function definition. */
public int $startLine = 1;
/** /**
* @var string 必须是带有命名空间的完整类名 * @var string 必须是带有命名空间的完整类名

@ -495,6 +495,8 @@ class Preprocessor extends CompilerBase
$this->fatalError($v, "The function `{$name}` is a built-in function and cannot be redefined"); $this->fatalError($v, "The function `{$name}` is a built-in function and cannot be redefined");
} }
$functionDef = $this->parseFunctionDecl($v); $functionDef = $this->parseFunctionDecl($v);
$functionDef->sourceFile = $this->file;
$functionDef->startLine = $v->getStartLine();
$this->addFunction($name, $functionDef); $this->addFunction($name, $functionDef);
if ($this->methodDef) { if ($this->methodDef) {
$functionDef->method = true; $functionDef->method = true;

@ -1161,11 +1161,16 @@ CODE;
$code .= 'php_app_init();' . PHP_EOL; $code .= 'php_app_init();' . PHP_EOL;
if ($this->isBuildModeBin()) { if ($this->isBuildModeBin()) {
if (count($this->functions[self::ENTRY_FUNCTION]->argInfoList) == 2) { $entryFunction = $this->functions[self::ENTRY_FUNCTION];
$code .= 'php::eval("global $argc, $argv; main($argc, $argv);");' . PHP_EOL; $entryFile = $entryFunction->sourceFile;
$entryFileArg = $this->genCharPtr($entryFile, true);
$entryPrefix = str_repeat("\n", max(0, $entryFunction->startLine - 1));
if (count($entryFunction->argInfoList) == 2) {
$entryScript = $entryPrefix . 'global $argc, $argv; main($argc, $argv);';
} else { } else {
$code .= 'php::eval("main();");' . PHP_EOL; $entryScript = $entryPrefix . 'main();';
} }
$code .= 'php::eval(' . $this->genCharPtr($entryScript, true) . ', ' . $entryFileArg . ');' . PHP_EOL;
} }
$code .= 'return SUCCESS;' . PHP_EOL; $code .= 'return SUCCESS;' . PHP_EOL;

@ -0,0 +1,21 @@
--TEST--
Uncaught AOT exception uses the PHP file containing main()
--FILE--
<?php
class MainFileLocationExample
{
public function fail(): void
{
throw new RuntimeException('location-test');
}
}
function main(): void
{
(new MainFileLocationExample())->fail();
}
?>
--EXPECTF--
Fatal error: Uncaught RuntimeException: location-test in %smain-file-location.php:10
Stack trace:
%A
Loading…
Cancel
Save