Skip to content

Commit bc057c1

Browse files
committed
Fix lineno for all constant expressions
Fixes GH-8821
1 parent 3663f76 commit bc057c1

17 files changed

+102
-24
lines changed

Zend/tests/bug41633_2.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ echo Foo::A."\n";
1010
--EXPECTF--
1111
Fatal error: Uncaught Error: Undefined constant self::B in %s:%d
1212
Stack trace:
13-
#0 {main}
13+
#0 %s(%d): [constant expression]()
14+
#1 {main}
1415
thrown in %sbug41633_2.php on line 3

Zend/tests/bug41633_3.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ echo Foo::A;
1111
--EXPECTF--
1212
Fatal error: Uncaught Error: Cannot declare self-referencing constant Foo::B in %s:%d
1313
Stack trace:
14-
#0 {main}
14+
#0 %s(%d): [constant expression]()
15+
#1 {main}
1516
thrown in %sbug41633_3.php on line %d

Zend/tests/bug47572.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ $foo = new Foo();
1616
--EXPECTF--
1717
Fatal error: Uncaught Error: Undefined constant "FOO" in %s:%d
1818
Stack trace:
19-
#0 {main}
19+
#0 %s(%d): [constant expression]()
20+
#1 {main}
2021
thrown in %s on line %d

Zend/tests/bug74657.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ var_dump((new C)->options);
2121
--EXPECTF--
2222
Fatal error: Uncaught Error: Undefined constant I::FOO in %s:%d
2323
Stack trace:
24-
#0 {main}
24+
#0 %s(%d): [constant expression]()
25+
#1 {main}
2526
thrown in %sbug74657.php on line %d

Zend/tests/constant_expressions_self_referencing_array.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ var_dump(A::FOO);
1111
--EXPECTF--
1212
Fatal error: Uncaught Error: Cannot declare self-referencing constant self::BAR in %s:%d
1313
Stack trace:
14-
#0 {main}
14+
#0 %s(%d): [constant expression]()
15+
#1 {main}
1516
thrown in %s on line %d

Zend/tests/enum/offsetGet-in-const-expr.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ var_dump(X::FOO_BAR);
2525
--EXPECTF--
2626
Fatal error: Uncaught Error: Cannot use [] on objects in constant expression in %s:%d
2727
Stack trace:
28-
#0 {main}
28+
#0 %s(%d): [constant expression]()
29+
#1 {main}
2930
thrown in %s on line %d

Zend/tests/gh7771_1.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ new Foo();
1111
--EXPECTF--
1212
Fatal error: Uncaught Error: Class "NonExistent" not found in %sgh7771_1_definition.inc:4
1313
Stack trace:
14-
#0 {main}
14+
#0 %sgh7771_1.php(5): [constant expression]()
15+
#1 {main}
1516
thrown in %sgh7771_1_definition.inc on line 4

Zend/tests/gh7771_2.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ new Foo();
1111
--EXPECTF--
1212
Fatal error: Uncaught Error: Class "NonExistent" not found in %sgh7771_2_definition.inc:6
1313
Stack trace:
14-
#0 {main}
14+
#0 %sgh7771_2.php(5): [constant expression]()
15+
#1 {main}
1516
thrown in %sgh7771_2_definition.inc on line 6

Zend/tests/gh8821.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-8821: Fix reported line number of constant expression
3+
--FILE--
4+
<?php
5+
6+
enum Alpha {
7+
case Foo;
8+
}
9+
10+
class Bravo {
11+
public const C = [Alpha::Foo => 3];
12+
}
13+
14+
new Bravo();
15+
16+
?>
17+
--EXPECTF--
18+
Fatal error: Uncaught TypeError: Illegal offset type in %sgh8821.php:8
19+
Stack trace:
20+
#0 %sgh8821.php(11): [constant expression]()
21+
#1 {main}
22+
thrown in %sgh8821.php on line 8

Zend/tests/type_declarations/typed_properties_022.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ $foo = new Foo();
1111
--EXPECTF--
1212
Fatal error: Uncaught Error: Class "BAR" not found in %s:%d
1313
Stack trace:
14-
#0 {main}
14+
#0 %s(%d): [constant expression]()
15+
#1 {main}
1516
thrown in %s on line %d

Zend/zend_ast.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,9 @@ zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope)
498498
return zend_fetch_class_with_scope(zend_ast_get_str(ast), ast->attr | ZEND_FETCH_CLASS_EXCEPTION, scope);
499499
}
500500

501-
static zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *ast, zend_class_entry *scope, bool *short_circuited_ptr)
501+
static zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *ast, zend_class_entry *scope, bool *short_circuited_ptr);
502+
503+
static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(zval *result, zend_ast *ast, zend_class_entry *scope, bool *short_circuited_ptr)
502504
{
503505
zval op1, op2;
504506
zend_result ret = SUCCESS;
@@ -801,8 +803,6 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *as
801803
{
802804
zend_string *class_name = zend_ast_get_str(ast->child[0]);
803805
zend_string *const_name = zend_ast_get_str(ast->child[1]);
804-
zval *zv;
805-
bool bailout = 0;
806806

807807
zend_string *previous_filename;
808808
zend_long previous_lineno;
@@ -812,18 +812,11 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *as
812812
EG(filename_override) = scope->info.user.filename;
813813
EG(lineno_override) = zend_ast_get_lineno(ast);
814814
}
815-
zend_try {
816-
zv = zend_get_class_constant_ex(class_name, const_name, scope, ast->attr);
817-
} zend_catch {
818-
bailout = 1;
819-
} zend_end_try();
815+
zval *zv = zend_get_class_constant_ex(class_name, const_name, scope, ast->attr);
820816
if (scope) {
821817
EG(filename_override) = previous_filename;
822818
EG(lineno_override) = previous_lineno;
823819
}
824-
if (bailout) {
825-
zend_bailout();
826-
}
827820

828821
if (UNEXPECTED(zv == NULL)) {
829822
ZVAL_UNDEF(result);
@@ -983,6 +976,24 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *as
983976
return ret;
984977
}
985978

979+
static zend_result ZEND_FASTCALL zend_ast_evaluate_ex(zval *result, zend_ast *ast, zend_class_entry *scope, bool *short_circuited_ptr)
980+
{
981+
zend_string *previous_filename;
982+
zend_long previous_lineno;
983+
if (scope) {
984+
previous_filename = EG(filename_override);
985+
previous_lineno = EG(lineno_override);
986+
EG(filename_override) = scope->info.user.filename;
987+
EG(lineno_override) = zend_ast_get_lineno(ast);
988+
}
989+
zend_result r = zend_ast_evaluate_inner(result, ast, scope, short_circuited_ptr);
990+
if (scope) {
991+
EG(filename_override) = previous_filename;
992+
EG(lineno_override) = previous_lineno;
993+
}
994+
return r;
995+
}
996+
986997
ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope)
987998
{
988999
bool short_circuited;
@@ -1026,11 +1037,13 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
10261037
new->attr = ast->attr;
10271038
ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
10281039
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
1040+
// Lineno gets copied with ZVAL_COPY
10291041
} else if (ast->kind == ZEND_AST_CONSTANT) {
10301042
zend_ast_zval *new = (zend_ast_zval*)buf;
10311043
new->kind = ZEND_AST_CONSTANT;
10321044
new->attr = ast->attr;
10331045
ZVAL_STR_COPY(&new->val, zend_ast_get_constant_name(ast));
1046+
Z_LINENO(new->val) = zend_ast_get_lineno(ast);
10341047
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
10351048
} else if (zend_ast_is_list(ast)) {
10361049
zend_ast_list *list = zend_ast_get_list(ast);
@@ -1039,6 +1052,7 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
10391052
new->kind = list->kind;
10401053
new->attr = list->attr;
10411054
new->children = list->children;
1055+
new->lineno = list->lineno;
10421056
buf = (void*)((char*)buf + zend_ast_list_size(list->children));
10431057
for (i = 0; i < list->children; i++) {
10441058
if (list->child[i]) {

Zend/zend_ast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ static zend_always_inline uint32_t zend_ast_get_lineno(zend_ast *ast) {
347347
if (ast->kind == ZEND_AST_ZVAL) {
348348
zval *zv = zend_ast_get_zval(ast);
349349
return Z_LINENO_P(zv);
350+
} else if (ast->kind == ZEND_AST_CONSTANT) {
351+
zval *zv = &((zend_ast_zval *) ast)->val;
352+
return Z_LINENO_P(zv);
350353
} else {
351354
return ast->lineno;
352355
}

Zend/zend_builtin_functions.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,32 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
17201720
return;
17211721
}
17221722

1723+
if (EG(filename_override)) {
1724+
// Add the current execution point to the frame so we don't lose it
1725+
zend_string *filename_override = EG(filename_override);
1726+
zend_long lineno_override = EG(lineno_override);
1727+
EG(filename_override) = NULL;
1728+
EG(lineno_override) = -1;
1729+
1730+
zend_string *filename = zend_get_executed_filename_ex();
1731+
zend_long lineno = zend_get_executed_lineno();
1732+
if (filename && (!zend_string_equals(filename, filename_override) || lineno != lineno_override)) {
1733+
stack_frame = zend_new_array(8);
1734+
zend_hash_real_init_mixed(stack_frame);
1735+
ZVAL_STR_COPY(&tmp, filename);
1736+
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1737+
ZVAL_LONG(&tmp, lineno);
1738+
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1739+
ZVAL_STR_COPY(&tmp, ZSTR_KNOWN(ZEND_STR_CONST_EXPR_PLACEHOLDER));
1740+
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1741+
ZVAL_ARR(&tmp, stack_frame);
1742+
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
1743+
}
1744+
1745+
EG(filename_override) = filename_override;
1746+
EG(lineno_override) = lineno_override;
1747+
}
1748+
17231749
if (skip_last) {
17241750
/* skip debug_backtrace() */
17251751
call = call->prev_execute_data;

Zend/zend_execute_API.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,8 @@ void shutdown_executor(void) /* {{{ */
472472
efree(EG(ht_iterators));
473473
}
474474

475-
ZEND_ASSERT(EG(filename_override) == NULL);
475+
EG(filename_override) = NULL;
476+
EG(lineno_override) = -1;
476477
}
477478

478479
#if ZEND_DEBUG

Zend/zend_string.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
593593
_(ZEND_STR_AUTOGLOBAL_REQUEST, "_REQUEST") \
594594
_(ZEND_STR_COUNT, "count") \
595595
_(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \
596+
_(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \
596597

597598

598599
typedef enum _zend_known_string_id {

ext/standard/tests/streams/bug77664.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ file_get_contents('error://test');
1212
--EXPECTF--
1313
Fatal error: Uncaught Error: Undefined constant self::INVALID in %s:%d
1414
Stack trace:
15-
#0 %sbug77664.php(%d): file_get_contents('error://test')
16-
#1 {main}
15+
#0 %s(%d): [constant expression]()
16+
#1 %s(%d): file_get_contents('error://test')
17+
#2 {main}
1718
thrown in %sbug77664.php on line %d

tests/classes/constants_error_004.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ Class constant whose initial value references a non-existent class
1212
--EXPECTF--
1313
Fatal error: Uncaught Error: Class "D" not found in %s:%d
1414
Stack trace:
15-
#0 {main}
15+
#0 %s(%d): [constant expression]()
16+
#1 {main}
1617
thrown in %s on line %d

0 commit comments

Comments
 (0)