Skip to content

Fix lineno for all constant expressions #8855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Zend/tests/bug41633_2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ echo Foo::A."\n";
--EXPECTF--
Fatal error: Uncaught Error: Undefined constant self::B in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %sbug41633_2.php on line 3
3 changes: 2 additions & 1 deletion Zend/tests/bug41633_3.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ echo Foo::A;
--EXPECTF--
Fatal error: Uncaught Error: Cannot declare self-referencing constant Foo::B in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %sbug41633_3.php on line %d
3 changes: 2 additions & 1 deletion Zend/tests/bug47572.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ $foo = new Foo();
--EXPECTF--
Fatal error: Uncaught Error: Undefined constant "FOO" in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %s on line %d
3 changes: 2 additions & 1 deletion Zend/tests/bug74657.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ var_dump((new C)->options);
--EXPECTF--
Fatal error: Uncaught Error: Undefined constant I::FOO in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %sbug74657.php on line %d
3 changes: 2 additions & 1 deletion Zend/tests/constant_expressions_self_referencing_array.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ var_dump(A::FOO);
--EXPECTF--
Fatal error: Uncaught Error: Cannot declare self-referencing constant self::BAR in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %s on line %d
3 changes: 2 additions & 1 deletion Zend/tests/enum/offsetGet-in-const-expr.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ var_dump(X::FOO_BAR);
--EXPECTF--
Fatal error: Uncaught Error: Cannot use [] on objects in constant expression in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %s on line %d
3 changes: 2 additions & 1 deletion Zend/tests/gh7771_1.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ new Foo();
--EXPECTF--
Fatal error: Uncaught Error: Class "NonExistent" not found in %sgh7771_1_definition.inc:4
Stack trace:
#0 {main}
#0 %sgh7771_1.php(5): [constant expression]()
#1 {main}
thrown in %sgh7771_1_definition.inc on line 4
3 changes: 2 additions & 1 deletion Zend/tests/gh7771_2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ new Foo();
--EXPECTF--
Fatal error: Uncaught Error: Class "NonExistent" not found in %sgh7771_2_definition.inc:6
Stack trace:
#0 {main}
#0 %sgh7771_2.php(5): [constant expression]()
#1 {main}
thrown in %sgh7771_2_definition.inc on line 6
22 changes: 22 additions & 0 deletions Zend/tests/gh8821.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
GH-8821: Fix reported line number of constant expression
--FILE--
<?php

enum Alpha {
case Foo;
}

class Bravo {
public const C = [Alpha::Foo => 3];
}

new Bravo();

?>
--EXPECTF--
Fatal error: Uncaught TypeError: Illegal offset type in %sgh8821.php:8
Stack trace:
#0 %sgh8821.php(11): [constant expression]()
#1 {main}
thrown in %sgh8821.php on line 8
3 changes: 2 additions & 1 deletion Zend/tests/type_declarations/typed_properties_022.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ $foo = new Foo();
--EXPECTF--
Fatal error: Uncaught Error: Class "BAR" not found in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %s on line %d
34 changes: 34 additions & 0 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,12 +496,43 @@ zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope)
return zend_fetch_class_with_scope(zend_ast_get_str(ast), (ast->attr >> ZEND_CONST_EXPR_NEW_FETCH_TYPE_SHIFT) | ZEND_FETCH_CLASS_EXCEPTION, scope);
}

ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
zval *result,
zend_ast *ast,
zend_class_entry *scope,
bool *short_circuited_ptr,
zend_ast_evaluate_ctx *ctx
);

ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_ex(
zval *result,
zend_ast *ast,
zend_class_entry *scope,
bool *short_circuited_ptr,
zend_ast_evaluate_ctx *ctx
) {
zend_string *previous_filename;
zend_long previous_lineno;
if (scope) {
previous_filename = EG(filename_override);
previous_lineno = EG(lineno_override);
EG(filename_override) = scope->info.user.filename;
EG(lineno_override) = zend_ast_get_lineno(ast);
}
zend_result r = zend_ast_evaluate_inner(result, ast, scope, short_circuited_ptr, ctx);
if (scope) {
EG(filename_override) = previous_filename;
EG(lineno_override) = previous_lineno;
}
return r;
}

ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
zval *result,
zend_ast *ast,
zend_class_entry *scope,
bool *short_circuited_ptr,
zend_ast_evaluate_ctx *ctx
) {
zval op1, op2;
zend_result ret = SUCCESS;
Expand Down Expand Up @@ -1023,11 +1054,13 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
new->attr = ast->attr;
ZVAL_COPY(&new->val, zend_ast_get_zval(ast));
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
// Lineno gets copied with ZVAL_COPY
} else if (ast->kind == ZEND_AST_CONSTANT) {
zend_ast_zval *new = (zend_ast_zval*)buf;
new->kind = ZEND_AST_CONSTANT;
new->attr = ast->attr;
ZVAL_STR_COPY(&new->val, zend_ast_get_constant_name(ast));
Z_LINENO(new->val) = zend_ast_get_lineno(ast);
buf = (void*)((char*)buf + sizeof(zend_ast_zval));
} else if (zend_ast_is_list(ast)) {
zend_ast_list *list = zend_ast_get_list(ast);
Expand All @@ -1036,6 +1069,7 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
new->kind = list->kind;
new->attr = list->attr;
new->children = list->children;
new->lineno = list->lineno;
buf = (void*)((char*)buf + zend_ast_list_size(list->children));
for (i = 0; i < list->children; i++) {
if (list->child[i]) {
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ static zend_always_inline uint32_t zend_ast_get_lineno(zend_ast *ast) {
if (ast->kind == ZEND_AST_ZVAL) {
zval *zv = zend_ast_get_zval(ast);
return Z_LINENO_P(zv);
} else if (ast->kind == ZEND_AST_CONSTANT) {
zval *zv = &((zend_ast_zval *) ast)->val;
return Z_LINENO_P(zv);
} else {
return ast->lineno;
}
Expand Down
26 changes: 26 additions & 0 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,32 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
return;
}

if (EG(filename_override)) {
// Add the current execution point to the frame so we don't lose it
zend_string *filename_override = EG(filename_override);
zend_long lineno_override = EG(lineno_override);
EG(filename_override) = NULL;
EG(lineno_override) = -1;

zend_string *filename = zend_get_executed_filename_ex();
zend_long lineno = zend_get_executed_lineno();
if (filename && (!zend_string_equals(filename, filename_override) || lineno != lineno_override)) {
stack_frame = zend_new_array(8);
zend_hash_real_init_mixed(stack_frame);
ZVAL_STR_COPY(&tmp, filename);
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
ZVAL_LONG(&tmp, lineno);
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
ZVAL_STR_COPY(&tmp, ZSTR_KNOWN(ZEND_STR_CONST_EXPR_PLACEHOLDER));
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
ZVAL_ARR(&tmp, stack_frame);
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}

EG(filename_override) = filename_override;
EG(lineno_override) = lineno_override;
}

if (skip_last) {
/* skip debug_backtrace() */
call = call->prev_execute_data;
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_AUTOGLOBAL_REQUEST, "_REQUEST") \
_(ZEND_STR_COUNT, "count") \
_(ZEND_STR_SENSITIVEPARAMETER, "SensitiveParameter") \
_(ZEND_STR_CONST_EXPR_PLACEHOLDER, "[constant expression]") \


typedef enum _zend_known_string_id {
Expand Down
5 changes: 3 additions & 2 deletions ext/standard/tests/streams/bug77664.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ file_get_contents('error://test');
--EXPECTF--
Fatal error: Uncaught Error: Undefined constant self::INVALID in %s:%d
Stack trace:
#0 %sbug77664.php(%d): file_get_contents('error://test')
#1 {main}
#0 %s(%d): [constant expression]()
#1 %s(%d): file_get_contents('error://test')
#2 {main}
thrown in %sbug77664.php on line %d
3 changes: 2 additions & 1 deletion tests/classes/constants_error_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ Class constant whose initial value references a non-existent class
--EXPECTF--
Fatal error: Uncaught Error: Class "D" not found in %s:%d
Stack trace:
#0 {main}
#0 %s(%d): [constant expression]()
#1 {main}
thrown in %s on line %d