Skip to content

Commit 4397811

Browse files
committed
Fix preloading of constants containing enums
Fixes GH-8133
1 parent e9b9fec commit 4397811

File tree

5 files changed

+56
-23
lines changed

5 files changed

+56
-23
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ PHP NEWS
55
- Core:
66
. Fixed bug GH-8310 (Registry settings are no longer recognized). (cmb)
77
. Fixed potential race condition during resource ID allocation. (ryancaicse)
8+
. Fixed bug GH-8133 (Preloading of constants containing arrays with enums
9+
segfaults). (ilutov)
810

911
- Date:
1012
. Fixed bug GH-7752 (DateTimeZone::getTransitions() returns insufficient

Zend/zend_ast.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,12 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast
750750
break;
751751
case ZEND_AST_CONST_ENUM_INIT:
752752
{
753+
// Preloading will attempt to resolve constants but objects can't be stored in shm
754+
// Aborting here to store the const AST instead
755+
if (CG(in_compilation)) {
756+
return FAILURE;
757+
}
758+
753759
zend_ast *class_name_ast = ast->child[0];
754760
zend_string *class_name = zend_ast_get_str(class_name_ast);
755761

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

764770
zend_class_entry *ce = zend_lookup_class(class_name);
765-
if (!ce) {
766-
/* Class may not be available when resolving constants on a dynamically
767-
* declared enum during preloading. */
768-
ZEND_ASSERT(CG(compiler_options) & ZEND_COMPILE_PRELOAD);
769-
return FAILURE;
770-
}
771-
772771
zend_enum_new(result, ce, case_name, case_value_zv);
773772
break;
774773
}

ext/opcache/ZendAccelerator.c

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3725,19 +3725,6 @@ static zend_result preload_resolve_deps(preload_error *error, const zend_class_e
37253725
return SUCCESS;
37263726
}
37273727

3728-
static zend_result preload_update_constant(zval *val, zend_class_entry *scope)
3729-
{
3730-
zval tmp;
3731-
ZVAL_COPY(&tmp, val);
3732-
if (zval_update_constant_ex(&tmp, scope) == FAILURE || Z_TYPE(tmp) == IS_OBJECT) {
3733-
zval_ptr_dtor(&tmp);
3734-
return FAILURE;
3735-
}
3736-
zval_ptr_dtor_nogc(val);
3737-
ZVAL_COPY_VALUE(val, &tmp);
3738-
return SUCCESS;
3739-
}
3740-
37413728
static bool preload_try_resolve_constants(zend_class_entry *ce)
37423729
{
37433730
bool ok, changed, was_changed = 0;
@@ -3751,7 +3738,7 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
37513738
ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
37523739
val = &c->value;
37533740
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
3754-
if (EXPECTED(preload_update_constant(val, c->ce) == SUCCESS)) {
3741+
if (EXPECTED(zval_update_constant_ex(val, c->ce) == SUCCESS)) {
37553742
was_changed = changed = 1;
37563743
} else {
37573744
ok = 0;
@@ -3769,7 +3756,7 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
37693756
val = &ce->default_properties_table[i];
37703757
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
37713758
zend_property_info *prop = ce->properties_info_table[i];
3772-
if (UNEXPECTED(preload_update_constant(val, prop->ce) != SUCCESS)) {
3759+
if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) {
37733760
resolved = ok = 0;
37743761
}
37753762
}
@@ -3785,7 +3772,7 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
37853772
val = ce->default_static_members_table + ce->default_static_members_count - 1;
37863773
while (count) {
37873774
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
3788-
if (UNEXPECTED(preload_update_constant(val, ce) != SUCCESS)) {
3775+
if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
37893776
resolved = ok = 0;
37903777
}
37913778
}

ext/opcache/tests/gh8133.inc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
enum Foo
4+
{
5+
case Bar;
6+
case Baz;
7+
const CASES = [Foo::Bar, Foo::Baz];
8+
}
9+
10+
class Qux {
11+
const CASES = [Foo::Bar, Foo::Baz];
12+
}

ext/opcache/tests/gh8133.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Enum preloading
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.optimization_level=-1
9+
opcache.preload={PWD}/gh8133.inc
10+
--SKIPIF--
11+
<?php
12+
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
13+
?>
14+
--FILE--
15+
<?php
16+
17+
var_dump(Foo::CASES);
18+
var_dump(Qux::CASES);
19+
20+
?>
21+
--EXPECT--
22+
array(2) {
23+
[0]=>
24+
enum(Foo::Bar)
25+
[1]=>
26+
enum(Foo::Baz)
27+
}
28+
array(2) {
29+
[0]=>
30+
enum(Foo::Bar)
31+
[1]=>
32+
enum(Foo::Baz)
33+
}

0 commit comments

Comments
 (0)