Fix preloading of constants containing enums

Fixes GH-8133
This commit is contained in:
Ilija Tovilo 2022-04-14 14:54:34 +02:00
parent e9b9fec2b2
commit 4397811db2
No known key found for this signature in database
GPG Key ID: A4F5D403F118200A
5 changed files with 56 additions and 23 deletions

2
NEWS
View File

@ -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

View File

@ -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);
@ -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;
}

View File

@ -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;
@ -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;
@ -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;
}
}
@ -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;
}
}

View File

@ -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];
}

View File

@ -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)
}