From: Nikita Popov Date: Fri, 9 Oct 2020 14:59:01 +0000 (+0200) Subject: Merge branch 'PHP-7.4' into PHP-8.0 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=623bf39e9c65b6d0708385f19dae1c9406de18a6;p=php Merge branch 'PHP-7.4' into PHP-8.0 * PHP-7.4: Fixed bug #80186 --- 623bf39e9c65b6d0708385f19dae1c9406de18a6 diff --cc Zend/zend_vm_def.h index 17708bb600,6305ef8ef4..930cd342e8 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@@ -6482,28 -6316,27 +6482,30 @@@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CO FREE_OP1_IF_VAR(); ZEND_VM_NEXT_OPCODE(); } else if (OP1_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) { - if (!Z_OBJCE_P(array_ptr)->get_iterator) { - HashTable *properties; - if (Z_OBJ_P(array_ptr)->properties - && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) { - if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) { - GC_DELREF(Z_OBJ_P(array_ptr)->properties); + zend_object *zobj = Z_OBJ_P(array_ptr); + if (!zobj->ce->get_iterator) { - HashTable *properties; - - result = EX_VAR(opline->result.var); - ZVAL_OBJ(result, zobj); - if (OP1_TYPE != IS_TMP_VAR) { - GC_ADDREF(zobj); - } - properties = zobj->properties; ++ HashTable *properties = zobj->properties; + if (properties) { + if (UNEXPECTED(GC_REFCOUNT(properties) > 1)) { + if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) { + GC_DELREF(properties); + } + properties = zobj->properties = zend_array_dup(properties); } - Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties); + } else { + properties = zobj->handlers->get_properties(zobj); } - Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(properties, 0); - properties = Z_OBJPROP_P(array_ptr); + if (zend_hash_num_elements(properties) == 0) { + ZEND_VM_C_GOTO(fe_reset_r_empty); + } + + result = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(result, array_ptr); + if (OP1_TYPE != IS_TMP_VAR) { + Z_ADDREF_P(array_ptr); + } + Z_FE_ITER_P(result) = zend_hash_iterator_add(properties, 0); FREE_OP1_IF_VAR(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { @@@ -6519,7 -6352,8 +6521,8 @@@ } } } else { - zend_error(E_WARNING, "Invalid argument supplied for foreach()"); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + ZEND_VM_C_LABEL(fe_reset_r_empty): ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; FREE_OP1(); diff --cc Zend/zend_vm_execute.h index 8e6e6aa87d,770f9667c9..e180c28c75 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@@ -4791,27 -4139,27 +4791,30 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS ZEND_VM_NEXT_OPCODE(); } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) { - if (!Z_OBJCE_P(array_ptr)->get_iterator) { - HashTable *properties; - if (Z_OBJ_P(array_ptr)->properties - && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) { - if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) { - GC_DELREF(Z_OBJ_P(array_ptr)->properties); + zend_object *zobj = Z_OBJ_P(array_ptr); + if (!zobj->ce->get_iterator) { - HashTable *properties; - - result = EX_VAR(opline->result.var); - ZVAL_OBJ(result, zobj); - if (IS_CONST != IS_TMP_VAR) { - GC_ADDREF(zobj); - } - properties = zobj->properties; ++ HashTable *properties = zobj->properties; + if (properties) { + if (UNEXPECTED(GC_REFCOUNT(properties) > 1)) { + if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) { + GC_DELREF(properties); + } + properties = zobj->properties = zend_array_dup(properties); } - Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties); + } else { + properties = zobj->handlers->get_properties(zobj); } - Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(properties, 0); + - properties = Z_OBJPROP_P(array_ptr); + if (zend_hash_num_elements(properties) == 0) { + goto fe_reset_r_empty; + } + + result = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(result, array_ptr); + if (IS_CONST != IS_TMP_VAR) { + Z_ADDREF_P(array_ptr); + } + Z_FE_ITER_P(result) = zend_hash_iterator_add(properties, 0); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { @@@ -4826,7 -4174,8 +4829,8 @@@ } } } else { - zend_error(E_WARNING, "Invalid argument supplied for foreach()"); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + fe_reset_r_empty: ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; @@@ -18786,27 -18207,27 +18798,30 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS ZEND_VM_NEXT_OPCODE(); } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) { - if (!Z_OBJCE_P(array_ptr)->get_iterator) { - HashTable *properties; - if (Z_OBJ_P(array_ptr)->properties - && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) { - if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) { - GC_DELREF(Z_OBJ_P(array_ptr)->properties); + zend_object *zobj = Z_OBJ_P(array_ptr); + if (!zobj->ce->get_iterator) { - HashTable *properties; - - result = EX_VAR(opline->result.var); - ZVAL_OBJ(result, zobj); - if (IS_TMP_VAR != IS_TMP_VAR) { - GC_ADDREF(zobj); - } - properties = zobj->properties; ++ HashTable *properties = zobj->properties; + if (properties) { + if (UNEXPECTED(GC_REFCOUNT(properties) > 1)) { + if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) { + GC_DELREF(properties); + } + properties = zobj->properties = zend_array_dup(properties); } - Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties); + } else { + properties = zobj->handlers->get_properties(zobj); } - Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(properties, 0); + - properties = Z_OBJPROP_P(array_ptr); + if (zend_hash_num_elements(properties) == 0) { + goto fe_reset_r_empty; + } + + result = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(result, array_ptr); + if (IS_TMP_VAR != IS_TMP_VAR) { + Z_ADDREF_P(array_ptr); + } + Z_FE_ITER_P(result) = zend_hash_iterator_add(properties, 0); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { @@@ -18822,10 -18243,11 +18837,11 @@@ } } } else { - zend_error(E_WARNING, "Invalid argument supplied for foreach()"); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + fe_reset_r_empty: ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } } @@@ -21333,32 -21310,31 +21357,34 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS } Z_FE_POS_P(result) = 0; - zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE(); } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) { - if (!Z_OBJCE_P(array_ptr)->get_iterator) { - HashTable *properties; - if (Z_OBJ_P(array_ptr)->properties - && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) { - if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) { - GC_DELREF(Z_OBJ_P(array_ptr)->properties); + zend_object *zobj = Z_OBJ_P(array_ptr); + if (!zobj->ce->get_iterator) { - HashTable *properties; - - result = EX_VAR(opline->result.var); - ZVAL_OBJ(result, zobj); - if (IS_VAR != IS_TMP_VAR) { - GC_ADDREF(zobj); - } - properties = zobj->properties; ++ HashTable *properties = zobj->properties; + if (properties) { + if (UNEXPECTED(GC_REFCOUNT(properties) > 1)) { + if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) { + GC_DELREF(properties); + } + properties = zobj->properties = zend_array_dup(properties); } - Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties); + } else { + properties = zobj->handlers->get_properties(zobj); } - Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(properties, 0); - properties = Z_OBJPROP_P(array_ptr); + if (zend_hash_num_elements(properties) == 0) { + goto fe_reset_r_empty; + } + + result = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(result, array_ptr); + if (IS_VAR != IS_TMP_VAR) { + Z_ADDREF_P(array_ptr); + } + Z_FE_ITER_P(result) = zend_hash_iterator_add(properties, 0); - zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { zend_bool is_empty = zend_fe_reset_iterator(array_ptr, 0 OPLINE_CC EXECUTE_DATA_CC); @@@ -21373,10 -21349,11 +21399,11 @@@ } } } else { - zend_error(E_WARNING, "Invalid argument supplied for foreach()"); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + fe_reset_r_empty: ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - zval_ptr_dtor_nogc(free_op1); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } } @@@ -21441,9 -21420,15 +21469,15 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS } Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties); } - Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(Z_OBJPROP_P(array_ptr), 0); + properties = Z_OBJPROP_P(array_ptr); + if (zend_hash_num_elements(properties) == 0) { + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t) -1; + ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); + } + + Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(properties, 0); - if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { zend_bool is_empty = zend_fe_reset_iterator(array_ptr, 1 OPLINE_CC EXECUTE_DATA_CC); @@@ -38038,27 -37837,27 +38072,30 @@@ static ZEND_OPCODE_HANDLER_RET ZEND_FAS ZEND_VM_NEXT_OPCODE(); } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(array_ptr) == IS_OBJECT)) { - if (!Z_OBJCE_P(array_ptr)->get_iterator) { - HashTable *properties; - if (Z_OBJ_P(array_ptr)->properties - && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) { - if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) { - GC_DELREF(Z_OBJ_P(array_ptr)->properties); + zend_object *zobj = Z_OBJ_P(array_ptr); + if (!zobj->ce->get_iterator) { - HashTable *properties; - - result = EX_VAR(opline->result.var); - ZVAL_OBJ(result, zobj); - if (IS_CV != IS_TMP_VAR) { - GC_ADDREF(zobj); - } - properties = zobj->properties; ++ HashTable *properties = zobj->properties; + if (properties) { + if (UNEXPECTED(GC_REFCOUNT(properties) > 1)) { + if (EXPECTED(!(GC_FLAGS(properties) & IS_ARRAY_IMMUTABLE))) { + GC_DELREF(properties); + } + properties = zobj->properties = zend_array_dup(properties); } - Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties); + } else { + properties = zobj->handlers->get_properties(zobj); } - Z_FE_ITER_P(EX_VAR(opline->result.var)) = zend_hash_iterator_add(properties, 0); + - properties = Z_OBJPROP_P(array_ptr); + if (zend_hash_num_elements(properties) == 0) { + goto fe_reset_r_empty; + } + + result = EX_VAR(opline->result.var); + ZVAL_COPY_VALUE(result, array_ptr); + if (IS_CV != IS_TMP_VAR) { + Z_ADDREF_P(array_ptr); + } + Z_FE_ITER_P(result) = zend_hash_iterator_add(properties, 0); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { @@@ -38073,7 -37872,8 +38110,8 @@@ } } } else { - zend_error(E_WARNING, "Invalid argument supplied for foreach()"); + zend_error(E_WARNING, "foreach() argument must be of type array|object, %s given", zend_zval_type_name(array_ptr)); + fe_reset_r_empty: ZVAL_UNDEF(EX_VAR(opline->result.var)); Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1;