From ce1af1e47bebb5ebbc2aa8f7a0b4dfb91ef8d327 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 5 Aug 2014 15:38:43 +0400 Subject: [PATCH] Fixed bug #67725 (now we create immutable arrays only in SHM) --- Zend/tests/gc_029.phpt | 4 +- Zend/zend_compile.c | 68 ++++++-------------------- Zend/zend_compile.h | 1 - Zend/zend_constants.c | 4 +- Zend/zend_vm_def.h | 4 +- Zend/zend_vm_execute.h | 14 ++++-- ext/intl/collator/collator_sort.c | 2 +- ext/opcache/Optimizer/zend_optimizer.c | 3 -- ext/opcache/zend_persist.c | 10 ++++ 9 files changed, 42 insertions(+), 68 deletions(-) diff --git a/Zend/tests/gc_029.phpt b/Zend/tests/gc_029.phpt index 18fef3c7d7..3873d8becd 100644 --- a/Zend/tests/gc_029.phpt +++ b/Zend/tests/gc_029.phpt @@ -33,5 +33,5 @@ unset($foo); unset($bar); var_dump(gc_collect_cycles()); ?> ---EXPECT-- -int(3) +--EXPECTREGEX-- +int\([23]\) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f099802a62..ae26733a7b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6378,23 +6378,27 @@ str_index: if (constant_array) { /* remove run-time array construction and use constant array instead */ opline = &CG(active_op_array)->opcodes[next_op_num-1]; - while (opline != init_opline) { + while (1) { if (opline->op2_type == IS_CONST) { zend_del_literal(CG(active_op_array), opline->op2.constant); } - zend_del_literal(CG(active_op_array), opline->op1.constant); + if (opline->op1_type == IS_CONST) { + if (Z_TYPE(CONSTANT(opline->op1.constant)) == IS_ARRAY && + Z_REFCOUNTED(CONSTANT(opline->op1.constant)) && + Z_REFCOUNT(CONSTANT(opline->op1.constant)) == 2) { + /* don't delete nested arrays */ + Z_DELREF(CONSTANT(opline->op1.constant)); + ZVAL_UNDEF(&CONSTANT(opline->op1.constant)); + } + zend_del_literal(CG(active_op_array), opline->op1.constant); + } + if (opline == init_opline) { + break; + } opline--; } - if (opline->op2_type == IS_CONST) { - zend_del_literal(CG(active_op_array), opline->op2.constant); - } - if (opline->op1_type == IS_CONST) { - zend_del_literal(CG(active_op_array), opline->op1.constant); - } CG(active_op_array)->last = array_node->u.op.opline_num; - zend_make_immutable_array(&array TSRMLS_CC); - result->op_type = IS_CONST; ZVAL_COPY_VALUE(&result->u.constant, &array); } else { @@ -7846,58 +7850,14 @@ void zend_do_end_compilation(TSRMLS_D) /* {{{ */ } /* }}} */ -ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC) /* {{{ */ -{ - zend_constant *c; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - - Z_TYPE_FLAGS_P(zv) = IS_TYPE_IMMUTABLE; - GC_REFCOUNT(Z_COUNTED_P(zv)) = 2; - Z_ARRVAL_P(zv)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; - - /* store as an anonymous constant */ - c = emalloc(sizeof(zend_constant)); - ZVAL_COPY_VALUE(&c->value, zv); - c->flags = 0; - c->name = NULL; - c->module_number = PHP_USER_CONSTANT; - zend_hash_next_index_insert_ptr(EG(zend_constants), c); -} -/* }}} */ - -void zend_make_immutable_array_r(zval *zv TSRMLS_DC) /* {{{ */ -{ - zval *el; - - if (Z_IMMUTABLE_P(zv)) { - return; - } - zend_make_immutable_array(zv TSRMLS_CC); - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), el) { - if (Z_TYPE_P(el) == IS_ARRAY) { - zend_make_immutable_array_r(el TSRMLS_CC); - } - } ZEND_HASH_FOREACH_END(); -} -/* }}} */ - void zend_do_constant_expression(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ { if (ast->kind == ZEND_CONST) { ZVAL_COPY_VALUE(&result->u.constant, &ast->u.val); efree(ast); - if (Z_TYPE(result->u.constant) == IS_ARRAY) { - zend_make_immutable_array_r(&result->u.constant TSRMLS_CC); - } } else if (zend_ast_is_ct_constant(ast)) { zend_ast_evaluate(&result->u.constant, ast, NULL TSRMLS_CC); zend_ast_destroy(ast); - if (Z_TYPE(result->u.constant) == IS_ARRAY) { - zend_make_immutable_array_r(&result->u.constant TSRMLS_CC); - } } else { ZVAL_NEW_AST(&result->u.constant, ast); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 4c28be91f3..3a085f6db7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -461,7 +461,6 @@ typedef int (*unary_op_type)(zval *, zval * TSRMLS_DC); typedef int (*binary_op_type)(zval *, zval *, zval * TSRMLS_DC); ZEND_API unary_op_type get_unary_op(int opcode); ZEND_API binary_op_type get_binary_op(int opcode); -ZEND_API void zend_make_immutable_array(zval *zv TSRMLS_DC); void zend_do_while_cond(znode *expr, znode *close_bracket_token TSRMLS_DC); void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC); diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index b134ed4cfe..64ea7060fa 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -32,9 +32,7 @@ void free_zend_constant(zval *zv) zend_constant *c = Z_PTR_P(zv); if (!(c->flags & CONST_PERSISTENT)) { - if (Z_REFCOUNTED(c->value) || Z_IMMUTABLE(c->value)) { - _zval_dtor_func(Z_COUNTED(c->value) ZEND_FILE_LINE_CC); - } + zval_dtor(&c->value); } else { zval_internal_dtor(&c->value); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index e4ba9597a6..9c5c17fd8f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3835,7 +3835,7 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST) retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -4478,6 +4478,8 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 761f4c630c..93ad949162 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3095,6 +3095,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -4137,7 +4139,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -8601,6 +8603,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -14030,6 +14034,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { @@ -16173,7 +16179,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -25440,7 +25446,7 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC retval = EX_VAR(opline->result.var); ZVAL_COPY_VALUE(retval, &c->value); if (Z_OPT_COPYABLE_P(retval) || Z_OPT_REFCOUNTED_P(retval)) { - if (Z_OPT_COPYABLE_P(retval) && (c->flags & CONST_PERSISTENT)) { + if (Z_OPT_COPYABLE_P(retval)) { zval_copy_ctor_func(retval); } else { Z_ADDREF_P(retval); @@ -31369,6 +31375,8 @@ static int ZEND_FASTCALL ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS } } else if (Z_IMMUTABLE_P(array_ptr)) { zval_copy_ctor(array_ptr); + } else { + SEPARATE_ZVAL_NOREF(array_ptr); } if (Z_REFCOUNTED_P(array_ref)) Z_ADDREF_P(array_ref); } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c index 8bf5449e14..43140b2f41 100644 --- a/ext/intl/collator/collator_sort.c +++ b/ext/intl/collator/collator_sort.c @@ -498,7 +498,7 @@ PHP_FUNCTION( collator_sort_with_sort_keys ) /* sort it */ zend_qsort( sortKeyIndxBuf, sortKeyCount, sortKeyIndxSize, collator_cmp_sort_keys TSRMLS_CC ); - zval_dtor( array ); + zval_ptr_dtor( array ); /* for resulting hash we'll assign new hash keys rather then reordering */ array_init(array); diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index e4e1f74acc..fd711cb9ee 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -110,9 +110,6 @@ int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) int i = op_array->last_literal; op_array->last_literal++; op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval)); - if (Z_TYPE_P(zv) == IS_ARRAY) { - zend_make_immutable_array(zv TSRMLS_CC); - } ZVAL_COPY_VALUE(&op_array->literals[i], zv); Z_CACHE_SLOT(op_array->literals[i]) = -1; //??? Z_SET_REFCOUNT(op_array->literals[i].constant, 2); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 69eecfd641..070d77670b 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -195,6 +195,7 @@ static void zend_persist_zval(zval *z TSRMLS_DC) new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); if (new_ptr) { Z_ARR_P(z) = new_ptr; + Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; } else { if (Z_IMMUTABLE_P(z)) { Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array)); @@ -202,6 +203,10 @@ static void zend_persist_zval(zval *z TSRMLS_DC) } else { zend_accel_store(Z_ARR_P(z), sizeof(zend_array)); zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval TSRMLS_CC); + /* make immutable array */ + Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; + GC_REFCOUNT(Z_COUNTED_P(z)) = 2; + Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; } } break; @@ -252,6 +257,7 @@ static void zend_persist_zval_const(zval *z TSRMLS_DC) new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z)); if (new_ptr) { Z_ARR_P(z) = new_ptr; + Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; } else { if (Z_IMMUTABLE_P(z)) { Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array)); @@ -259,6 +265,10 @@ static void zend_persist_zval_const(zval *z TSRMLS_DC) } else { zend_accel_store(Z_ARR_P(z), sizeof(zend_array)); zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval TSRMLS_CC); + /* make immutable array */ + Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE; + GC_REFCOUNT(Z_COUNTED_P(z)) = 2; + Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION; } } break; -- 2.40.0