mirror of
https://github.com/php/php-src.git
synced 2024-12-02 14:24:10 +08:00
- Disallow foreach($v as &$ref) when $v is an object that implements
interface Iterator. The signature of Iterator::current() doesn't allow that. Maybe ppl also want IteratorByReference or similar. Unfortunatley this comes with an API change but there is no easier way.
This commit is contained in:
parent
a6e8746bbe
commit
c8d78028b5
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user