diff options
author | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:34:37 -0400 |
---|---|---|
committer | Mark A. Hershberger <mah@debian.(none)> | 2009-03-25 00:34:37 -0400 |
commit | 10f5b47dc7c1cf2b9a00991629f43652710322d3 (patch) | |
tree | 3b727a16f652b8042d573e90f003868ffb3b56c7 /Zend/zend_execute.c | |
parent | 0e920280a2e04b110827bb766b9f29e3d581c4ee (diff) | |
download | php-10f5b47dc7c1cf2b9a00991629f43652710322d3.tar.gz |
Imported Upstream version 5.0.5upstream/5.0.5
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r-- | Zend/zend_execute.c | 427 |
1 files changed, 266 insertions, 161 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index ebff3e976..5bdc015c0 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: zend_execute.c,v 1.652.2.22 2005/03/21 16:22:10 andi Exp $ */ +/* $Id: zend_execute.c,v 1.652.2.49 2005/09/01 13:21:56 dmitry Exp $ */ #define ZEND_INTENSIVE_DEBUGGING 0 @@ -54,6 +54,17 @@ static void zend_extension_fcall_end_handler(zend_extension *extension, zend_op_ #define TEMP_VAR_STACK_LIMIT 2000 +#define MAKE_REAL_ZVAL_PTR(val) \ + do { \ + zval *_tmp; \ + ALLOC_ZVAL(_tmp); \ + _tmp->value = (val)->value; \ + _tmp->type = (val)->type; \ + _tmp->refcount = 1; \ + _tmp->is_ref = 0; \ + val = _tmp; \ + } while (0) + /* former zend_execute_locks.h */ static inline void zend_pzval_lock_func(zval *z) { @@ -154,22 +165,9 @@ static inline zval **_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC) static inline void zend_fetch_property_address_inner(zval *object, znode *op2, znode *result, temp_variable *Ts, int type TSRMLS_DC) { zval *prop_ptr = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); - zval tmp; - - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *prop_ptr; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - prop_ptr = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(prop_ptr); - break; + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(prop_ptr); } if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { @@ -192,10 +190,9 @@ static inline void zend_fetch_property_address_inner(zval *object, znode *op2, z T(result->u.var).var.ptr_ptr = &EG(error_zval_ptr); } - if (prop_ptr == &tmp) { - zval_dtor(prop_ptr); + if (EG(free_op2)) { + zval_ptr_dtor(&prop_ptr); } - FREE_OP(Ts, op2, EG(free_op2)); } @@ -240,12 +237,6 @@ void zend_assign_to_variable_reference(znode *result, zval **variable_ptr_ptr, z if (variable_ptr == EG(error_zval_ptr) || value_ptr==EG(error_zval_ptr)) { variable_ptr_ptr = &EG(uninitialized_zval_ptr); } else if (variable_ptr != value_ptr) { - variable_ptr->refcount--; - if (variable_ptr->refcount==0) { - zendi_zval_dtor(*variable_ptr); - FREE_ZVAL(variable_ptr); - } - if (!PZVAL_IS_REF(value_ptr)) { /* break it away */ value_ptr->refcount--; @@ -258,9 +249,14 @@ void zend_assign_to_variable_reference(znode *result, zval **variable_ptr_ptr, z value_ptr->refcount = 1; value_ptr->is_ref = 1; } - *variable_ptr_ptr = value_ptr; value_ptr->refcount++; + + variable_ptr->refcount--; + if (variable_ptr->refcount==0) { + zendi_zval_dtor(*variable_ptr); + FREE_ZVAL(variable_ptr); + } } else if (!variable_ptr->is_ref) { if (variable_ptr_ptr == value_ptr_ptr) { SEPARATE_ZVAL(variable_ptr_ptr); @@ -393,15 +389,27 @@ static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode /* separate our value if necessary */ if (EG(ze1_compatibility_mode) && Z_TYPE_P(value) == IS_OBJECT) { zval *orig_value = value; - + char *class_name; + zend_uint class_name_len; + int dup; + ALLOC_ZVAL(value); *value = *orig_value; value->is_ref = 0; value->refcount = 0; + + dup = zend_get_object_classname(orig_value, &class_name, &class_name_len TSRMLS_CC); + if (Z_OBJ_HANDLER_P(value, clone_obj) == NULL) { - zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", Z_OBJCE_P(orig_value)->name); + zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(orig_value)->name); + + zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + + if(!dup) { + efree(class_name); + } + value->value.obj = Z_OBJ_HANDLER_P(orig_value, clone_obj)(orig_value TSRMLS_CC); } else if (value_op->op_type == IS_TMP_VAR) { zval *orig_value = value; @@ -423,40 +431,29 @@ static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode value->refcount++; if (opcode == ZEND_ASSIGN_OBJ) { - zval tmp; - - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *property_name; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - property_name = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(property_name); - break; + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(property_name); } Z_OBJ_HT_P(object)->write_property(object, property_name, value TSRMLS_CC); - if (property_name == &tmp) { - zval_dtor(property_name); - } } else { /* Note: property_name in this case is really the array index! */ if (!Z_OBJ_HT_P(object)->write_dimension) { zend_error(E_ERROR, "Cannot use object as array"); } + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(property_name); + } Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC); } - FREE_OP(Ts, op2, EG(free_op2)); if (result) { T(result->u.var).var.ptr = value; T(result->u.var).var.ptr_ptr = &T(result->u.var).var.ptr; /* this is so that we could use it in FETCH_DIM_R, etc. - see bug #27876 */ SELECTIVE_PZVAL_LOCK(value, result); } + if (EG(free_op2)) { + zval_ptr_dtor(&property_name); + } zval_ptr_dtor(&value); } @@ -566,40 +563,60 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2 } if (EG(ze1_compatibility_mode) && Z_TYPE_P(value) == IS_OBJECT) { + char *class_name; + zend_uint class_name_len; + int dup; + + dup = zend_get_object_classname(value, &class_name, &class_name_len TSRMLS_CC); + if (Z_OBJ_HANDLER_P(value, clone_obj) == NULL) { - zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", Z_OBJCE_P(value)->name); + zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); } else if (PZVAL_IS_REF(variable_ptr)) { - if (variable_ptr != value) { + if (variable_ptr != value) { zend_uint refcount = variable_ptr->refcount; zval garbage; - + if (type != IS_TMP_VAR) { value->refcount++; } + garbage = *variable_ptr; *variable_ptr = *value; variable_ptr->refcount = refcount; variable_ptr->is_ref = 1; - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(value)->name); + + zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC); + if (type != IS_TMP_VAR) { value->refcount--; } + zendi_zval_dtor(garbage); } } else { - variable_ptr->refcount--; - if (variable_ptr->refcount == 0) { - zendi_zval_dtor(*variable_ptr); - } else { - ALLOC_ZVAL(variable_ptr); - *variable_ptr_ptr = variable_ptr; + if (variable_ptr != value) { + value->refcount++; + variable_ptr->refcount--; + if (variable_ptr->refcount == 0) { + zendi_zval_dtor(*variable_ptr); + } else { + ALLOC_ZVAL(variable_ptr); + *variable_ptr_ptr = variable_ptr; + } + *variable_ptr = *value; + INIT_PZVAL(variable_ptr); + zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); + variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC); + zval_ptr_dtor(&value); } - *variable_ptr = *value; - INIT_PZVAL(variable_ptr); - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(value)->name); - variable_ptr->value.obj = Z_OBJ_HANDLER_P(value, clone_obj)(value TSRMLS_CC); } + + if(!dup) { + efree(class_name); + } + } else if (PZVAL_IS_REF(variable_ptr)) { if (variable_ptr!=value) { zend_uint refcount = variable_ptr->refcount; @@ -945,7 +962,7 @@ static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2, new_zval->refcount++; if (zend_hash_next_index_insert(container->value.ht, &new_zval, sizeof(zval *), (void **) retval) == FAILURE) { zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied"); - *retval = &EG(uninitialized_zval_ptr); + *retval = &EG(error_zval_ptr); new_zval->refcount--; } } else { @@ -1003,8 +1020,12 @@ static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2, zend_error(E_ERROR, "Cannot use object as array"); } else { zval *dim = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); - zval *overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC); + zval *overloaded_result; + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(dim); + } + overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC); if (overloaded_result) { switch (type) { case BP_VAR_RW: @@ -1021,8 +1042,10 @@ static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2, *retval = &EG(error_zval_ptr); } AI_USE_PTR(T(result->u.var).var); - FREE_OP(Ts, op2, EG(free_op2)); SELECTIVE_PZVAL_LOCK(**retval, result); + if (EG(free_op2)) { + zval_ptr_dtor(&dim); + } } break; default: { @@ -1140,41 +1163,29 @@ static void zend_fetch_property_address_read(znode *result, znode *op1, znode *o } else { *retval = EG(error_zval_ptr); } + SELECTIVE_PZVAL_LOCK(*retval, result); } else { zval *offset; - zval tmp; offset = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *offset; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - offset = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(offset); - break; + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(offset); } /* here we are sure we are dealing with an object */ *retval = Z_OBJ_HT_P(container)->read_property(container, offset, type TSRMLS_CC); - if (offset == &tmp) { - zval_dtor(offset); - } - FREE_OP(Ts, op2, EG(free_op2)); if (RETURN_VALUE_UNUSED(result) && ((*retval)->refcount == 0)) { zval_dtor(*retval); FREE_ZVAL(*retval); - return; /* no need for locking */ + } else { + SELECTIVE_PZVAL_LOCK(*retval, result); + } + + if (EG(free_op2)) { + zval_ptr_dtor(&offset); } } - - SELECTIVE_PZVAL_LOCK(*retval, result); } static void zend_pre_incdec_property(znode *result, znode *op1, znode *op2, temp_variable * Ts, int (*incdec_op)(zval *) TSRMLS_DC) @@ -1197,6 +1208,10 @@ static void zend_pre_incdec_property(znode *result, znode *op1, znode *op2, temp return; } + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(property); + } + /* here we are sure we are dealing with an object */ if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { @@ -1232,7 +1247,9 @@ static void zend_pre_incdec_property(znode *result, znode *op1, znode *op2, temp zval_ptr_dtor(&z); } - FREE_OP(Ts, op2, EG(free_op2)); + if (EG(free_op2)) { + zval_ptr_dtor(&property); + } } static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, temp_variable * Ts, int (*incdec_op)(zval *) TSRMLS_DC) @@ -1253,6 +1270,10 @@ static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, tem return; } + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(property); + } + /* here we are sure we are dealing with an object */ if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { @@ -1271,6 +1292,7 @@ static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, tem if (!have_get_ptr) { zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); + zval *z_copy; if (z->type == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); @@ -1283,13 +1305,22 @@ static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, tem } *retval = *z; zendi_zval_copy_ctor(*retval); - incdec_op(z); + ALLOC_ZVAL(z_copy); + *z_copy = *z; + zendi_zval_copy_ctor(*z_copy); + INIT_PZVAL(z_copy); + incdec_op(z_copy); z->refcount++; - Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC); + Z_OBJ_HT_P(object)->write_property(object, property, z_copy TSRMLS_CC); + zval_ptr_dtor(&z_copy); + /* this would destroy z if it was returned with refcount == 0 and undo + recount++ above otherwise */ zval_ptr_dtor(&z); } - FREE_OP(Ts, op2, EG(free_op2)); + if (EG(free_op2)) { + zval_ptr_dtor(&property); + } } @@ -1328,7 +1359,7 @@ static int zend_check_symbol(zval **pz TSRMLS_DC) #define SET_OPCODE(new_op) \ CHECK_SYMBOL_TABLES() \ - EX(opline) = new_op; + EX(opline) = new_op; \ #define INC_OPCODE() \ if (!EG(exception)) { \ @@ -1638,7 +1669,6 @@ static inline int zend_binary_assign_op_obj_helper(int (*binary_op)(zval *result zval *property = get_zval_ptr(&opline->op2, EX(Ts), &EG(free_op2), BP_VAR_R); zval *free_value; zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_value, BP_VAR_R); - zval tmp; znode *result = &opline->result; zval **retval = &EX_T(result->u.var).var.ptr; int have_get_ptr = 0; @@ -1657,19 +1687,8 @@ static inline int zend_binary_assign_op_obj_helper(int (*binary_op)(zval *result SELECTIVE_PZVAL_LOCK(*retval, result); } else { /* here we are sure we are dealing with an object */ - switch (opline->op2.op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *property; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - property = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(property); - break; + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(property); } /* here property is a string */ @@ -1722,11 +1741,9 @@ static inline int zend_binary_assign_op_obj_helper(int (*binary_op)(zval *result zval_ptr_dtor(&z); } - if (property == &tmp) { - zval_dtor(property); + if (EG(free_op2)) { + zval_ptr_dtor(&property); } - - FREE_OP(Ts, op2, EG(free_op2)); FREE_OP(Ts, value, free_value); } @@ -2114,6 +2131,9 @@ int zend_fetch_dim_func_arg_handler(ZEND_OPCODE_HANDLER_ARGS) /* Behave like FETCH_DIM_W */ zend_fetch_dimension_address(&opline->result, &opline->op1, &opline->op2, EX(Ts), BP_VAR_W TSRMLS_CC); } else { + if (opline->op2.op_type == IS_UNUSED) { + zend_error(E_ERROR, "Cannot use [] for reading"); + } /* Behave like FETCH_DIM_R, except for locking used for list() */ zend_fetch_dimension_address(&opline->result, &opline->op1, &opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); AI_USE_PTR(EX_T(opline->result.u.var).var); @@ -2246,7 +2266,7 @@ int zend_assign_dim_handler(ZEND_OPCODE_HANDLER_ARGS) zend_fetch_dimension_address(&op_data->op2, &opline->op1, &opline->op2, EX(Ts), BP_VAR_W TSRMLS_CC); value = get_zval_ptr(&op_data->op1, EX(Ts), &EG(free_op1), BP_VAR_R); - zend_assign_to_variable(&opline->result, &op_data->op2, &op_data->op1, value, (EG(free_op1)?IS_TMP_VAR:opline->op1.op_type), EX(Ts) TSRMLS_CC); + zend_assign_to_variable(&opline->result, &op_data->op2, &op_data->op1, value, (EG(free_op1)?IS_TMP_VAR:op_data->op1.op_type), EX(Ts) TSRMLS_CC); } /* assign_dim has two opcodes! */ INC_OPCODE(); @@ -2270,6 +2290,19 @@ int zend_assign_ref_handler(ZEND_OPCODE_HANDLER_ARGS) { zval **value_ptr_ptr = get_zval_ptr_ptr(&opline->op2, EX(Ts), BP_VAR_W); + if (opline->op2.op_type == IS_VAR && + value_ptr_ptr && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + zend_error(E_STRICT, "Only variables should be assigned by reference"); + return zend_assign_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + if (opline->op1.op_type == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { + zend_error(E_ERROR, "Cannot assign by reference to overloaded object"); + } + zend_assign_to_variable_reference(&opline->result, get_zval_ptr_ptr(&opline->op1, EX(Ts), BP_VAR_W), value_ptr_ptr, EX(Ts) TSRMLS_CC); NEXT_OPCODE(); @@ -2454,7 +2487,7 @@ int zend_fetch_class_handler(ZEND_OPCODE_HANDLER_ARGS) if (opline->op2.op_type == IS_UNUSED) { - EX_T(opline->result.u.var).class_entry = zend_fetch_class(NULL, ZEND_FETCH_CLASS_AUTO, opline->extended_value TSRMLS_CC); + EX_T(opline->result.u.var).class_entry = zend_fetch_class(NULL, 0, opline->extended_value TSRMLS_CC); NEXT_OPCODE(); } @@ -2465,7 +2498,7 @@ int zend_fetch_class_handler(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); break; case IS_STRING: - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC); + EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); break; default: zend_error(E_ERROR, "Class name must be a valid object or a string"); @@ -2806,9 +2839,11 @@ int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS) if (EG(exception) && EX(fbc) && EX(fbc)->common.fn_flags&ZEND_ACC_CTOR) { EG(This)->refcount--; if (EG(This)->refcount == 1) { - zend_object_store_ctor_failed(EG(This) TSRMLS_CC); + zend_object_store_ctor_failed(EG(This) TSRMLS_CC); + } + if (should_change_scope && EG(This) != current_this) { + zval_ptr_dtor(&EG(This)); } - zval_ptr_dtor(&EG(This)); } else if (should_change_scope) { zval_ptr_dtor(&EG(This)); } @@ -2879,10 +2914,11 @@ int zend_return_handler(ZEND_OPCODE_HANDLER_ARGS) } if (!(*retval_ptr_ptr)->is_ref) { - if (EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr - || (opline->extended_value == ZEND_RETURNS_FUNCTION && !EX_T(opline->op1.u.var).var.fcall_returned_reference)) { - zend_error(E_STRICT, "Only variable references should be returned by reference"); + if (opline->extended_value == ZEND_RETURNS_FUNCTION && + EX_T(opline->op1.u.var).var.fcall_returned_reference) { + } else if (EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + zend_error(E_STRICT, "Only variable references should be returned by reference"); goto return_by_value; } } @@ -2896,16 +2932,27 @@ return_by_value: retval_ptr = get_zval_ptr(&opline->op1, EX(Ts), &EG(free_op1), BP_VAR_R); if (EG(ze1_compatibility_mode) && Z_TYPE_P(retval_ptr) == IS_OBJECT) { + char *class_name; + zend_uint class_name_len; + int dup; + + dup = zend_get_object_classname(retval_ptr, &class_name, &class_name_len TSRMLS_CC); + ALLOC_ZVAL(*(EG(return_value_ptr_ptr))); **EG(return_value_ptr_ptr) = *retval_ptr; INIT_PZVAL(*EG(return_value_ptr_ptr)); if (Z_OBJ_HT_P(retval_ptr)->clone_obj == NULL) { - zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", Z_OBJCE_P(retval_ptr)->name); + zend_error(E_ERROR, "Trying to clone an uncloneable object of class %s", class_name); } - zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", Z_OBJCE_P(retval_ptr)->name); + zend_error(E_STRICT, "Implicit cloning object of class '%s' because of 'zend.ze1_compatibility_mode'", class_name); (*EG(return_value_ptr_ptr))->value.obj = Z_OBJ_HT_P(retval_ptr)->clone_obj(retval_ptr TSRMLS_CC); + + if(!dup) { + efree(class_name); + } } else if (!EG(free_op1)) { /* Not a temp var */ - if (PZVAL_IS_REF(retval_ptr) && retval_ptr->refcount > 0) { + if (EG(active_op_array)->return_reference == ZEND_RETURN_REF || + (PZVAL_IS_REF(retval_ptr) && retval_ptr->refcount > 0)) { ALLOC_ZVAL(*(EG(return_value_ptr_ptr))); **EG(return_value_ptr_ptr) = *retval_ptr; (*EG(return_value_ptr_ptr))->is_ref = 0; @@ -3036,7 +3083,10 @@ int zend_send_var_no_ref_handler(ZEND_OPCODE_HANDLER_ARGS) } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) { return zend_send_by_var_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } - { + if ((opline->extended_value & ZEND_ARG_SEND_FUNCTION) && + !EX_T(opline->op1.u.var).var.fcall_returned_reference) { + zend_error(E_ERROR, "Only variables can be passed by reference"); + } else { zval *varptr; varptr = get_zval_ptr(&opline->op1, EX(Ts), &EG(free_op1), BP_VAR_R); @@ -3291,7 +3341,7 @@ int zend_clone_handler(ZEND_OPCODE_HANDLER_ARGS) NEXT_OPCODE(); } - ce = Z_OBJCE_P(obj); + ce = (Z_OBJ_HT_P(obj)->get_class_entry) ? Z_OBJCE_P(obj) : NULL; clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { @@ -3654,62 +3704,70 @@ int zend_unset_dim_obj_handler(ZEND_OPCODE_HANDLER_ARGS) long index; if (container) { - HashTable *ht; - if (opline->extended_value == ZEND_UNSET_DIM) { switch (Z_TYPE_PP(container)) { - case IS_ARRAY: - ht = Z_ARRVAL_PP(container); + case IS_ARRAY: { + HashTable *ht = Z_ARRVAL_PP(container); + switch (offset->type) { + case IS_DOUBLE: + case IS_RESOURCE: + case IS_BOOL: + case IS_LONG: + if (offset->type == IS_DOUBLE) { + index = (long) offset->value.dval; + } else { + index = offset->value.lval; + } + + zend_hash_index_del(ht, index); + break; + case IS_STRING: + zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1); + break; + case IS_NULL: + zend_hash_del(ht, "", sizeof("")); + break; + default: + zend_error(E_WARNING, "Illegal offset type in unset"); + break; + } + FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); break; + } case IS_OBJECT: - ht = NULL; if (!Z_OBJ_HT_P(*container)->unset_dimension) { zend_error(E_ERROR, "Cannot use object as array"); } + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(offset); + } Z_OBJ_HT_P(*container)->unset_dimension(*container, offset TSRMLS_CC); + if (EG(free_op2)) { + zval_ptr_dtor(&offset); + } break; case IS_STRING: zend_error(E_ERROR, "Cannot unset string offsets"); return 0; /* bailed out before */ default: - ht = NULL; + FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); break; } } else { /* ZEND_UNSET_OBJ */ - ht = NULL; if (Z_TYPE_PP(container) == IS_OBJECT) { + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(offset); + } Z_OBJ_HT_P(*container)->unset_property(*container, offset TSRMLS_CC); - } - } - if (ht) { - switch (offset->type) { - case IS_DOUBLE: - case IS_RESOURCE: - case IS_BOOL: - case IS_LONG: - if (offset->type == IS_DOUBLE) { - index = (long) offset->value.dval; - } else { - index = offset->value.lval; - } - - zend_hash_index_del(ht, index); - break; - case IS_STRING: - zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1); - break; - case IS_NULL: - zend_hash_del(ht, "", sizeof("")); - break; - default: - zend_error(E_WARNING, "Illegal offset type in unset"); - break; + if (EG(free_op2)) { + zval_ptr_dtor(&offset); + } } } } else { /* overloaded element */ + FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); } - FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); NEXT_OPCODE(); } @@ -3727,6 +3785,12 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS) if (array_ptr_ptr == NULL) { ALLOC_INIT_ZVAL(array_ptr); } else if (Z_TYPE_PP(array_ptr_ptr) == IS_OBJECT) { + if(Z_OBJ_HT_PP(array_ptr_ptr)->get_class_entry == NULL) { + zend_error(E_WARNING, "foreach() can not iterate over objects without PHP class"); + opline++; + SET_OPCODE(op_array->opcodes+opline->op2.u.opline_num); + return 0; + } ce = Z_OBJCE_PP(array_ptr_ptr); if (!ce || ce->get_iterator == NULL) { SEPARATE_ZVAL_IF_NOT_REF(array_ptr_ptr); @@ -3747,7 +3811,7 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS) *tmp = *array_ptr; INIT_PZVAL(tmp); array_ptr = tmp; - } else if (Z_TYPE_P(array_ptr) == IS_OBJECT) { + } else if (Z_TYPE_P(array_ptr) == IS_OBJECT && Z_OBJ_HT_P(array_ptr)->get_class_entry) { ce = Z_OBJCE_P(array_ptr); } else { array_ptr->refcount++; @@ -3760,7 +3824,6 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS) if (iter && !EG(exception)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { - zval_ptr_dtor(&array_ptr); FREE_OP(Ts, op1, EG(free_op1)); if (!EG(exception)) { zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); @@ -3779,6 +3842,11 @@ int zend_fe_reset_handler(ZEND_OPCODE_HANDLER_ARGS) iter->index = 0; if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); + if (EG(exception)) { + array_ptr->refcount--; + zval_ptr_dtor(&array_ptr); + NEXT_OPCODE(); + } } } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { /* probably redundant */ @@ -3855,13 +3923,28 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS) /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ iter->funcs->move_forward(iter TSRMLS_CC); + if (EG(exception)) { + array->refcount--; + zval_ptr_dtor(&array); + NEXT_OPCODE(); + } } if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) { /* reached end of iteration */ + if (EG(exception)) { + array->refcount--; + zval_ptr_dtor(&array); + NEXT_OPCODE(); + } SET_OPCODE(op_array->opcodes+opline->op2.u.opline_num); return 0; /* CHECK_ME */ } iter->funcs->get_current_data(iter, &value TSRMLS_CC); + if (EG(exception)) { + array->refcount--; + zval_ptr_dtor(&array); + NEXT_OPCODE(); + } if (!value) { /* failure in get_current_data */ SET_OPCODE(op_array->opcodes+opline->op2.u.opline_num); @@ -3869,6 +3952,11 @@ int zend_fe_fetch_handler(ZEND_OPCODE_HANDLER_ARGS) } if (iter->funcs->get_current_key) { key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + if (EG(exception)) { + array->refcount--; + zval_ptr_dtor(&array); + NEXT_OPCODE(); + } } else { key_type = HASH_KEY_IS_LONG; int_key = iter->index; @@ -3991,12 +4079,13 @@ int zend_isset_isempty_var_handler(ZEND_OPCODE_HANDLER_ARGS) static int zend_isset_isempty_dim_prop_obj_handler(int prop_dim, ZEND_OPCODE_HANDLER_ARGS) { zval **container = get_obj_zval_ptr_ptr(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); - zval *offset = get_zval_ptr(&opline->op2, EX(Ts), &EG(free_op2), BP_VAR_R); zval **value = NULL; int result = 0; long index; if (container) { + zval *offset = get_zval_ptr(&opline->op2, EX(Ts), &EG(free_op2), BP_VAR_R); + if ((*container)->type == IS_ARRAY) { HashTable *ht; int isset = 0; @@ -4049,12 +4138,19 @@ static int zend_isset_isempty_dim_prop_obj_handler(int prop_dim, ZEND_OPCODE_HAN } break; } + FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); } else if ((*container)->type == IS_OBJECT) { + if (EG(free_op2)) { + MAKE_REAL_ZVAL_PTR(offset); + } if (prop_dim) { result = Z_OBJ_HT_P(*container)->has_property(*container, offset, (opline->extended_value == ZEND_ISEMPTY) TSRMLS_CC); } else { result = Z_OBJ_HT_P(*container)->has_dimension(*container, offset, (opline->extended_value == ZEND_ISEMPTY) TSRMLS_CC); } + if (EG(free_op2)) { + zval_ptr_dtor(&offset); + } } else if ((*container)->type == IS_STRING && !prop_dim) { /* string offsets */ zval tmp; @@ -4076,6 +4172,9 @@ static int zend_isset_isempty_dim_prop_obj_handler(int prop_dim, ZEND_OPCODE_HAN } break; } + FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); + } else { + FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); } } @@ -4090,8 +4189,6 @@ static int zend_isset_isempty_dim_prop_obj_handler(int prop_dim, ZEND_OPCODE_HAN break; } - FREE_OP(EX(Ts), &opline->op2, EG(free_op2)); - NEXT_OPCODE(); } @@ -4234,7 +4331,7 @@ int zend_instanceof_handler(ZEND_OPCODE_HANDLER_ARGS) zval *expr = get_zval_ptr(&opline->op1, EX(Ts), &EG(free_op1), BP_VAR_R); zend_bool result; - if (Z_TYPE_P(expr) == IS_OBJECT) { + if (Z_TYPE_P(expr) == IS_OBJECT && Z_OBJ_HT_P(expr)->get_class_entry) { result = instanceof_function(Z_OBJCE_P(expr), EX_T(opline->op2.u.var).class_entry TSRMLS_CC); } else { result = 0; @@ -4284,6 +4381,7 @@ int zend_handle_exception_handler(ZEND_OPCODE_HANDLER_ARGS) while (*stack_zval_pp != NULL) { zval_ptr_dtor(stack_zval_pp); EG(argument_stack).top_element--; + EG(argument_stack).top--; stack_zval_pp--; } @@ -4298,6 +4396,13 @@ int zend_handle_exception_handler(ZEND_OPCODE_HANDLER_ARGS) } } + while (EX(fbc)) { + if (EX(object)) { + zval_ptr_dtor(&EX(object)); + } + zend_ptr_stack_n_pop(&EG(arg_types_stack), 3, &EX(calling_scope), &EX(object), &EX(fbc)); + } + if (encapsulating_block == -1) { RETURN_FROM_EXECUTE_LOOP(execute_data); } else { |