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.
This commit is contained in:
Dmitry Stogov 2017-10-30 23:13:10 +03:00
parent dc4427d0ca
commit fcc08ce19f
13 changed files with 134 additions and 169 deletions

View File

@ -1127,19 +1127,22 @@ ZEND_API int zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
#endif
for (i = 0; i < class_type->default_static_members_count; i++) {
p = &class_type->default_static_members_table[i];
if (Z_ISREF_P(p) &&
class_type->parent &&
i < class_type->parent->default_static_members_count &&
p == &class_type->parent->default_static_members_table[i] &&
Z_TYPE(CE_STATIC_MEMBERS(class_type->parent)[i]) != IS_UNDEF
) {
zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i];
if (Z_ISREF_P(p)) {
if (class_type->parent &&
i < class_type->parent->default_static_members_count &&
p == &class_type->parent->default_static_members_table[i] &&
Z_TYPE(CE_STATIC_MEMBERS(class_type->parent)[i]) != IS_UNDEF
) {
zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i];
ZVAL_NEW_REF(q, q);
ZVAL_COPY_VALUE(&CE_STATIC_MEMBERS(class_type)[i], q);
Z_ADDREF_P(q);
ZVAL_NEW_REF(q, q);
ZVAL_COPY_VALUE(&CE_STATIC_MEMBERS(class_type)[i], q);
Z_ADDREF_P(q);
} else {
ZVAL_COPY_OR_DUP(&CE_STATIC_MEMBERS(class_type)[i], Z_REFVAL_P(p));
}
} else {
ZVAL_DUP(&CE_STATIC_MEMBERS(class_type)[i], p);
ZVAL_COPY_OR_DUP(&CE_STATIC_MEMBERS(class_type)[i], p);
}
}
} else {
@ -1191,15 +1194,19 @@ ZEND_API void object_properties_init(zend_object *object, zend_class_entry *clas
zval *dst = object->properties_table;
zval *end = src + class_type->default_properties_count;
do {
#if ZTS
ZVAL_DUP(dst, src);
#else
ZVAL_COPY(dst, src);
#endif
src++;
dst++;
} while (src != end);
if (UNEXPECTED(class_type->type == ZEND_INTERNAL_CLASS)) {
do {
ZVAL_COPY_OR_DUP(dst, src);
src++;
dst++;
} while (src != end);
} else {
do {
ZVAL_COPY(dst, src);
src++;
dst++;
} while (src != end);
}
object->properties = NULL;
}
}

View File

@ -301,7 +301,7 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc
ret = zend_use_undefined_constant(name, ast->attr, result);
break;
}
ZVAL_DUP(result, zv);
ZVAL_COPY_OR_DUP(result, zv);
break;
}
case ZEND_AST_CONSTANT_CLASS:
@ -457,9 +457,9 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc
zend_fetch_dimension_const(&tmp, &op1, &op2, (ast->attr == ZEND_DIM_IS) ? BP_VAR_IS : BP_VAR_R);
if (UNEXPECTED(Z_ISREF(tmp))) {
ZVAL_DUP(result, Z_REFVAL(tmp));
ZVAL_COPY_OR_DUP(result, Z_REFVAL(tmp));
} else {
ZVAL_DUP(result, &tmp);
ZVAL_COPY_OR_DUP(result, &tmp);
}
zval_ptr_dtor(&tmp);
zval_dtor(&op1);

View File

@ -1064,12 +1064,8 @@ static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, int st
/* copy: enforce read only access */
ZVAL_DEREF(prop);
if (UNEXPECTED(Z_COPYABLE_P(prop))) {
ZVAL_DUP(&prop_copy, prop);
prop = &prop_copy;
} else {
Z_TRY_ADDREF_P(prop);
}
ZVAL_COPY_OR_DUP(&prop_copy, prop);
prop = &prop_copy;
/* this is necessary to make it able to work with default array
* properties, returned to user */
@ -2032,7 +2028,7 @@ static int add_constant_info(zval *item, void *arg) /* {{{ */
return 0;
}
ZVAL_DUP(&const_val, &constant->value);
ZVAL_COPY_OR_DUP(&const_val, &constant->value);
zend_hash_add_new(Z_ARRVAL_P(name_array), constant->name, &const_val);
return 0;
}
@ -2108,7 +2104,7 @@ ZEND_FUNCTION(get_defined_constants)
add_assoc_zval(return_value, module_names[module_number], &modules[module_number]);
}
ZVAL_DUP(&const_val, &val->value);
ZVAL_COPY_OR_DUP(&const_val, &val->value);
zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val);
} ZEND_HASH_FOREACH_END();

View File

@ -98,12 +98,6 @@ static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
}
/* }}} */
static void zend_destroy_class_constant_internal(zval *zv) /* {{{ */
{
free(Z_PTR_P(zv));
}
/* }}} */
static zend_string *zend_new_interned_string_safe(zend_string *str) /* {{{ */ {
zend_string *interned_str;
@ -1402,7 +1396,7 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i
((c->flags & CONST_PERSISTENT) && !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION))
|| (Z_TYPE(c->value) < IS_OBJECT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION))
)) {
ZVAL_DUP(zv, &c->value);
ZVAL_COPY_OR_DUP(zv, &c->value);
return 1;
}
@ -1417,7 +1411,7 @@ static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool i
c = zend_lookup_reserved_const(lookup_name, lookup_len);
if (c) {
ZVAL_DUP(zv, &c->value);
ZVAL_COPY_OR_DUP(zv, &c->value);
return 1;
}
}
@ -1570,7 +1564,7 @@ static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name,
/* Substitute case-sensitive (or lowercase) persistent class constants */
if (Z_TYPE_P(c) < IS_OBJECT) {
ZVAL_DUP(zv, c);
ZVAL_COPY_OR_DUP(zv, c);
return 1;
}
@ -1760,7 +1754,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
ce->default_properties_table = NULL;
ce->default_static_members_table = NULL;
zend_hash_init_ex(&ce->properties_info, 8, NULL, (persistent_hashes ? zend_destroy_property_info_internal : NULL), persistent_hashes, 0);
zend_hash_init_ex(&ce->constants_table, 8, NULL, (persistent_hashes ? zend_destroy_class_constant_internal : NULL), persistent_hashes, 0);
zend_hash_init_ex(&ce->constants_table, 8, NULL, NULL, persistent_hashes, 0);
zend_hash_init_ex(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0);
if (ce->type == ZEND_INTERNAL_CLASS) {

View File

@ -590,7 +590,7 @@ ZEND_API int zval_update_constant_ex(zval *p, zend_class_entry *scope) /* {{{ */
return zend_use_undefined_constant(name, ast->attr, p);
}
zval_ptr_dtor_nogc(p);
ZVAL_DUP(p, zv);
ZVAL_COPY_OR_DUP(p, zv);
} else {
zval tmp;

View File

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

View File

@ -346,9 +346,12 @@ ZEND_API void destroy_zend_class(zval *zv)
zend_class_constant *c;
ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
zval_internal_ptr_dtor(&c->value);
if (c->doc_comment && c->ce == ce) {
zend_string_release(c->doc_comment);
if (c->ce == ce) {
zval_internal_ptr_dtor(&c->value);
if (c->doc_comment) {
zend_string_release(c->doc_comment);
}
free(c);
}
} ZEND_HASH_FOREACH_END();
zend_hash_destroy(&ce->constants_table);

View File

@ -993,6 +993,26 @@ static zend_always_inline uint32_t zval_delref_p(zval* pz) {
} \
} while (0)
/* ZVAL_COPY_OR_DUP() should be used instead of ZVAL_COPY() and ZVAL_DUP()
* in all places where the source may be a persistent zval.
*/
#define ZVAL_COPY_OR_DUP(z, v) \
do { \
zval *_z1 = (z); \
const zval *_z2 = (v); \
zend_refcounted *_gc = Z_COUNTED_P(_z2); \
uint32_t _t = Z_TYPE_INFO_P(_z2); \
ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \
if ((_t & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0) { \
if (EXPECTED(!(GC_FLAGS(_gc) & GC_PERSISTENT))) { \
GC_ADDREF(_gc); \
} else { \
_zval_copy_ctor_func(_z1 ZEND_FILE_LINE_CC); \
} \
} \
} while (0)
#define ZVAL_DEREF(z) do { \
if (UNEXPECTED(Z_ISREF_P(z))) { \
(z) = Z_REFVAL_P(z); \

View File

@ -5055,15 +5055,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, UNUSED, CONST, CONST_FETCH)
CACHE_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2)), c);
}
#ifdef ZTS
if (c->flags & CONST_PERSISTENT) {
ZVAL_DUP(EX_VAR(opline->result.var), &c->value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
#endif
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
ZEND_VM_NEXT_OPCODE();
}
@ -5081,9 +5073,6 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
if (OP1_TYPE == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2)));
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
#endif
break;
} else if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1))))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
@ -5140,15 +5129,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
}
} while (0);
#ifdef ZTS
if (ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_DUP(EX_VAR(opline->result.var), value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), value);
#endif
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value);
ZEND_VM_NEXT_OPCODE();
}

View File

@ -5764,9 +5764,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
if (IS_CONST == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2)));
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
#endif
break;
} else if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1))))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
@ -5823,15 +5820,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS
}
} while (0);
#ifdef ZTS
if (ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_DUP(EX_VAR(opline->result.var), value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), value);
#endif
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value);
ZEND_VM_NEXT_OPCODE();
}
@ -19813,9 +19802,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
if (IS_VAR == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2)));
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
#endif
break;
} else if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1))))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
@ -19872,15 +19858,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_
}
} while (0);
#ifdef ZTS
if (ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_DUP(EX_VAR(opline->result.var), value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), value);
#endif
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value);
ZEND_VM_NEXT_OPCODE();
}
@ -28698,15 +28676,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CON
CACHE_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2)), c);
}
#ifdef ZTS
if (c->flags & CONST_PERSISTENT) {
ZVAL_DUP(EX_VAR(opline->result.var), &c->value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), &c->value);
#endif
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
ZEND_VM_NEXT_OPCODE();
}
@ -28724,9 +28694,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
if (IS_UNUSED == IS_CONST) {
if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2))))) {
value = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op2)));
#ifdef ZTS
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
#endif
break;
} else if (EXPECTED(CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1))))) {
ce = CACHED_PTR(Z_CACHE_SLOT_P(RT_CONSTANT(opline, opline->op1)));
@ -28783,15 +28750,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS
}
} while (0);
#ifdef ZTS
if (ce->type == ZEND_INTERNAL_CLASS) {
ZVAL_DUP(EX_VAR(opline->result.var), value);
} else {
ZVAL_COPY(EX_VAR(opline->result.var), value);
}
#else
ZVAL_COPY(EX_VAR(opline->result.var), value);
#endif
ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), value);
ZEND_VM_NEXT_OPCODE();
}

View File

@ -310,8 +310,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
} else {
ZVAL_COPY_VALUE(&t, c);
zval_copy_ctor(&t);
ZVAL_COPY_OR_DUP(&t, c);
}
if (opline->op1_type == IS_CONST) {

View File

@ -3715,7 +3715,7 @@ ZEND_METHOD(reflection_class_constant, getValue)
}
GET_REFLECTION_OBJECT_PTR(ref);
ZVAL_DUP(return_value, &ref->value);
ZVAL_COPY_OR_DUP(return_value, &ref->value);
if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
zval_update_constant_ex(return_value, ref->ce);
}
@ -3848,7 +3848,7 @@ static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value
/* copy: enforce read only access */
ZVAL_DEREF(prop);
ZVAL_DUP(&prop_copy, prop);
ZVAL_COPY_OR_DUP(&prop_copy, prop);
/* this is necessary to make it able to work with default array
* properties, returned to user */
@ -4504,7 +4504,7 @@ ZEND_METHOD(reflection_class, getConstants)
zend_class_entry *ce;
zend_string *key;
zend_class_constant *c;
zval *val;
zval val;
if (zend_parse_parameters_none() == FAILURE) {
return;
@ -4516,8 +4516,8 @@ ZEND_METHOD(reflection_class, getConstants)
zend_array_destroy(Z_ARRVAL_P(return_value));
return;
}
val = zend_hash_add_new(Z_ARRVAL_P(return_value), key, &c->value);
Z_TRY_ADDREF_P(val);
ZVAL_COPY_OR_DUP(&val, &c->value);
zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
} ZEND_HASH_FOREACH_END();
}
/* }}} */
@ -4567,7 +4567,7 @@ ZEND_METHOD(reflection_class, getConstant)
if ((c = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
RETURN_FALSE;
}
ZVAL_DUP(return_value, &c->value);
ZVAL_COPY_OR_DUP(return_value, &c->value);
}
/* }}} */
@ -5848,7 +5848,7 @@ static int _addconstant(zval *el, int num_args, va_list args, zend_hash_key *has
int number = va_arg(args, int);
if (number == constant->module_number) {
ZVAL_DUP(&const_val, &constant->value);
ZVAL_COPY_OR_DUP(&const_val, &constant->value);
zend_hash_update(Z_ARRVAL_P(retval), constant->name, &const_val);
}
return 0;

View File

@ -3879,7 +3879,7 @@ PHP_FUNCTION(constant)
scope = zend_get_executed_scope();
c = zend_get_constant_ex(const_name, scope, ZEND_FETCH_CLASS_SILENT);
if (c) {
ZVAL_DUP(return_value, c);
ZVAL_COPY_OR_DUP(return_value, c);
if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
if (UNEXPECTED(zval_update_constant_ex(return_value, scope) != SUCCESS)) {
return;