diff --git a/Zend/zend.h b/Zend/zend.h index b665b80f5be..99a0ba112ab 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -357,7 +357,7 @@ struct _zend_class_entry { /* handlers */ zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC); - zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object TSRMLS_DC); + zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */ /* serializer callbacks */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bb3894ceaa9..ed514892c0a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3757,7 +3757,7 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno opline->result.u.var = get_temporary_variable(CG(active_op_array)); opline->op1 = *array; SET_UNUSED(opline->op2); - opline->extended_value = is_variable; + opline->extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0; *open_brackets_token = opline->result; { @@ -3830,6 +3830,7 @@ void zend_do_foreach_cont(znode *foreach_token, znode *as_token, znode *value, z } /* Mark extended_value for assign-by-reference */ opline->extended_value |= ZEND_FE_FETCH_BYREF; + CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE; } value_node = opline->result; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index d3a681a4008..3178cf60d4f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -661,6 +661,9 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_FE_FETCH_BYREF 1 #define ZEND_FE_FETCH_WITH_KEY 2 +#define ZEND_FE_RESET_VARIABLE 1 +#define ZEND_FE_RESET_REFERENCE 2 + #define ZEND_MEMBER_FUNC_CALL 1<<0 #define ZEND_ARG_SEND_BY_REF (1<<0) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index e8a9965bfbf..b1a76b912e5 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -34,6 +34,7 @@ #include "zend_fast_cache.h" #include "zend_ini.h" #include "zend_exceptions.h" +#include "zend_interfaces.h" #include "zend_vm.h" #include "zend_unicode.h" diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 6f01ffe4a16..edd39a62f33 100755 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -270,9 +270,15 @@ zend_object_iterator_funcs zend_interface_iterator_funcs_iterator = { }; /* {{{ zend_user_it_get_iterator */ -static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) +static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) { - zend_user_iterator *iterator = emalloc(sizeof(zend_user_iterator)); + zend_user_iterator *iterator; + + if (by_ref) { + zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); + } + + iterator = emalloc(sizeof(zend_user_iterator)); object->refcount++; iterator->it.data = (void*)object; @@ -284,7 +290,7 @@ static zend_object_iterator *zend_user_it_get_iterator(zend_class_entry *ce, zva /* }}} */ /* {{{ zend_user_it_get_new_iterator */ -static zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object TSRMLS_DC) +ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) { zval *iterator = zend_user_it_new_iterator(ce, object TSRMLS_CC); zend_object_iterator *new_iterator; @@ -302,7 +308,11 @@ static zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, } return NULL; } - new_iterator = ce_it->get_iterator(ce_it, iterator TSRMLS_CC); + if (by_ref && ce_it && instanceof_function(ce_it, zend_ce_iterator TSRMLS_CC)) { + zend_error(E_ERROR, "An iterator cannot be used with foreach by reference"); + } + + new_iterator = ce_it->get_iterator(ce_it, iterator, by_ref TSRMLS_CC); zval_ptr_dtor(&iterator); return new_iterator; } diff --git a/Zend/zend_interfaces.h b/Zend/zend_interfaces.h index 55fc7ea94c4..f56eb62bc8c 100755 --- a/Zend/zend_interfaces.h +++ b/Zend/zend_interfaces.h @@ -49,6 +49,8 @@ ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend #define zend_call_method_with_2_params(obj, obj_ce, fn_proxy, function_name, retval, arg1, arg2) \ zend_call_method(obj, obj_ce, fn_proxy, function_name, sizeof(function_name)-1, retval, 2, arg1, arg2 TSRMLS_CC) +ZEND_API zend_object_iterator *zend_user_it_get_new_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC); + ZEND_API void zend_register_interfaces(TSRMLS_D); END_EXTERN_C() diff --git a/Zend/zend_iterators.h b/Zend/zend_iterators.h index b74e291bd18..4400507b77d 100755 --- a/Zend/zend_iterators.h +++ b/Zend/zend_iterators.h @@ -57,11 +57,8 @@ struct _zend_object_iterator { ulong index; /* private to fe_reset/fe_fetch opcodes */ }; -typedef zval *(*zend_object_new_iterator_t)(zend_class_entry *ce, zval *object TSRMLS_DC); - typedef struct _zend_class_iterator_funcs { zend_object_iterator_funcs *funcs; - zend_object_new_iterator_t new_iterator; union _zend_function *zf_new_iterator; union _zend_function *zf_valid; union _zend_function *zf_current; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 783b150dbed..b07ea0c6be5 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3041,7 +3041,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) zend_class_entry *ce = NULL; zend_bool is_empty = 0; - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { array_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R); if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) { ALLOC_INIT_ZVAL(array_ptr); @@ -3078,12 +3078,12 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) } if (ce && ce->get_iterator) { - iter = ce->get_iterator(ce, array_ptr TSRMLS_CC); + iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC); if (iter && !EG(exception)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { FREE_OP1_VAR_PTR(); } else { FREE_OP1_IF_VAR(); @@ -3140,7 +3140,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) is_empty = 1; } - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { FREE_OP1_VAR_PTR(); } else { FREE_OP1_IF_VAR(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 894b62f71e4..88226faa6ce 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1980,7 +1980,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *ce = NULL; zend_bool is_empty = 0; - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { array_ptr_ptr = NULL; if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) { ALLOC_INIT_ZVAL(array_ptr); @@ -2017,12 +2017,12 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (ce && ce->get_iterator) { - iter = ce->get_iterator(ce, array_ptr TSRMLS_CC); + iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC); if (iter && !EG(exception)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { } else { @@ -2079,7 +2079,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) is_empty = 1; } - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { } else { @@ -4478,7 +4478,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *ce = NULL; zend_bool is_empty = 0; - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { array_ptr_ptr = NULL; if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) { ALLOC_INIT_ZVAL(array_ptr); @@ -4515,12 +4515,12 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (ce && ce->get_iterator) { - iter = ce->get_iterator(ce, array_ptr TSRMLS_CC); + iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC); if (iter && !EG(exception)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { } else { @@ -4577,7 +4577,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) is_empty = 1; } - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { } else { @@ -7573,7 +7573,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *ce = NULL; zend_bool is_empty = 0; - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { array_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) { ALLOC_INIT_ZVAL(array_ptr); @@ -7610,12 +7610,12 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (ce && ce->get_iterator) { - iter = ce->get_iterator(ce, array_ptr TSRMLS_CC); + iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC); if (iter && !EG(exception)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; } else { if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -7672,7 +7672,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) is_empty = 1; } - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; } else { if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; @@ -20213,7 +20213,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_class_entry *ce = NULL; zend_bool is_empty = 0; - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { array_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC); if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) { ALLOC_INIT_ZVAL(array_ptr); @@ -20250,12 +20250,12 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } if (ce && ce->get_iterator) { - iter = ce->get_iterator(ce, array_ptr TSRMLS_CC); + iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC); if (iter && !EG(exception)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { } else { @@ -20312,7 +20312,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) is_empty = 1; } - if (opline->extended_value) { + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { } else {