mirror of
https://github.com/php/php-src.git
synced 2024-11-24 02:15:04 +08:00
Fixed bug 78175 (Preloading must store default values of static variables and properties)
This commit is contained in:
parent
94df6dc3fd
commit
0f29fb5cd8
@ -5877,8 +5877,14 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /*
|
||||
|
||||
init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE);
|
||||
|
||||
ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*)));
|
||||
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
|
||||
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
|
||||
op_array->fn_flags |= ZEND_ACC_PRELOADED;
|
||||
ZEND_MAP_PTR_NEW(op_array->run_time_cache);
|
||||
ZEND_MAP_PTR_NEW(op_array->static_variables_ptr);
|
||||
} else {
|
||||
ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*)));
|
||||
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
|
||||
}
|
||||
|
||||
op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_STRICT_TYPES);
|
||||
op_array->fn_flags |= decl->flags;
|
||||
@ -6313,6 +6319,11 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
|
||||
ce->name = name;
|
||||
zend_initialize_class_data(ce, 1);
|
||||
|
||||
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
|
||||
ce->ce_flags |= ZEND_ACC_PRELOADED;
|
||||
ZEND_MAP_PTR_NEW(ce->static_members_table);
|
||||
}
|
||||
|
||||
ce->ce_flags |= decl->flags;
|
||||
ce->info.user.filename = zend_get_compiled_filename();
|
||||
ce->info.user.line_start = decl->start_lineno;
|
||||
|
@ -1178,7 +1178,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
|
||||
} while (dst != end);
|
||||
} else if (ce->type == ZEND_USER_CLASS) {
|
||||
if (CE_STATIC_MEMBERS(parent_ce) == NULL) {
|
||||
ZEND_ASSERT(parent_ce->ce_flags & ZEND_ACC_IMMUTABLE);
|
||||
ZEND_ASSERT(parent_ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED));
|
||||
zend_class_init_statics(parent_ce);
|
||||
}
|
||||
src = CE_STATIC_MEMBERS(parent_ce) + parent_ce->default_static_members_count;
|
||||
|
@ -1491,7 +1491,7 @@ ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend
|
||||
|
||||
/* check if static properties were destroyed */
|
||||
if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
|
||||
if (ce->type == ZEND_INTERNAL_CLASS || (ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
|
||||
if (ce->type == ZEND_INTERNAL_CLASS || (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED))) {
|
||||
zend_class_init_statics(ce);
|
||||
} else {
|
||||
undeclared_property:
|
||||
|
@ -219,7 +219,7 @@ ZEND_API void destroy_zend_class(zval *zv)
|
||||
zend_class_entry *ce = Z_PTR_P(zv);
|
||||
zend_function *fn;
|
||||
|
||||
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
|
||||
if (ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED)) {
|
||||
zend_op_array *op_array;
|
||||
|
||||
if (ce->default_static_members_count) {
|
||||
|
@ -8122,7 +8122,7 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
|
||||
|
||||
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
|
||||
if (!ht) {
|
||||
ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_IMMUTABLE);
|
||||
ZEND_ASSERT(EX(func)->op_array.fn_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED));
|
||||
ht = zend_array_dup(EX(func)->op_array.static_variables);
|
||||
ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
|
||||
} else if (GC_REFCOUNT(ht) > 1) {
|
||||
|
@ -47533,7 +47533,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN
|
||||
|
||||
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
|
||||
if (!ht) {
|
||||
ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_IMMUTABLE);
|
||||
ZEND_ASSERT(EX(func)->op_array.fn_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED));
|
||||
ht = zend_array_dup(EX(func)->op_array.static_variables);
|
||||
ZEND_MAP_PTR_SET(EX(func)->op_array.static_variables_ptr, ht);
|
||||
} else if (GC_REFCOUNT(ht) > 1) {
|
||||
|
@ -3176,7 +3176,6 @@ static void preload_move_user_functions(HashTable *src, HashTable *dst)
|
||||
}
|
||||
if (copy) {
|
||||
_zend_hash_append_ptr(dst, p->key, function);
|
||||
function->common.fn_flags |= ZEND_ACC_PRELOADED;
|
||||
} else {
|
||||
orig_dtor(&p->val);
|
||||
}
|
||||
@ -3210,15 +3209,7 @@ static void preload_move_user_classes(HashTable *src, HashTable *dst)
|
||||
}
|
||||
}
|
||||
if (copy) {
|
||||
zend_function *function;
|
||||
|
||||
ce->ce_flags |= ZEND_ACC_PRELOADED;
|
||||
_zend_hash_append_ptr(dst, p->key, ce);
|
||||
ZEND_HASH_FOREACH_PTR(&ce->function_table, function) {
|
||||
if (EXPECTED(function->type == ZEND_USER_FUNCTION)) {
|
||||
function->common.fn_flags |= ZEND_ACC_PRELOADED;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else {
|
||||
orig_dtor(&p->val);
|
||||
}
|
||||
@ -3481,6 +3472,7 @@ static void preload_link(void)
|
||||
uint32_t i;
|
||||
zend_op_array *op_array;
|
||||
dtor_func_t orig_dtor;
|
||||
zend_function *function;
|
||||
|
||||
/* Resolve class dependencies */
|
||||
do {
|
||||
@ -3652,6 +3644,13 @@ static void preload_link(void)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
ce->ce_flags &= ~ZEND_ACC_PRELOADED;
|
||||
ZEND_HASH_FOREACH_PTR(&ce->function_table, function) {
|
||||
if (EXPECTED(function->type == ZEND_USER_FUNCTION)
|
||||
&& function->common.scope == ce) {
|
||||
function->common.fn_flags &= ~ZEND_ACC_PRELOADED;
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
script = zend_hash_find_ptr(preload_scripts, ce->info.user.filename);
|
||||
ZEND_ASSERT(script);
|
||||
zend_hash_add(&script->script.class_table, key, zv);
|
||||
@ -4006,6 +4005,8 @@ static int accel_preload(const char *config)
|
||||
int ret;
|
||||
uint32_t orig_compiler_options;
|
||||
char *orig_open_basedir;
|
||||
size_t orig_map_ptr_last;
|
||||
zval *zv;
|
||||
|
||||
ZCG(enabled) = 0;
|
||||
ZCG(accelerator_enabled) = 0;
|
||||
@ -4022,6 +4023,8 @@ static int accel_preload(const char *config)
|
||||
CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
|
||||
// CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
|
||||
|
||||
orig_map_ptr_last = CG(map_ptr_last);
|
||||
|
||||
/* Compile and execute proloading script */
|
||||
memset(&file_handle, 0, sizeof(file_handle));
|
||||
file_handle.filename = (char*)config;
|
||||
@ -4105,10 +4108,58 @@ static int accel_preload(const char *config)
|
||||
|
||||
zend_objects_store_free_object_storage(&EG(objects_store), 1);
|
||||
|
||||
/* Cleanup static variables of preloaded functions */
|
||||
ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
|
||||
zend_op_array *op_array = Z_PTR_P(zv);
|
||||
if (op_array->type == ZEND_INTERNAL_FUNCTION) {
|
||||
break;
|
||||
}
|
||||
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_PRELOADED);
|
||||
if (op_array->static_variables) {
|
||||
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
|
||||
if (ht) {
|
||||
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
|
||||
zend_array_destroy(ht);
|
||||
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
/* Cleanup static properties and variables of preloaded classes */
|
||||
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
|
||||
zend_class_entry *ce = Z_PTR_P(zv);
|
||||
if (ce->type == ZEND_INTERNAL_CLASS) {
|
||||
break;
|
||||
}
|
||||
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_PRELOADED);
|
||||
if (ce->default_static_members_count) {
|
||||
zend_cleanup_internal_class_data(ce);
|
||||
}
|
||||
if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
|
||||
zend_op_array *op_array;
|
||||
|
||||
ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
|
||||
if (op_array->type == ZEND_USER_FUNCTION) {
|
||||
if (op_array->static_variables) {
|
||||
HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
|
||||
if (ht) {
|
||||
ZEND_ASSERT(GC_REFCOUNT(ht) == 1);
|
||||
zend_array_destroy(ht);
|
||||
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
CG(map_ptr_last) = orig_map_ptr_last;
|
||||
|
||||
/* Inheritance errors may be thrown during linking */
|
||||
zend_try {
|
||||
preload_link();
|
||||
} zend_catch {
|
||||
CG(map_ptr_last) = orig_map_ptr_last;
|
||||
ret = FAILURE;
|
||||
goto finish;
|
||||
} zend_end_try();
|
||||
@ -4234,6 +4285,8 @@ static int accel_preload(const char *config)
|
||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||
|
||||
zend_shared_alloc_destroy_xlat_table();
|
||||
} else {
|
||||
CG(map_ptr_last) = orig_map_ptr_last;
|
||||
}
|
||||
|
||||
finish:
|
||||
|
19
ext/opcache/tests/bug78175_2.phpt
Normal file
19
ext/opcache/tests/bug78175_2.phpt
Normal file
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Bug #78175.2 (Preloading segfaults at preload time and at runtime)
|
||||
--INI--
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.optimization_level=-1
|
||||
opcache.preload={PWD}/preload_bug78175_2.inc
|
||||
--SKIPIF--
|
||||
<?php require_once('skipif.inc'); ?>
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(get_class(Loader::getLoader()));
|
||||
var_dump(Loader::getCounter());
|
||||
?>
|
||||
OK
|
||||
--EXPECT--
|
||||
string(6) "Loader"
|
||||
int(0)
|
||||
OK
|
20
ext/opcache/tests/preload_bug78175_2.inc
Normal file
20
ext/opcache/tests/preload_bug78175_2.inc
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
class Loader {
|
||||
static private $loader;
|
||||
|
||||
static function getLoader() {
|
||||
if (null !== self::$loader) {
|
||||
return self::$loader;
|
||||
}
|
||||
return self::$loader = new Loader();
|
||||
}
|
||||
|
||||
static function getCounter() {
|
||||
static $counter = 0;
|
||||
return $counter++;
|
||||
}
|
||||
}
|
||||
|
||||
Loader::getLoader();
|
||||
Loader::getCounter();
|
||||
Loader::getCounter();
|
@ -247,6 +247,10 @@ static void zend_persist_zval(zval *z)
|
||||
efree(old_ref);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ZEND_ASSERT(Z_TYPE_P(z) != IS_OBJECT);
|
||||
ZEND_ASSERT(Z_TYPE_P(z) != IS_RESOURCE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,6 +141,10 @@ static void zend_persist_zval_calc(zval *z)
|
||||
zend_persist_ast_calc(Z_ASTVAL_P(z));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ZEND_ASSERT(Z_TYPE_P(z) != IS_OBJECT);
|
||||
ZEND_ASSERT(Z_TYPE_P(z) != IS_RESOURCE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user