Skip to content

Commit

Permalink
Fix preloading of constants containing enums
Browse files Browse the repository at this point in the history
  • Loading branch information
iluuu1994 committed Apr 21, 2022
1 parent e9b9fec commit 4397811
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 23 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fixed bug GH-8310 (Registry settings are no longer recognized). (cmb)
. Fixed potential race condition during resource ID allocation. (ryancaicse)
. Fixed bug GH-8133 (Preloading of constants containing arrays with enums
segfaults). (ilutov)

- Date:
. Fixed bug GH-7752 (DateTimeZone::getTransitions() returns insufficient
Expand Down
13 changes: 6 additions & 7 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,12 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
break;
case ZEND_AST_CONST_ENUM_INIT:
{
// Preloading will attempt to resolve constants but objects can't be stored in shm
// Aborting here to store the const AST instead
if (CG(in_compilation)) {
return FAILURE;
}

zend_ast *class_name_ast = ast->child[0];
zend_string *class_name = zend_ast_get_str(class_name_ast);

Expand All @@ -762,13 +768,6 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
: NULL;

zend_class_entry *ce = zend_lookup_class(class_name);
if (!ce) {
/* Class may not be available when resolving constants on a dynamically
* declared enum during preloading. */
ZEND_ASSERT(CG(compiler_options) & ZEND_COMPILE_PRELOAD);
return FAILURE;
}

zend_enum_new(result, ce, case_name, case_value_zv);
break;
}
Expand Down
19 changes: 3 additions & 16 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -3725,19 +3725,6 @@ static zend_result preload_resolve_deps(preload_error *error, const zend_class_e
return SUCCESS;
}

static zend_result preload_update_constant(zval *val, zend_class_entry *scope)
{
zval tmp;
ZVAL_COPY(&tmp, val);
if (zval_update_constant_ex(&tmp, scope) == FAILURE || Z_TYPE(tmp) == IS_OBJECT) {
zval_ptr_dtor(&tmp);
return FAILURE;
}
zval_ptr_dtor_nogc(val);
ZVAL_COPY_VALUE(val, &tmp);
return SUCCESS;
}

static bool preload_try_resolve_constants(zend_class_entry *ce)
{
bool ok, changed, was_changed = 0;
Expand All @@ -3751,7 +3738,7 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
val = &c->value;
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
if (EXPECTED(preload_update_constant(val, c->ce) == SUCCESS)) {
if (EXPECTED(zval_update_constant_ex(val, c->ce) == SUCCESS)) {
was_changed = changed = 1;
} else {
ok = 0;
Expand All @@ -3769,7 +3756,7 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
val = &ce->default_properties_table[i];
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
zend_property_info *prop = ce->properties_info_table[i];
if (UNEXPECTED(preload_update_constant(val, prop->ce) != SUCCESS)) {
if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) {
resolved = ok = 0;
}
}
Expand All @@ -3785,7 +3772,7 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
val = ce->default_static_members_table + ce->default_static_members_count - 1;
while (count) {
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
if (UNEXPECTED(preload_update_constant(val, ce) != SUCCESS)) {
if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
resolved = ok = 0;
}
}
Expand Down
12 changes: 12 additions & 0 deletions ext/opcache/tests/gh8133.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

enum Foo
{
case Bar;
case Baz;
const CASES = [Foo::Bar, Foo::Baz];
}

class Qux {
const CASES = [Foo::Bar, Foo::Baz];
}
33 changes: 33 additions & 0 deletions ext/opcache/tests/gh8133.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--TEST--
Enum preloading
--EXTENSIONS--
opcache
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
opcache.preload={PWD}/gh8133.inc
--SKIPIF--
<?php
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
<?php

var_dump(Foo::CASES);
var_dump(Qux::CASES);

?>
--EXPECT--
array(2) {
[0]=>
enum(Foo::Bar)
[1]=>
enum(Foo::Baz)
}
array(2) {
[0]=>
enum(Foo::Bar)
[1]=>
enum(Foo::Baz)
}

0 comments on commit 4397811

Please sign in to comment.