diff options
author | Dmitry Stogov <dmitry@zend.com> | 2019-06-24 20:32:27 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2019-06-24 20:32:27 +0300 |
commit | 0f29fb5cd81d9df4829bc63f704019df910b3075 (patch) | |
tree | 05c34dda76c2e45630d5fe9528d10dc5fef97bd3 | |
parent | 94df6dc3fd07fa187ba09c587a8d1357fd8bbe6f (diff) | |
download | php-git-0f29fb5cd81d9df4829bc63f704019df910b3075.tar.gz |
Fixed bug 78175 (Preloading must store default values of static variables and properties)
-rw-r--r-- | Zend/zend_compile.c | 15 | ||||
-rw-r--r-- | Zend/zend_inheritance.c | 2 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 2 | ||||
-rw-r--r-- | Zend/zend_opcode.c | 2 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 2 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 2 | ||||
-rw-r--r-- | ext/opcache/ZendAccelerator.c | 71 | ||||
-rw-r--r-- | ext/opcache/tests/bug78175_2.phpt | 19 | ||||
-rw-r--r-- | ext/opcache/tests/preload_bug78175_2.inc | 20 | ||||
-rw-r--r-- | ext/opcache/zend_persist.c | 4 | ||||
-rw-r--r-- | ext/opcache/zend_persist_calc.c | 4 |
11 files changed, 127 insertions, 16 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0837c5b0b8..cb9419c7b8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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; diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index ba1612c189..e62d990c18 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -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; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 10f5ac1524..3f8be6f707 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -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: diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 6c8ff85b10..dd7c42a093 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -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) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 330132b43d..3508cba5dd 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 832f9bef42..b5e63d394f 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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) { diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index c8f640bfeb..60e44c6508 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -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: diff --git a/ext/opcache/tests/bug78175_2.phpt b/ext/opcache/tests/bug78175_2.phpt new file mode 100644 index 0000000000..1d736f6e10 --- /dev/null +++ b/ext/opcache/tests/bug78175_2.phpt @@ -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 diff --git a/ext/opcache/tests/preload_bug78175_2.inc b/ext/opcache/tests/preload_bug78175_2.inc new file mode 100644 index 0000000000..288c142678 --- /dev/null +++ b/ext/opcache/tests/preload_bug78175_2.inc @@ -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(); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index f5e1c45738..698611e1a7 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -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; } } diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index ca96da7ffa..a38398e3cf 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -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; } } |