From: Marcus Boerger Date: Sat, 5 Feb 2005 14:01:59 +0000 (+0000) Subject: - Cleanup foreach statement X-Git-Tag: RELEASE_0_2~78 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=662cd8262e922e4b4c406dbd59749f8cc6fe2814;p=php - Cleanup foreach statement --- diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index b893b12fb1..429d913e34 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3343,7 +3343,7 @@ void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type } -void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC) +void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, int variable TSRMLS_DC) { zend_op *opline; zend_bool is_variable; @@ -3367,6 +3367,9 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack is_variable = 0; } + /* save the location of the beginning of the loop (array fetching) */ + foreach_token->u.opline_num = get_next_op_number(CG(active_op_array)); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); /* Preform array reset */ @@ -3392,10 +3395,17 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack } zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op)); } - - /* save the location of the beginning of the loop (array fetching) */ - opline->op2.u.opline_num = foreach_token->u.opline_num = get_next_op_number(CG(active_op_array)); +} + +void zend_do_foreach_cont(znode *foreach_token, znode *open_brackets_token, znode *as_token, znode *value, znode *key, znode *cont_token TSRMLS_DC) +{ + zend_op *opline; + znode result_value, result_key, dummy; + zend_bool assign_by_ref=0; + + cont_token->u.opline_num = get_next_op_number(CG(active_op_array)); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FE_FETCH; opline->result.op_type = IS_TMP_VAR; @@ -3404,14 +3414,6 @@ void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brack opline->extended_value = 0; SET_UNUSED(opline->op2); *as_token = opline->result; -} - - -void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC) -{ - zend_op *opline; - znode result_value, result_key, dummy; - zend_bool assign_by_ref=0; if (key->op_type != IS_UNUSED) { znode *tmp; @@ -3422,7 +3424,7 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore value = tmp; /* Mark extended_value in case both key and value are being used */ - CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_FETCH_WITH_KEY; + CG(active_op_array)->opcodes[cont_token->u.opline_num].extended_value |= ZEND_FE_FETCH_WITH_KEY; } if ((key->op_type != IS_UNUSED) && (key->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE)) { @@ -3431,11 +3433,11 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore if (value->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE) { assign_by_ref = 1; - if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num-1].extended_value) { + if (!CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value) { zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression"); } /* Mark extended_value for assign-by-reference */ - CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_FETCH_BYREF; + CG(active_op_array)->opcodes[cont_token->u.opline_num].extended_value |= ZEND_FE_FETCH_BYREF; } if (key->op_type != IS_UNUSED) { @@ -3463,14 +3465,14 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore opline->extended_value = ZEND_FETCH_STANDARD; /* ignored in fetch_dim_tmp_var, but what the hell. */ result_key = opline->result; } else { - result_value = CG(active_op_array)->opcodes[foreach_token->u.opline_num].result; + result_value = CG(active_op_array)->opcodes[cont_token->u.opline_num].result; } if (assign_by_ref) { if (key->op_type == IS_UNUSED) { /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */ - CG(active_op_array)->opcodes[foreach_token->u.opline_num].result.op_type = IS_VAR; - zend_do_assign_ref(NULL, value, &CG(active_op_array)->opcodes[foreach_token->u.opline_num].result TSRMLS_CC); + CG(active_op_array)->opcodes[cont_token->u.opline_num].result.op_type = IS_VAR; + zend_do_assign_ref(NULL, value, &CG(active_op_array)->opcodes[cont_token->u.opline_num].result TSRMLS_CC); } else { zend_do_assign_ref(NULL, value, &result_value TSRMLS_CC); } @@ -3489,19 +3491,21 @@ void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *fore } -void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC) +void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token, znode *cont_token TSRMLS_DC) { zend_op *container_ptr; zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMP; - opline->op1.u.opline_num = foreach_token->u.opline_num; + opline->op1.u.opline_num = cont_token->u.opline_num; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); CG(active_op_array)->opcodes[foreach_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[foreach_token->u.opline_num+1].op2.u.opline_num = cont_token->u.opline_num; + CG(active_op_array)->opcodes[cont_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); - do_end_loop(foreach_token->u.opline_num TSRMLS_CC); + do_end_loop(cont_token->u.opline_num TSRMLS_CC); zend_stack_top(&CG(foreach_copy_stack), (void **) &container_ptr); generate_free_foreach_copy(container_ptr TSRMLS_CC); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 825ffca758..0b8c0cfaa6 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -461,9 +461,9 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC void zend_do_instanceof(znode *result, znode *expr, znode *class_znode, int type TSRMLS_DC); -void zend_do_foreach_begin(znode *foreach_token, znode *array, znode *open_brackets_token, znode *as_token, int variable TSRMLS_DC); -void zend_do_foreach_cont(znode *value, znode *key, znode *as_token, znode *foreach_token TSRMLS_DC); -void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token TSRMLS_DC); +void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, int variable TSRMLS_DC); +void zend_do_foreach_cont(znode *foreach_token, znode *open_brackets_token, znode *as_token, znode *value, znode *key, znode *cont_token TSRMLS_DC); +void zend_do_foreach_end(znode *foreach_token, znode *open_brackets_token, znode *cont_token TSRMLS_DC); void zend_do_declare_begin(TSRMLS_D); void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 7dd066fb0a..8ccbc6dca9 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -209,8 +209,14 @@ unticked_statement: | expr ';' { zend_do_free(&$1 TSRMLS_CC); } | T_USE use_filename ';' { zend_error(E_COMPILE_ERROR,"use: Not yet supported. Please use include_once() or require_once()"); zval_dtor(&$2.u.constant); } | T_UNSET '(' unset_variables ')' ';' - | T_FOREACH '(' variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 1 TSRMLS_CC); } foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); } - | T_FOREACH '(' expr_without_variable T_AS { zend_do_foreach_begin(&$1, &$3, &$2, &$4, 0 TSRMLS_CC); } w_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$6, &$7, &$4, &$1 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$2 TSRMLS_CC); } + | T_FOREACH '(' variable T_AS foreach_variable foreach_optional_arg + { zend_do_foreach_begin(&$1, &$2, &$3, 1 TSRMLS_CC); } + ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$5, &$6, &$8 TSRMLS_CC); } + foreach_statement { zend_do_foreach_end(&$1, &$2, &$8 TSRMLS_CC); } + | T_FOREACH '(' expr_without_variable T_AS w_variable foreach_optional_arg + { zend_do_foreach_begin(&$1, &$2, &$3, 0 TSRMLS_CC); } + ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$5, &$6, &$8 TSRMLS_CC); } + foreach_statement { zend_do_foreach_end(&$1, &$2, &$8 TSRMLS_CC); } | T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); } | ';' /* empty statement */ | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index db0dc06569..eb1becd4d1 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2828,6 +2828,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) HashTable *fe_ht; zend_object_iterator *iter = NULL; zend_class_entry *ce = NULL; + zend_bool is_empty = 0; if (opline->extended_value) { array_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R); @@ -2889,20 +2890,26 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); } + is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { - /* probably redundant */ zend_hash_internal_pointer_reset(fe_ht); + if (ce) { + zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC); + while (zend_hash_has_more_elements(fe_ht) == SUCCESS) { + char *str_key; + uint str_key_len; + ulong int_key; + if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING + && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + break; + } + zend_hash_move_forward(fe_ht); + } + } + is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - - opline++; - ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); - if (opline->extended_value) { - FREE_OP1_VAR_PTR(); - } else { - FREE_OP1_IF_VAR(); - } - ZEND_VM_CONTINUE_JMP(); + is_empty = 1; } if (opline->extended_value) { @@ -2910,7 +2917,12 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) } else { FREE_OP1_IF_VAR(); } - ZEND_VM_NEXT_OPCODE(); + if (is_empty) { + ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_CONTINUE_JMP(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) @@ -2980,7 +2992,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) * In case that ever happens we need an additional flag. */ iter->funcs->move_forward(iter TSRMLS_CC); } - if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) { + if (!iter || (iter->index > 1 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) { /* reached end of iteration */ ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); ZEND_VM_CONTINUE_JMP(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b2f075bbe1..08e0611cc8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1924,6 +1924,7 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) HashTable *fe_ht; zend_object_iterator *iter = NULL; zend_class_entry *ce = NULL; + zend_bool is_empty = 0; if (opline->extended_value) { array_ptr_ptr = _get_zval_ptr_ptr_const(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); @@ -1985,20 +1986,26 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); } + is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { - /* probably redundant */ zend_hash_internal_pointer_reset(fe_ht); + if (ce) { + zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC); + while (zend_hash_has_more_elements(fe_ht) == SUCCESS) { + char *str_key; + uint str_key_len; + ulong int_key; + if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING + && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + break; + } + zend_hash_move_forward(fe_ht); + } + } + is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - - opline++; - ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); - if (opline->extended_value) { - ; - } else { - ; - } - ZEND_VM_CONTINUE_JMP(); + is_empty = 1; } if (opline->extended_value) { @@ -2006,7 +2013,12 @@ static int ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { ; } - ZEND_VM_NEXT_OPCODE(); + if (is_empty) { + ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_CONTINUE_JMP(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -4343,6 +4355,7 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) HashTable *fe_ht; zend_object_iterator *iter = NULL; zend_class_entry *ce = NULL; + zend_bool is_empty = 0; if (opline->extended_value) { array_ptr_ptr = _get_zval_ptr_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); @@ -4404,20 +4417,26 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); } + is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { - /* probably redundant */ zend_hash_internal_pointer_reset(fe_ht); + if (ce) { + zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC); + while (zend_hash_has_more_elements(fe_ht) == SUCCESS) { + char *str_key; + uint str_key_len; + ulong int_key; + if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING + && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + break; + } + zend_hash_move_forward(fe_ht); + } + } + is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - - opline++; - ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); - if (opline->extended_value) { - ; - } else { - ; - } - ZEND_VM_CONTINUE_JMP(); + is_empty = 1; } if (opline->extended_value) { @@ -4425,7 +4444,12 @@ static int ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { ; } - ZEND_VM_NEXT_OPCODE(); + if (is_empty) { + ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_CONTINUE_JMP(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_JMP_NO_CTOR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7424,6 +7448,7 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) HashTable *fe_ht; zend_object_iterator *iter = NULL; zend_class_entry *ce = NULL; + zend_bool is_empty = 0; if (opline->extended_value) { array_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); @@ -7485,20 +7510,26 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); } + is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { - /* probably redundant */ zend_hash_internal_pointer_reset(fe_ht); + if (ce) { + zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC); + while (zend_hash_has_more_elements(fe_ht) == SUCCESS) { + char *str_key; + uint str_key_len; + ulong int_key; + if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING + && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + break; + } + zend_hash_move_forward(fe_ht); + } + } + is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - - opline++; - ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); - if (opline->extended_value) { - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - } else { - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - } - ZEND_VM_CONTINUE_JMP(); + is_empty = 1; } if (opline->extended_value) { @@ -7506,7 +7537,12 @@ static int ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; } - ZEND_VM_NEXT_OPCODE(); + if (is_empty) { + ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_CONTINUE_JMP(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -7576,7 +7612,7 @@ static int ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) * In case that ever happens we need an additional flag. */ iter->funcs->move_forward(iter TSRMLS_CC); } - if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) { + if (!iter || (iter->index > 1 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) { /* reached end of iteration */ ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); ZEND_VM_CONTINUE_JMP(); @@ -18203,6 +18239,7 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) HashTable *fe_ht; zend_object_iterator *iter = NULL; zend_class_entry *ce = NULL; + zend_bool is_empty = 0; if (opline->extended_value) { array_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), &free_op1, BP_VAR_R TSRMLS_CC); @@ -18264,20 +18301,26 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); } + is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { - /* probably redundant */ zend_hash_internal_pointer_reset(fe_ht); + if (ce) { + zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC); + while (zend_hash_has_more_elements(fe_ht) == SUCCESS) { + char *str_key; + uint str_key_len; + ulong int_key; + if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING + && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + break; + } + zend_hash_move_forward(fe_ht); + } + } + is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - - opline++; - ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); - if (opline->extended_value) { - ; - } else { - ; - } - ZEND_VM_CONTINUE_JMP(); + is_empty = 1; } if (opline->extended_value) { @@ -18285,7 +18328,12 @@ static int ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { ; } - ZEND_VM_NEXT_OPCODE(); + if (is_empty) { + ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_CONTINUE_JMP(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_JMP_NO_CTOR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -30505,6 +30553,7 @@ static int ZEND_FE_RESET_HANDLER(ZEND_OPCODE_HANDLER_ARGS) HashTable *fe_ht; zend_object_iterator *iter = NULL; zend_class_entry *ce = NULL; + zend_bool is_empty = 0; if (opline->extended_value) { array_ptr_ptr = get_zval_ptr_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_R); @@ -30566,20 +30615,26 @@ static int ZEND_FE_RESET_HANDLER(ZEND_OPCODE_HANDLER_ARGS) if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); } + is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { - /* probably redundant */ zend_hash_internal_pointer_reset(fe_ht); + if (ce) { + zend_object *zobj = zend_objects_get_address(array_ptr TSRMLS_CC); + while (zend_hash_has_more_elements(fe_ht) == SUCCESS) { + char *str_key; + uint str_key_len; + ulong int_key; + if (zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL) == HASH_KEY_IS_STRING + && zend_check_property_access(zobj, str_key TSRMLS_CC) == SUCCESS) { + break; + } + zend_hash_move_forward(fe_ht); + } + } + is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - - opline++; - ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); - if (opline->extended_value) { - if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; - } else { - FREE_OP_IF_VAR(free_op1); - } - ZEND_VM_CONTINUE_JMP(); + is_empty = 1; } if (opline->extended_value) { @@ -30587,7 +30642,12 @@ static int ZEND_FE_RESET_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { FREE_OP_IF_VAR(free_op1); } - ZEND_VM_NEXT_OPCODE(); + if (is_empty) { + ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_CONTINUE_JMP(); + } else { + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -30657,7 +30717,7 @@ static int ZEND_FE_FETCH_HANDLER(ZEND_OPCODE_HANDLER_ARGS) * In case that ever happens we need an additional flag. */ iter->funcs->move_forward(iter TSRMLS_CC); } - if (!iter || iter->funcs->valid(iter TSRMLS_CC) == FAILURE) { + if (!iter || (iter->index > 1 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) { /* reached end of iteration */ ZEND_VM_SET_OPCODE(EX(op_array)->opcodes+opline->op2.u.opline_num); ZEND_VM_CONTINUE_JMP();