]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-7.4' into PHP-8.0
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 9 Oct 2020 14:59:01 +0000 (16:59 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 9 Oct 2020 15:02:20 +0000 (17:02 +0200)
* PHP-7.4:
  Fixed bug #80186

1  2 
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 17708bb60097d6a50eddd6e229b6a55c487889aa,6305ef8ef4649aaa727c2a3e05adb0b637ec12bf..930cd342e80e332017d740ea1f85924ce55060d1
@@@ -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 {
                        }
                }
        } 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();
index 8e6e6aa87d99f370baddbb3e30f3732b9331924d,770f9667c95f4e43eaf9e38fe19dfec037fba339..e180c28c7528be14bb8dffa518401a6ed52c7601
@@@ -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 {
                        }
                }
        } 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 {
                        }
                }
        } 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);
                        }
                }
        } 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);
  
 -                      if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);};
+                       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);
 +                      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 {
                        }
                }
        } 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;