summaryrefslogtreecommitdiff
path: root/Zend/zend_inheritance.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2017-10-30 23:13:10 +0300
committerDmitry Stogov <dmitry@zend.com>2017-10-30 23:13:10 +0300
commitfcc08ce19f39f7ab1381ecc8a010037d41819329 (patch)
treec390b9b848758ad8e8b79b8f11e9a798a7de039d /Zend/zend_inheritance.c
parentdc4427d0caf2d066cd01f91fd0e899217fbceb30 (diff)
downloadphp-git-fcc08ce19f39f7ab1381ecc8a010037d41819329.tar.gz
Prevent reference-counting on persistent zvals (internal constants, default properties and constants of internal classes).
New macro ZVAL_COPY_OR_DUP() is used perform duplication, if necessary. This should eliminate related race-coditions in ZTS build and prevent reference-counting bugs after unclean shutdown.
Diffstat (limited to 'Zend/zend_inheritance.c')
-rw-r--r--Zend/zend_inheritance.c102
1 files changed, 54 insertions, 48 deletions
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index 02b1810f2e..c200573ac8 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -775,16 +775,7 @@ static void do_inherit_class_constant(zend_string *name, zend_class_constant *pa
if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
- if (ce->type & ZEND_INTERNAL_CLASS) {
- if (Z_REFCOUNTED(parent_const->value)) {
- Z_ADDREF(parent_const->value);
- }
- c = pemalloc(sizeof(zend_class_constant), 1);
- memcpy(c, parent_const, sizeof(zend_class_constant));
- } else {
- c = parent_const;
- }
- _zend_hash_append_ptr(&ce->constants_table, name, c);
+ _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
}
}
/* }}} */
@@ -842,24 +833,28 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
ce->default_properties_table = end;
}
src = parent_ce->default_properties_table + parent_ce->default_properties_count;
- do {
- dst--;
- src--;
-#ifdef ZTS
- if (parent_ce->type != ce->type) {
- ZVAL_DUP(dst, src);
+ if (UNEXPECTED(parent_ce->type != ce->type)) {
+ /* User class extends internal */
+ do {
+ dst--;
+ src--;
+ ZVAL_COPY_OR_DUP(dst, src);
if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
continue;
- }
-#endif
-
- ZVAL_COPY(dst, src);
- if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- } while (dst != end);
+ } while (dst != end);
+ } else {
+ do {
+ dst--;
+ src--;
+ ZVAL_COPY(dst, src);
+ if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
+ ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+ }
+ continue;
+ } while (dst != end);
+ }
ce->default_properties_count += parent_ce->default_properties_count;
}
@@ -884,23 +879,43 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
dst = end + parent_ce->default_static_members_count;
ce->default_static_members_table = end;
}
- src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
- do {
- dst--;
- src--;
- if (parent_ce->type == ZEND_INTERNAL_CLASS) {
+ if (UNEXPECTED(parent_ce->type != ce->type)) {
+ /* User class extends internal */
+ if (UNEXPECTED(zend_update_class_constants(parent_ce) != SUCCESS)) {
+ ZEND_ASSERT(0);
+ }
+ src = CE_STATIC_MEMBERS(parent_ce) + parent_ce->default_static_members_count;
+ do {
+ dst--;
+ src--;
+ ZVAL_MAKE_REF(src);
+ ZVAL_COPY_VALUE(dst, src);
+ Z_ADDREF_P(dst);
+ } while (dst != end);
+ } else if (ce->type == ZEND_USER_CLASS) {
+ src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
+ do {
+ dst--;
+ src--;
+ ZVAL_MAKE_REF(src);
+ ZVAL_COPY_VALUE(dst, src);
+ Z_ADDREF_P(dst);
+ if (Z_TYPE_P(Z_REFVAL_P(dst)) == IS_CONSTANT_AST) {
+ ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
+ }
+ } while (dst != end);
+ } else {
+ src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
+ do {
+ dst--;
+ src--;
if (!Z_ISREF_P(src)) {
ZVAL_NEW_PERSISTENT_REF(src, src);
}
- } else {
- ZVAL_MAKE_REF(src);
- }
- ZVAL_COPY_VALUE(dst, src);
- Z_ADDREF_P(dst);
- if (Z_TYPE_P(Z_REFVAL_P(dst)) == IS_CONSTANT_AST) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- } while (dst != end);
+ ZVAL_COPY_VALUE(dst, src);
+ Z_ADDREF_P(dst);
+ } while (dst != end);
+ }
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;
@@ -988,16 +1003,7 @@ static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c,
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
}
- if (ce->type & ZEND_INTERNAL_CLASS) {
- if (Z_REFCOUNTED(c->value)) {
- Z_ADDREF(c->value);
- }
- ct = pemalloc(sizeof(zend_class_constant), 1);
- memcpy(ct, c, sizeof(zend_class_constant));
- } else {
- ct = c;
- }
- zend_hash_update_ptr(&ce->constants_table, name, ct);
+ zend_hash_update_ptr(&ce->constants_table, name, c);
}
}
/* }}} */