Skip to content

Commit 22aeec7

Browse files
committed
Fix GH-18105: Wrong file & line on exception trace with trait default parameter
When a trait method has a default parameter using `new` and the constructor throws, the exception's file/line pointed to the class using the trait rather than where the throw actually occurred. `EG(filename_override)`, set to the scope's filename during AST evaluation, leaked into the constructor's VM re-entry. Clear the override before constructor calls in `zend_ast_evaluate_inner`'s ZEND_AST_NEW handler so normal stack frame resolution applies. Closes GH-18105
1 parent 6d62d87 commit 22aeec7

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

Zend/tests/gh18105.phpt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
GH-18105 (Wrong line & file on error trace with trait default parameter)
3+
--FILE--
4+
<?php
5+
6+
file_put_contents(__DIR__ . '/gh18105_defs.inc', <<<'PHP'
7+
<?php
8+
class ThrowableParam {
9+
public function __construct() {
10+
throw new Exception('thrown here');
11+
}
12+
}
13+
trait TraitInASeparateFile {
14+
public function execute(ThrowableParam $param = new ThrowableParam): void {}
15+
}
16+
PHP);
17+
18+
include __DIR__ . '/gh18105_defs.inc';
19+
20+
class Foo {
21+
use TraitInASeparateFile;
22+
}
23+
24+
try {
25+
(new Foo)->execute();
26+
} catch (Exception $e) {
27+
echo basename($e->getFile()), "\n";
28+
echo $e->getLine(), "\n";
29+
}
30+
?>
31+
--CLEAN--
32+
<?php
33+
@unlink(__DIR__ . '/gh18105_defs.inc');
34+
?>
35+
--EXPECT--
36+
gh18105_defs.inc
37+
4

Zend/zend_ast.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,8 +1099,14 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10991099

11001100
zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
11011101
if (ctor) {
1102+
zend_string *prev_filename = EG(filename_override);
1103+
zend_long prev_lineno = EG(lineno_override);
1104+
EG(filename_override) = NULL;
1105+
EG(lineno_override) = -1;
11021106
zend_call_known_function(
11031107
ctor, Z_OBJ_P(result), Z_OBJCE_P(result), NULL, 0, NULL, args);
1108+
EG(filename_override) = prev_filename;
1109+
EG(lineno_override) = prev_lineno;
11041110
}
11051111

11061112
zend_array_destroy(args);
@@ -1120,8 +1126,14 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
11201126

11211127
zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
11221128
if (ctor) {
1129+
zend_string *prev_filename = EG(filename_override);
1130+
zend_long prev_lineno = EG(lineno_override);
1131+
EG(filename_override) = NULL;
1132+
EG(lineno_override) = -1;
11231133
zend_call_known_instance_method(
11241134
ctor, Z_OBJ_P(result), NULL, args_ast->children, args);
1135+
EG(filename_override) = prev_filename;
1136+
EG(lineno_override) = prev_lineno;
11251137
}
11261138

11271139
for (uint32_t i = 0; i < args_ast->children; i++) {

0 commit comments

Comments
 (0)