From: Dmitry Stogov Date: Wed, 27 Jun 2018 09:33:20 +0000 (+0300) Subject: Fixed ZTS race condition (zend_class_entry->ce_flags of internal classes must not... X-Git-Tag: php-7.3.0alpha3~56 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6dc0cd868d972885249ce40f2d64097cd0ba6c1f;p=php Fixed ZTS race condition (zend_class_entry->ce_flags of internal classes must not be modified, because internal class enties are shared between threads) --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 777361d41b..b05c5a96d4 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1146,67 +1146,46 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */ { if (!(class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { + zend_class_entry *ce; + zend_class_constant *c; + zval *val; + zend_property_info *prop_info; + if (class_type->parent) { if (UNEXPECTED(zend_update_class_constants(class_type->parent) != SUCCESS)) { return FAILURE; } } - if (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count) { - /* initialize static members of internal class */ - int i; - zval *p; - -#if ZTS - CG(static_members_table)[(zend_intptr_t)(class_type->static_members_table)] = emalloc(sizeof(zval) * class_type->default_static_members_count); -#else - class_type->static_members_table = emalloc(sizeof(zval) * class_type->default_static_members_count); -#endif - for (i = 0; i < class_type->default_static_members_count; i++) { - p = &class_type->default_static_members_table[i]; - if (Z_TYPE_P(p) == IS_INDIRECT) { - zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i]; - ZVAL_DEINDIRECT(q); - ZVAL_INDIRECT(&CE_STATIC_MEMBERS(class_type)[i], q); - } else { - ZVAL_COPY_OR_DUP(&CE_STATIC_MEMBERS(class_type)[i], p); + ZEND_HASH_FOREACH_PTR(&class_type->constants_table, c) { + val = &c->value; + if (Z_TYPE_P(val) == IS_CONSTANT_AST) { + if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) { + return FAILURE; } } - } else { - zend_class_entry *ce; - zend_class_constant *c; - zval *val; - zend_property_info *prop_info; - - ZEND_HASH_FOREACH_PTR(&class_type->constants_table, c) { - val = &c->value; - if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) { - return FAILURE; - } - } - } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); - ce = class_type; - while (ce) { - ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { - if (prop_info->ce == ce) { - if (prop_info->flags & ZEND_ACC_STATIC) { - val = CE_STATIC_MEMBERS(class_type) + prop_info->offset; - } else { - val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0)); - } - ZVAL_DEREF(val); - if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) { - return FAILURE; - } + ce = class_type; + while (ce) { + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) { + if (prop_info->ce == ce) { + if (prop_info->flags & ZEND_ACC_STATIC) { + val = CE_STATIC_MEMBERS(class_type) + prop_info->offset; + } else { + val = (zval*)((char*)class_type->default_properties_table + prop_info->offset - OBJ_PROP_TO_OFFSET(0)); + } + ZVAL_DEREF(val); + if (Z_TYPE_P(val) == IS_CONSTANT_AST) { + if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) { + return FAILURE; } } - } ZEND_HASH_FOREACH_END(); - ce = ce->parent; - } + } + } ZEND_HASH_FOREACH_END(); + ce = ce->parent; } + class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED; } @@ -3705,9 +3684,6 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, z if (ce->type == ZEND_INTERNAL_CLASS) { property_info = pemalloc(sizeof(zend_property_info), 1); - if ((access_type & ZEND_ACC_STATIC) || Z_TYPE_P(property) == IS_CONSTANT_AST) { - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; - } } else { property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info)); if (Z_TYPE_P(property) == IS_CONSTANT_AST) { diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 67e2b97d3e..be605a49de 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -925,8 +925,6 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent ce->default_static_members_count += parent_ce->default_static_members_count; if (ce->type == ZEND_USER_CLASS) { ce->static_members_table = ce->default_static_members_table; - } else { - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 86029ee4b9..fda969cd30 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1420,6 +1420,34 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st } /* }}} */ +static void zend_intenal_class_init_statics(zend_class_entry *class_type) /* {{{ */ +{ + int i; + zval *p; + + if (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count) { + if (class_type->parent) { + zend_intenal_class_init_statics(class_type->parent); + } + +#if ZTS + CG(static_members_table)[(zend_intptr_t)(class_type->static_members_table)] = emalloc(sizeof(zval) * class_type->default_static_members_count); +#else + class_type->static_members_table = emalloc(sizeof(zval) * class_type->default_static_members_count); +#endif + for (i = 0; i < class_type->default_static_members_count; i++) { + p = &class_type->default_static_members_table[i]; + if (Z_TYPE_P(p) == IS_INDIRECT) { + zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i]; + ZVAL_DEINDIRECT(q); + ZVAL_INDIRECT(&CE_STATIC_MEMBERS(class_type)[i], q); + } else { + ZVAL_COPY_OR_DUP(&CE_STATIC_MEMBERS(class_type)[i], p); + } + } + } +} /* }}} */ + ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, zend_bool silent) /* {{{ */ { zend_property_info *property_info = zend_hash_find_ptr(&ce->properties_info, property_name); @@ -1448,11 +1476,15 @@ ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *p /* check if static properties were destoyed */ if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) { + if (ce->type == ZEND_INTERNAL_CLASS) { + zend_intenal_class_init_statics(ce); + } else { undeclared_property: - if (!silent) { - zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name)); + if (!silent) { + zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name)); + } + return NULL; } - return NULL; } ret = CE_STATIC_MEMBERS(ce) + property_info->offset; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index ddb78c7924..645f942818 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -172,7 +172,6 @@ ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce) #else ce->static_members_table = NULL; #endif - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; while (p != end) { i_zval_ptr_dtor(p ZEND_FILE_LINE_CC); p++;