diff --git a/7.4/alpine3.16/cli/1.diff b/7.4/alpine3.16/cli/1.diff new file mode 100644 index 0000000000..202fd235ae --- /dev/null +++ b/7.4/alpine3.16/cli/1.diff @@ -0,0 +1,584 @@ +diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c +index 656316cc4e00b..a9da9c6c4e954 100644 +--- a/Zend/zend_operators.c ++++ b/Zend/zend_operators.c +@@ -2019,7 +2019,317 @@ static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */ + } + /* }}} */ + +-ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++static int compare_long_to_string(zend_long lval, zend_string *str, zend_bool equality_only, zval *orig_op1, zval *orig_op2) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 1); ++ ++ if (type == IS_LONG) { ++ num_cmp_result = lval > str_lval ? 1 : lval < str_lval ? -1 : 0; ++ } else if (type == IS_DOUBLE) { ++ double diff = (double) lval - str_dval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else { ++ compare_function_orig(&num_cmp_result, orig_op1, orig_op2); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *lval_as_str = zend_long_to_str(lval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(lval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between " ZEND_LONG_FMT " and \"%s\" will change (%d to %d)", ++ lval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++static int compare_double_to_string(double dval, zend_string *str, zend_bool equality_only, zval *orig_op1, zval *orig_op2) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ ++ if (type == IS_LONG) { ++ double diff = dval - (double) str_lval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else if (type == IS_DOUBLE) { ++ if (dval == str_dval) { ++ return 0; ++ } ++ num_cmp_result = ZEND_NORMALIZE_BOOL(dval - str_dval); ++ } else { ++ compare_function_orig(&num_cmp_result, orig_op1, orig_op2); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *dval_as_str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(dval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between %G and \"%s\" will change (%d to %d)", ++ dval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only) /* {{{ */ ++{ ++ int ret; ++ int converted = 0; ++ zval op1_copy, op2_copy; ++ zval *op_free, tmp_free; ++ ++ while (1) { ++ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { ++ case TYPE_PAIR(IS_LONG, IS_LONG): ++ ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)get) { ++ zval rv; ++ op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); ++ ret = compare_function_ex(result, op_free, op2, equality_only); ++ zend_free_obj_get_result(op_free); ++ return ret; ++ } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { ++ ZVAL_UNDEF(&tmp_free); ++ if (Z_OBJ_HT_P(op1)->cast_object(op1, &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) { ++ ZVAL_LONG(result, 1); ++ zend_free_obj_get_result(&tmp_free); ++ return SUCCESS; ++ } ++ ret = compare_function_ex(result, &tmp_free, op2, equality_only); ++ zend_free_obj_get_result(&tmp_free); ++ return ret; ++ } ++ } ++ if (Z_TYPE_P(op2) == IS_OBJECT) { ++ if (Z_OBJ_HT_P(op2)->get) { ++ zval rv; ++ op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); ++ ret = compare_function_ex(result, op1, op_free, equality_only); ++ zend_free_obj_get_result(op_free); ++ return ret; ++ } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { ++ ZVAL_UNDEF(&tmp_free); ++ if (Z_OBJ_HT_P(op2)->cast_object(op2, &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) { ++ ZVAL_LONG(result, -1); ++ zend_free_obj_get_result(&tmp_free); ++ return SUCCESS; ++ } ++ ret = compare_function_ex(result, op1, &tmp_free, equality_only); ++ zend_free_obj_get_result(&tmp_free); ++ return ret; ++ } else if (Z_TYPE_P(op1) == IS_OBJECT) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } ++ } ++ if (!converted) { ++ if (Z_TYPE_P(op1) < IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op1) == IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op2) < IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op2) == IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1); ++ return SUCCESS; ++ } else { ++ op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 1); ++ op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 1); ++ if (EG(exception)) { ++ if (result != op1) { ++ ZVAL_UNDEF(result); ++ } ++ return FAILURE; ++ } ++ converted = 1; ++ } ++ } else if (Z_TYPE_P(op1)==IS_ARRAY) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op2)==IS_ARRAY) { ++ ZVAL_LONG(result, -1); ++ return SUCCESS; ++ } else { ++ ZEND_ASSERT(0); ++ zend_throw_error(NULL, "Unsupported operand types"); ++ if (result != op1) { ++ ZVAL_UNDEF(result); ++ } ++ return FAILURE; ++ } ++ } ++ } ++} ++/* }}} */ ++ ++ ++ZEND_API int ZEND_FASTCALL compare_function_orig(zval *result, zval *op1, zval *op2) /* {{{ */ + { + int ret; + int converted = 0; +@@ -2133,7 +2443,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op1)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); +- ret = compare_function(result, op_free, op2); ++ ret = compare_function_orig(result, op_free, op2); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { +@@ -2143,7 +2453,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, &tmp_free, op2); ++ ret = compare_function_orig(result, &tmp_free, op2); + zend_free_obj_get_result(&tmp_free); + return ret; + } +@@ -2152,7 +2462,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op2)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); +- ret = compare_function(result, op1, op_free); ++ ret = compare_function_orig(result, op1, op_free); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { +@@ -2162,7 +2472,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, op1, &tmp_free); ++ ret = compare_function_orig(result, op1, &tmp_free); + zend_free_obj_get_result(&tmp_free); + return ret; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { +@@ -2213,6 +2523,12 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + } + /* }}} */ + ++ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++{ ++ return compare_function_ex(result, op1, op2, 0); ++} ++/* }}} */ ++ + static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ + { + /* is_identical_function() returns 1 in case of identity and 0 in case +@@ -2271,7 +2587,7 @@ ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zv + + ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); +@@ -2281,7 +2597,7 @@ ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) + + ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); +@@ -2967,15 +3283,44 @@ static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */ + } + /* }}} */ + ++static int hash_zval_compare_function_equality(zval *z1, zval *z2) /* {{{ */ ++{ ++ zval result; ++ ++ if (compare_function_ex(&result, z1, z2, 1)==FAILURE) { ++ return 1; ++ } ++ return Z_LVAL(result); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only) /* {{{ */ ++{ ++ if (ht1 == ht2) { ++ return 0; ++ } ++ return zend_hash_compare(ht1, ht2, ++ equality_only ++ ? (compare_func_t) hash_zval_compare_function_equality ++ : (compare_func_t) hash_zval_compare_function, 0); ++} ++/* }}} */ ++ + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */ + { +- return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0); ++ return zend_compare_symbol_tables_ex(ht1, ht2, 0); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only) /* {{{ */ ++{ ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), equality_only); + } + /* }}} */ + + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */ + { +- return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2)); ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), 0); + } + /* }}} */ + +diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h +index dad23bc4d8c83..05fecf4cf2989 100644 +--- a/Zend/zend_operators.h ++++ b/Zend/zend_operators.h +@@ -388,6 +388,7 @@ static zend_always_inline int i_zend_is_true(zval *op) + return result; + } + ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2); + + ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2); +@@ -417,7 +418,9 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1 + + ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2); + ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2); ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2); ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2); + ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2); + +@@ -860,7 +863,7 @@ static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2) + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -870,7 +873,7 @@ static zend_always_inline int fast_equal_check_long(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + return Z_LVAL_P(op1) == Z_LVAL_P(op2); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -880,7 +883,7 @@ static zend_always_inline int fast_equal_check_string(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index 827548504cc29..6fb75cf472eab 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -498,7 +498,7 @@ ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -593,7 +593,7 @@ ZEND_VM_HELPER(zend_is_not_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -688,7 +688,7 @@ ZEND_VM_HELPER(zend_is_smaller_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -768,7 +768,7 @@ ZEND_VM_HELPER(zend_is_smaller_or_equal_helper, ANY, ANY, zval *op_1, zval *op_2 + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -5354,7 +5354,7 @@ ZEND_VM_HELPER(zend_case_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index ae30886c9056d..a145a261cc3d2 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -587,7 +587,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_hel + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -619,7 +619,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -651,7 +651,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_h + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -683,7 +683,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_o + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -2141,7 +2141,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_case_helper_ + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } \ No newline at end of file diff --git a/7.4/alpine3.16/cli/3917.diff b/7.4/alpine3.16/cli/3917.diff new file mode 100644 index 0000000000..b74451e35b --- /dev/null +++ b/7.4/alpine3.16/cli/3917.diff @@ -0,0 +1,387 @@ +diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c +index 656316cc4e00b..37e9bb08a7241 100644 +--- a/Zend/zend_operators.c ++++ b/Zend/zend_operators.c +@@ -2019,7 +2019,96 @@ static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */ + } + /* }}} */ + +-ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++static int compare_long_to_string(zend_long lval, zend_string *str, zend_bool equality_only) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 1); ++ ++ if (type == IS_LONG) { ++ num_cmp_result = lval > str_lval ? 1 : lval < str_lval ? -1 : 0; ++ } else if (type == IS_DOUBLE) { ++ double diff = (double) lval - str_dval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else { ++ num_cmp_result = ZEND_NORMALIZE_BOOL(lval); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *lval_as_str = zend_long_to_str(lval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(lval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between " ZEND_LONG_FMT " and \"%s\" will change (%d to %d)", ++ lval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++static int compare_double_to_string(double dval, zend_string *str, zend_bool equality_only) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ ++ if (type == IS_LONG) { ++ double diff = dval - (double) str_lval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else if (type == IS_DOUBLE) { ++ if (dval == str_dval) { ++ return 0; ++ } ++ num_cmp_result = ZEND_NORMALIZE_BOOL(dval - str_dval); ++ } else { ++ num_cmp_result = ZEND_NORMALIZE_BOOL(dval); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *dval_as_str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(dval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between %G and \"%s\" will change (%d to %d)", ++ dval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only) /* {{{ */ + { + int ret; + int converted = 0; +@@ -2052,7 +2141,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + return SUCCESS; + + case TYPE_PAIR(IS_ARRAY, IS_ARRAY): +- ZVAL_LONG(result, zend_compare_arrays(op1, op2)); ++ ZVAL_LONG(result, zend_compare_arrays_ex(op1, op2, equality_only)); + return SUCCESS; + + case TYPE_PAIR(IS_NULL, IS_NULL): +@@ -2087,6 +2176,32 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1); + return SUCCESS; + ++ case TYPE_PAIR(IS_LONG, IS_STRING): ++ ZVAL_LONG(result, compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2), equality_only)); ++ return SUCCESS; ++ ++ case TYPE_PAIR(IS_STRING, IS_LONG): ++ ZVAL_LONG(result, -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1), equality_only)); ++ return SUCCESS; ++ ++ case TYPE_PAIR(IS_DOUBLE, IS_STRING): ++ if (zend_isnan(Z_DVAL_P(op1))) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } ++ ++ ZVAL_LONG(result, compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2), equality_only)); ++ return SUCCESS; ++ ++ case TYPE_PAIR(IS_STRING, IS_DOUBLE): ++ if (zend_isnan(Z_DVAL_P(op2))) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } ++ ++ ZVAL_LONG(result, -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1), equality_only)); ++ return SUCCESS; ++ + case TYPE_PAIR(IS_OBJECT, IS_NULL): + ZVAL_LONG(result, 1); + return SUCCESS; +@@ -2133,7 +2248,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op1)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); +- ret = compare_function(result, op_free, op2); ++ ret = compare_function_ex(result, op_free, op2, equality_only); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { +@@ -2143,7 +2258,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, &tmp_free, op2); ++ ret = compare_function_ex(result, &tmp_free, op2, equality_only); + zend_free_obj_get_result(&tmp_free); + return ret; + } +@@ -2152,7 +2267,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op2)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); +- ret = compare_function(result, op1, op_free); ++ ret = compare_function_ex(result, op1, op_free, equality_only); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { +@@ -2162,7 +2277,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, op1, &tmp_free); ++ ret = compare_function_ex(result, op1, &tmp_free, equality_only); + zend_free_obj_get_result(&tmp_free); + return ret; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { +@@ -2213,6 +2328,12 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + } + /* }}} */ + ++ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++{ ++ return compare_function_ex(result, op1, op2, 0); ++} ++/* }}} */ ++ + static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ + { + /* is_identical_function() returns 1 in case of identity and 0 in case +@@ -2271,7 +2392,7 @@ ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zv + + ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); +@@ -2281,7 +2402,7 @@ ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) + + ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); +@@ -2967,15 +3088,44 @@ static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */ + } + /* }}} */ + ++static int hash_zval_compare_function_equality(zval *z1, zval *z2) /* {{{ */ ++{ ++ zval result; ++ ++ if (compare_function_ex(&result, z1, z2, 1)==FAILURE) { ++ return 1; ++ } ++ return Z_LVAL(result); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only) /* {{{ */ ++{ ++ if (ht1 == ht2) { ++ return 0; ++ } ++ return zend_hash_compare(ht1, ht2, ++ equality_only ++ ? (compare_func_t) hash_zval_compare_function_equality ++ : (compare_func_t) hash_zval_compare_function, 0); ++} ++/* }}} */ ++ + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */ + { +- return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0); ++ return zend_compare_symbol_tables_ex(ht1, ht2, 0); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only) /* {{{ */ ++{ ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), equality_only); + } + /* }}} */ + + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */ + { +- return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2)); ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), 0); + } + /* }}} */ + +diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h +index dad23bc4d8c83..05fecf4cf2989 100644 +--- a/Zend/zend_operators.h ++++ b/Zend/zend_operators.h +@@ -388,6 +388,7 @@ static zend_always_inline int i_zend_is_true(zval *op) + return result; + } + ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2); + + ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2); +@@ -417,7 +418,9 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1 + + ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2); + ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2); ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2); ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2); + ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2); + +@@ -860,7 +863,7 @@ static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2) + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -870,7 +873,7 @@ static zend_always_inline int fast_equal_check_long(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + return Z_LVAL_P(op1) == Z_LVAL_P(op2); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -880,7 +883,7 @@ static zend_always_inline int fast_equal_check_string(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index 827548504cc29..eb09c1ba64087 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -498,7 +498,7 @@ ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -593,7 +593,7 @@ ZEND_VM_HELPER(zend_is_not_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -688,7 +688,7 @@ ZEND_VM_HELPER(zend_is_smaller_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -768,7 +768,7 @@ ZEND_VM_HELPER(zend_is_smaller_or_equal_helper, ANY, ANY, zval *op_1, zval *op_2 + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index ae30886c9056d..4b10d2c0d0b6c 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -587,7 +587,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_hel + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -619,7 +619,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -651,7 +651,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_h + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -683,7 +683,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_o + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } diff --git a/7.4/alpine3.16/cli/Dockerfile b/7.4/alpine3.16/cli/Dockerfile index b1192fefb4..dc810603ca 100644 --- a/7.4/alpine3.16/cli/Dockerfile +++ b/7.4/alpine3.16/cli/Dockerfile @@ -88,6 +88,8 @@ RUN set -eux; \ apk del --no-network .fetch-deps COPY docker-php-source /usr/local/bin/ +# patch https://github.com/php/php-src/pull/3917.diff +COPY 1.diff / RUN set -eux; \ apk add --no-cache --virtual .build-deps \ @@ -117,6 +119,12 @@ RUN set -eux; \ ; \ docker-php-source extract; \ cd /usr/src/php; \ +# ----------PATCH---------- + apk add --no-cache patch; \ + patch -p1 < /1.diff; \ + rm /1.diff; \ + apk del patch; \ +# ----------END_PATCH---------- gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \ ./configure \ --build="$gnuArch" \ diff --git a/7.4/bullseye/apache/1.diff b/7.4/bullseye/apache/1.diff new file mode 100644 index 0000000000..202fd235ae --- /dev/null +++ b/7.4/bullseye/apache/1.diff @@ -0,0 +1,584 @@ +diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c +index 656316cc4e00b..a9da9c6c4e954 100644 +--- a/Zend/zend_operators.c ++++ b/Zend/zend_operators.c +@@ -2019,7 +2019,317 @@ static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */ + } + /* }}} */ + +-ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++static int compare_long_to_string(zend_long lval, zend_string *str, zend_bool equality_only, zval *orig_op1, zval *orig_op2) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 1); ++ ++ if (type == IS_LONG) { ++ num_cmp_result = lval > str_lval ? 1 : lval < str_lval ? -1 : 0; ++ } else if (type == IS_DOUBLE) { ++ double diff = (double) lval - str_dval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else { ++ compare_function_orig(&num_cmp_result, orig_op1, orig_op2); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *lval_as_str = zend_long_to_str(lval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(lval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between " ZEND_LONG_FMT " and \"%s\" will change (%d to %d)", ++ lval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++static int compare_double_to_string(double dval, zend_string *str, zend_bool equality_only, zval *orig_op1, zval *orig_op2) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ ++ if (type == IS_LONG) { ++ double diff = dval - (double) str_lval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else if (type == IS_DOUBLE) { ++ if (dval == str_dval) { ++ return 0; ++ } ++ num_cmp_result = ZEND_NORMALIZE_BOOL(dval - str_dval); ++ } else { ++ compare_function_orig(&num_cmp_result, orig_op1, orig_op2); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *dval_as_str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(dval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between %G and \"%s\" will change (%d to %d)", ++ dval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only) /* {{{ */ ++{ ++ int ret; ++ int converted = 0; ++ zval op1_copy, op2_copy; ++ zval *op_free, tmp_free; ++ ++ while (1) { ++ switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) { ++ case TYPE_PAIR(IS_LONG, IS_LONG): ++ ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)get) { ++ zval rv; ++ op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); ++ ret = compare_function_ex(result, op_free, op2, equality_only); ++ zend_free_obj_get_result(op_free); ++ return ret; ++ } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { ++ ZVAL_UNDEF(&tmp_free); ++ if (Z_OBJ_HT_P(op1)->cast_object(op1, &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) { ++ ZVAL_LONG(result, 1); ++ zend_free_obj_get_result(&tmp_free); ++ return SUCCESS; ++ } ++ ret = compare_function_ex(result, &tmp_free, op2, equality_only); ++ zend_free_obj_get_result(&tmp_free); ++ return ret; ++ } ++ } ++ if (Z_TYPE_P(op2) == IS_OBJECT) { ++ if (Z_OBJ_HT_P(op2)->get) { ++ zval rv; ++ op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); ++ ret = compare_function_ex(result, op1, op_free, equality_only); ++ zend_free_obj_get_result(op_free); ++ return ret; ++ } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { ++ ZVAL_UNDEF(&tmp_free); ++ if (Z_OBJ_HT_P(op2)->cast_object(op2, &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) { ++ ZVAL_LONG(result, -1); ++ zend_free_obj_get_result(&tmp_free); ++ return SUCCESS; ++ } ++ ret = compare_function_ex(result, op1, &tmp_free, equality_only); ++ zend_free_obj_get_result(&tmp_free); ++ return ret; ++ } else if (Z_TYPE_P(op1) == IS_OBJECT) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } ++ } ++ if (!converted) { ++ if (Z_TYPE_P(op1) < IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op1) == IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op2) < IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op2) == IS_TRUE) { ++ ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1); ++ return SUCCESS; ++ } else { ++ op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 1); ++ op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 1); ++ if (EG(exception)) { ++ if (result != op1) { ++ ZVAL_UNDEF(result); ++ } ++ return FAILURE; ++ } ++ converted = 1; ++ } ++ } else if (Z_TYPE_P(op1)==IS_ARRAY) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } else if (Z_TYPE_P(op2)==IS_ARRAY) { ++ ZVAL_LONG(result, -1); ++ return SUCCESS; ++ } else { ++ ZEND_ASSERT(0); ++ zend_throw_error(NULL, "Unsupported operand types"); ++ if (result != op1) { ++ ZVAL_UNDEF(result); ++ } ++ return FAILURE; ++ } ++ } ++ } ++} ++/* }}} */ ++ ++ ++ZEND_API int ZEND_FASTCALL compare_function_orig(zval *result, zval *op1, zval *op2) /* {{{ */ + { + int ret; + int converted = 0; +@@ -2133,7 +2443,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op1)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); +- ret = compare_function(result, op_free, op2); ++ ret = compare_function_orig(result, op_free, op2); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { +@@ -2143,7 +2453,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, &tmp_free, op2); ++ ret = compare_function_orig(result, &tmp_free, op2); + zend_free_obj_get_result(&tmp_free); + return ret; + } +@@ -2152,7 +2462,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op2)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); +- ret = compare_function(result, op1, op_free); ++ ret = compare_function_orig(result, op1, op_free); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { +@@ -2162,7 +2472,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, op1, &tmp_free); ++ ret = compare_function_orig(result, op1, &tmp_free); + zend_free_obj_get_result(&tmp_free); + return ret; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { +@@ -2213,6 +2523,12 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + } + /* }}} */ + ++ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++{ ++ return compare_function_ex(result, op1, op2, 0); ++} ++/* }}} */ ++ + static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ + { + /* is_identical_function() returns 1 in case of identity and 0 in case +@@ -2271,7 +2587,7 @@ ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zv + + ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); +@@ -2281,7 +2597,7 @@ ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) + + ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); +@@ -2967,15 +3283,44 @@ static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */ + } + /* }}} */ + ++static int hash_zval_compare_function_equality(zval *z1, zval *z2) /* {{{ */ ++{ ++ zval result; ++ ++ if (compare_function_ex(&result, z1, z2, 1)==FAILURE) { ++ return 1; ++ } ++ return Z_LVAL(result); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only) /* {{{ */ ++{ ++ if (ht1 == ht2) { ++ return 0; ++ } ++ return zend_hash_compare(ht1, ht2, ++ equality_only ++ ? (compare_func_t) hash_zval_compare_function_equality ++ : (compare_func_t) hash_zval_compare_function, 0); ++} ++/* }}} */ ++ + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */ + { +- return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0); ++ return zend_compare_symbol_tables_ex(ht1, ht2, 0); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only) /* {{{ */ ++{ ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), equality_only); + } + /* }}} */ + + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */ + { +- return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2)); ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), 0); + } + /* }}} */ + +diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h +index dad23bc4d8c83..05fecf4cf2989 100644 +--- a/Zend/zend_operators.h ++++ b/Zend/zend_operators.h +@@ -388,6 +388,7 @@ static zend_always_inline int i_zend_is_true(zval *op) + return result; + } + ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2); + + ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2); +@@ -417,7 +418,9 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1 + + ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2); + ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2); ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2); ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2); + ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2); + +@@ -860,7 +863,7 @@ static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2) + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -870,7 +873,7 @@ static zend_always_inline int fast_equal_check_long(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + return Z_LVAL_P(op1) == Z_LVAL_P(op2); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -880,7 +883,7 @@ static zend_always_inline int fast_equal_check_string(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index 827548504cc29..6fb75cf472eab 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -498,7 +498,7 @@ ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -593,7 +593,7 @@ ZEND_VM_HELPER(zend_is_not_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -688,7 +688,7 @@ ZEND_VM_HELPER(zend_is_smaller_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -768,7 +768,7 @@ ZEND_VM_HELPER(zend_is_smaller_or_equal_helper, ANY, ANY, zval *op_1, zval *op_2 + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -5354,7 +5354,7 @@ ZEND_VM_HELPER(zend_case_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP2_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index ae30886c9056d..a145a261cc3d2 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -587,7 +587,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_hel + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -619,7 +619,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -651,7 +651,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_h + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -683,7 +683,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_o + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -2141,7 +2141,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_case_helper_ + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_2); + } \ No newline at end of file diff --git a/7.4/bullseye/apache/3917.diff b/7.4/bullseye/apache/3917.diff new file mode 100644 index 0000000000..b74451e35b --- /dev/null +++ b/7.4/bullseye/apache/3917.diff @@ -0,0 +1,387 @@ +diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c +index 656316cc4e00b..37e9bb08a7241 100644 +--- a/Zend/zend_operators.c ++++ b/Zend/zend_operators.c +@@ -2019,7 +2019,96 @@ static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */ + } + /* }}} */ + +-ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++static int compare_long_to_string(zend_long lval, zend_string *str, zend_bool equality_only) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 1); ++ ++ if (type == IS_LONG) { ++ num_cmp_result = lval > str_lval ? 1 : lval < str_lval ? -1 : 0; ++ } else if (type == IS_DOUBLE) { ++ double diff = (double) lval - str_dval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else { ++ num_cmp_result = ZEND_NORMALIZE_BOOL(lval); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *lval_as_str = zend_long_to_str(lval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(lval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between " ZEND_LONG_FMT " and \"%s\" will change (%d to %d)", ++ lval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++static int compare_double_to_string(double dval, zend_string *str, zend_bool equality_only) /* {{{ */ ++{ ++ zend_long str_lval; ++ double str_dval; ++ int num_cmp_result; ++ zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ ++ if (type == IS_LONG) { ++ double diff = dval - (double) str_lval; ++ num_cmp_result = ZEND_NORMALIZE_BOOL(diff); ++ } else if (type == IS_DOUBLE) { ++ if (dval == str_dval) { ++ return 0; ++ } ++ num_cmp_result = ZEND_NORMALIZE_BOOL(dval - str_dval); ++ } else { ++ num_cmp_result = ZEND_NORMALIZE_BOOL(dval); ++ } ++ ++ /* TODO Avoid duplicate is_numeric_string call. */ ++ zend_bool is_numeric = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0); ++ if (is_numeric) { ++ /* For numeric strings, the comparison result stays the same. */ ++ return num_cmp_result; ++ } ++ ++ zend_string *dval_as_str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval); ++ int str_cmp_result = zend_binary_strcmp( ++ ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str)); ++ str_cmp_result = ZEND_NORMALIZE_BOOL(str_cmp_result); ++ zend_string_release(dval_as_str); ++ ++ /* Don't report a warning if we're using == and the comparison changed between 1/-1. */ ++ zend_bool cmp_result_changed_observably = str_cmp_result != num_cmp_result && ++ (!equality_only || str_cmp_result == 0 || num_cmp_result == 0); ++ if (cmp_result_changed_observably) { ++ zend_error(E_WARNING, ++ "Result of comparison between %G and \"%s\" will change (%d to %d)", ++ dval, ZSTR_VAL(str), num_cmp_result, str_cmp_result); ++ } ++ ++ /* Return old (numeric) comparison result. */ ++ return num_cmp_result; ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only) /* {{{ */ + { + int ret; + int converted = 0; +@@ -2052,7 +2141,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + return SUCCESS; + + case TYPE_PAIR(IS_ARRAY, IS_ARRAY): +- ZVAL_LONG(result, zend_compare_arrays(op1, op2)); ++ ZVAL_LONG(result, zend_compare_arrays_ex(op1, op2, equality_only)); + return SUCCESS; + + case TYPE_PAIR(IS_NULL, IS_NULL): +@@ -2087,6 +2176,32 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1); + return SUCCESS; + ++ case TYPE_PAIR(IS_LONG, IS_STRING): ++ ZVAL_LONG(result, compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2), equality_only)); ++ return SUCCESS; ++ ++ case TYPE_PAIR(IS_STRING, IS_LONG): ++ ZVAL_LONG(result, -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1), equality_only)); ++ return SUCCESS; ++ ++ case TYPE_PAIR(IS_DOUBLE, IS_STRING): ++ if (zend_isnan(Z_DVAL_P(op1))) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } ++ ++ ZVAL_LONG(result, compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2), equality_only)); ++ return SUCCESS; ++ ++ case TYPE_PAIR(IS_STRING, IS_DOUBLE): ++ if (zend_isnan(Z_DVAL_P(op2))) { ++ ZVAL_LONG(result, 1); ++ return SUCCESS; ++ } ++ ++ ZVAL_LONG(result, -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1), equality_only)); ++ return SUCCESS; ++ + case TYPE_PAIR(IS_OBJECT, IS_NULL): + ZVAL_LONG(result, 1); + return SUCCESS; +@@ -2133,7 +2248,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op1)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op1)->get(op1, &rv); +- ret = compare_function(result, op_free, op2); ++ ret = compare_function_ex(result, op_free, op2, equality_only); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) { +@@ -2143,7 +2258,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, &tmp_free, op2); ++ ret = compare_function_ex(result, &tmp_free, op2, equality_only); + zend_free_obj_get_result(&tmp_free); + return ret; + } +@@ -2152,7 +2267,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + if (Z_OBJ_HT_P(op2)->get) { + zval rv; + op_free = Z_OBJ_HT_P(op2)->get(op2, &rv); +- ret = compare_function(result, op1, op_free); ++ ret = compare_function_ex(result, op1, op_free, equality_only); + zend_free_obj_get_result(op_free); + return ret; + } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) { +@@ -2162,7 +2277,7 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + zend_free_obj_get_result(&tmp_free); + return SUCCESS; + } +- ret = compare_function(result, op1, &tmp_free); ++ ret = compare_function_ex(result, op1, &tmp_free, equality_only); + zend_free_obj_get_result(&tmp_free); + return ret; + } else if (Z_TYPE_P(op1) == IS_OBJECT) { +@@ -2213,6 +2328,12 @@ ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) + } + /* }}} */ + ++ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */ ++{ ++ return compare_function_ex(result, op1, op2, 0); ++} ++/* }}} */ ++ + static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */ + { + /* is_identical_function() returns 1 in case of identity and 0 in case +@@ -2271,7 +2392,7 @@ ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zv + + ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); +@@ -2281,7 +2402,7 @@ ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) + + ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */ + { +- if (compare_function(result, op1, op2) == FAILURE) { ++ if (compare_function_ex(result, op1, op2, 1) == FAILURE) { + return FAILURE; + } + ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); +@@ -2967,15 +3088,44 @@ static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */ + } + /* }}} */ + ++static int hash_zval_compare_function_equality(zval *z1, zval *z2) /* {{{ */ ++{ ++ zval result; ++ ++ if (compare_function_ex(&result, z1, z2, 1)==FAILURE) { ++ return 1; ++ } ++ return Z_LVAL(result); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only) /* {{{ */ ++{ ++ if (ht1 == ht2) { ++ return 0; ++ } ++ return zend_hash_compare(ht1, ht2, ++ equality_only ++ ? (compare_func_t) hash_zval_compare_function_equality ++ : (compare_func_t) hash_zval_compare_function, 0); ++} ++/* }}} */ ++ + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */ + { +- return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0); ++ return zend_compare_symbol_tables_ex(ht1, ht2, 0); ++} ++/* }}} */ ++ ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only) /* {{{ */ ++{ ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), equality_only); + } + /* }}} */ + + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */ + { +- return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2)); ++ return zend_compare_symbol_tables_ex(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2), 0); + } + /* }}} */ + +diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h +index dad23bc4d8c83..05fecf4cf2989 100644 +--- a/Zend/zend_operators.h ++++ b/Zend/zend_operators.h +@@ -388,6 +388,7 @@ static zend_always_inline int i_zend_is_true(zval *op) + return result; + } + ++ZEND_API int ZEND_FASTCALL compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2); + + ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2); +@@ -417,7 +418,9 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1 + + ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2); + ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2); ++ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables_ex(HashTable *ht1, HashTable *ht2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2); ++ZEND_API int ZEND_FASTCALL zend_compare_arrays_ex(zval *a1, zval *a2, zend_bool equality_only); + ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2); + ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2); + +@@ -860,7 +863,7 @@ static zend_always_inline int fast_equal_check_function(zval *op1, zval *op2) + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -870,7 +873,7 @@ static zend_always_inline int fast_equal_check_long(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { + return Z_LVAL_P(op1) == Z_LVAL_P(op2); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +@@ -880,7 +883,7 @@ static zend_always_inline int fast_equal_check_string(zval *op1, zval *op2) + if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) { + return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2)); + } +- compare_function(&result, op1, op2); ++ compare_function_ex(&result, op1, op2, 1); + return Z_LVAL(result) == 0; + } + +diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h +index 827548504cc29..eb09c1ba64087 100644 +--- a/Zend/zend_vm_def.h ++++ b/Zend/zend_vm_def.h +@@ -498,7 +498,7 @@ ZEND_VM_HELPER(zend_is_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -593,7 +593,7 @@ ZEND_VM_HELPER(zend_is_not_equal_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -688,7 +688,7 @@ ZEND_VM_HELPER(zend_is_smaller_helper, ANY, ANY, zval *op_1, zval *op_2) + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -768,7 +768,7 @@ ZEND_VM_HELPER(zend_is_smaller_or_equal_helper, ANY, ANY, zval *op_1, zval *op_2 + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h +index ae30886c9056d..4b10d2c0d0b6c 100644 +--- a/Zend/zend_vm_execute.h ++++ b/Zend/zend_vm_execute.h +@@ -587,7 +587,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_equal_hel + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -619,7 +619,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_not_equal + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -651,7 +651,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_h + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } +@@ -683,7 +683,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_is_smaller_o + if (UNEXPECTED(Z_TYPE_INFO_P(op_2) == IS_UNDEF)) { + op_2 = ZVAL_UNDEFINED_OP2(); + } +- compare_function(EX_VAR(opline->result.var), op_1, op_2); ++ compare_function_ex(EX_VAR(opline->result.var), op_1, op_2, 1); + if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor_nogc(op_1); + } diff --git a/7.4/bullseye/apache/Dockerfile b/7.4/bullseye/apache/Dockerfile index 327725b9b8..96d479cc1f 100644 --- a/7.4/bullseye/apache/Dockerfile +++ b/7.4/bullseye/apache/Dockerfile @@ -154,6 +154,8 @@ RUN set -eux; \ apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false COPY docker-php-source /usr/local/bin/ +# patch https://github.com/php/php-src/pull/3917.diff +COPY 1.diff / RUN set -eux; \ \ @@ -179,6 +181,10 @@ RUN set -eux; \ ; \ docker-php-source extract; \ cd /usr/src/php; \ +# ----------PATCH---------- + patch -p1 < /1.diff; \ + rm /1.diff; \ +# ----------END_PATCH---------- gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \ debMultiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)"; \ # https://bugs.php.net/bug.php?id=74125 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..7074b2e127 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +# MakeコマンドにAWS_PROFILEを渡してね +build: setup build-apache build-alpine cleanup + +setup: + aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 426786900385.dkr.ecr.ap-northeast-1.amazonaws.com + +build-alpine: + docker \ + buildx build \ + -t 426786900385.dkr.ecr.ap-northeast-1.amazonaws.com/phpatch:7.4-alpine \ + --platform "linux/amd64" \ + --progress plain \ + ./7.4/alpine3.16/cli \ + --push + +build-apache: + docker \ + buildx build \ + -t 426786900385.dkr.ecr.ap-northeast-1.amazonaws.com/phpatch:7.4-apache \ + --platform "linux/amd64" \ + --progress plain \ + ./7.4/bullseye/apache \ + --push + +# 本来php公式イメージがサポートしているプラットフォーム +# linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# +# multi-platformで試した痕跡 +# (docker-desktop環境ではつらみ) +# +# docker buildx create --name phpbuilder || true +# docker buildx use phpbuilder +# docker buildx inspect --bootstrap +# docker run --privileged --rm tonistiigi/binfmt --install all +# docker -H ssh://USER@REMOTE_HOST info +# docker buildx create \ +# --name arm_remote_builder \ +# --node arm_remote_builder \ +# --platform linux/arm64 \ +# --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10000000 \ +# --driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000 +# docker buildx create \ +# --name arm_remote_builder \ +# --append \ +# --node intelarch \ +# --platform linux/arm64 \ +# ssh://ec2-user@35.72.11.197 \ +# --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10000000 \ +# --driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000 +# docker buildx use arm_remote_builder +# docker buildx inspect --bootstrap +# cleanup: +# docker buildx rm phpbuilder +