diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c index 3f298fc6d934b..c8b95d034d15c 100644 --- a/TSRM/TSRM.c +++ b/TSRM/TSRM.c @@ -729,13 +729,13 @@ TSRM_API size_t tsrm_get_ls_cache_tcb_offset(void) #if defined(__APPLE__) && defined(__x86_64__) // TODO: Implement support for fast JIT ZTS code ??? return 0; -#elif defined(__x86_64__) && defined(__GNUC__) && !defined(__FreeBSD__) +#elif defined(__x86_64__) && defined(__GNUC__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) size_t ret; asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0" : "=r" (ret)); return ret; -#elif defined(__i386__) && defined(__GNUC__) && !defined(__FreeBSD__) +#elif defined(__i386__) && defined(__GNUC__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) size_t ret; asm ("leal _tsrm_ls_cache@ntpoff,%0" diff --git a/Zend/Optimizer/pass1.c b/Zend/Optimizer/pass1.c index 8f3c263833dd6..3579ea1c6bfc8 100644 --- a/Zend/Optimizer/pass1.c +++ b/Zend/Optimizer/pass1.c @@ -25,7 +25,6 @@ * - constant expression evaluation * - optimize constant conditional JMPs * - pre-evaluate constant function calls - * - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM */ #include "php.h" @@ -531,52 +530,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); } break; -#if 0 - /* see ext/opcache/tests/bug78961.phpt */ -// case ZEND_FETCH_R: - case ZEND_FETCH_W: -// case ZEND_FETCH_RW: - case ZEND_FETCH_IS: -// case ZEND_FETCH_FUNC_ARG: - case ZEND_FETCH_UNSET: - /* convert FETCH $GLOBALS (global), FETCH_DIM $x into FETCH $x (global) */ - if ((opline->extended_value & ZEND_FETCH_GLOBAL) != 0 && - opline->op1_type == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && - zend_string_equals_literal(Z_STR(ZEND_OP1_LITERAL(opline)), "GLOBALS") && - ((opline + 1)->opcode == opline->opcode + 1 || - ((opline + 1)->opcode == ZEND_UNSET_DIM && - opline->opcode == ZEND_FETCH_UNSET) || - ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ && - opline->opcode == ZEND_FETCH_IS)) && - (opline + 1)->op1_type == opline->result_type && - (opline + 1)->op1.var == opline->result.var && - ((opline + 1)->op2_type != IS_CONST || - Z_TYPE(ZEND_OP2_LITERAL(opline + 1)) < IS_ARRAY)) { - - if ((opline + 1)->opcode == ZEND_UNSET_DIM) { - (opline + 1)->opcode = ZEND_UNSET_VAR; - (opline + 1)->extended_value = ZEND_FETCH_GLOBAL; - } else if ((opline + 1)->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ) { - (opline + 1)->opcode = ZEND_ISSET_ISEMPTY_VAR; - (opline + 1)->extended_value |= ZEND_FETCH_GLOBAL; - } else { - (opline + 1)->opcode = opline->opcode; - (opline + 1)->extended_value = ZEND_FETCH_GLOBAL; - } - (opline + 1)->op1_type = (opline + 1)->op2_type; - (opline + 1)->op1 = (opline + 1)->op2; - if ((opline + 1)->op1_type == IS_CONST && - Z_TYPE(ZEND_OP1_LITERAL(opline + 1)) != IS_STRING) { - - convert_to_string(&ZEND_OP1_LITERAL(opline + 1)); - zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline + 1))); - } - SET_UNUSED((opline + 1)->op2); - MAKE_NOP(opline); - } - break; -#endif case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 2f2020fb3ed2a..0e18481f40738 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -95,6 +95,10 @@ static const func_info_t func_infos[] = { F1("filter_input_array", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_FALSE|MAY_BE_NULL), F1("filter_var_array", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_FALSE|MAY_BE_NULL), F1("filter_list", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), + F1("ftp_raw", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_NULL), + F1("ftp_nlist", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), + F1("ftp_rawlist", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), + F1("ftp_mlsd", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE), F1("gd_info", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_FALSE|MAY_BE_ARRAY_OF_TRUE), F1("imagecreatetruecolor", MAY_BE_OBJECT|MAY_BE_FALSE), #if defined(PHP_WIN32) @@ -163,6 +167,10 @@ static const func_info_t func_infos[] = { #if defined(HAVE_BIND_TEXTDOMAIN_CODESET) F1("bind_textdomain_codeset", MAY_BE_STRING|MAY_BE_FALSE), #endif + F1("gmp_div_qr", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_OBJECT), + F1("gmp_sqrtrem", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_OBJECT), + F1("gmp_rootrem", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_OBJECT), + F1("gmp_gcdext", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_OBJECT), F1("hash", MAY_BE_STRING|MAY_BE_FALSE), F1("hash_file", MAY_BE_STRING|MAY_BE_FALSE), F1("hash_hmac", MAY_BE_STRING|MAY_BE_FALSE), @@ -189,6 +197,13 @@ static const func_info_t func_infos[] = { F1("iconv_mime_decode_headers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE), F1("iconv", MAY_BE_STRING|MAY_BE_FALSE), F1("iconv_get_encoding", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_STRING|MAY_BE_FALSE), + F1("intlcal_get_available_locales", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING), + F1("datefmt_localtime", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_FALSE), + F1("locale_get_keywords", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE|MAY_BE_NULL), + F1("msgfmt_parse", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_DOUBLE|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), + F1("msgfmt_parse_message", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_DOUBLE|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), + F1("resourcebundle_locales", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), + F1("transliterator_list_ids", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_FALSE), F1("json_encode", MAY_BE_STRING|MAY_BE_FALSE), F1("json_last_error_msg", MAY_BE_STRING), F1("ldap_get_entries", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE), diff --git a/Zend/tests/bug81626.phpt b/Zend/tests/bug81626.phpt new file mode 100644 index 0000000000000..b05cb23097bbb --- /dev/null +++ b/Zend/tests/bug81626.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #81626: Error on use static:: in __сallStatic() wrapped to Closure::fromCallable() +--FILE-- + +--EXPECT-- +string(2) "ok" diff --git a/Zend/tests/bug81631.phpt b/Zend/tests/bug81631.phpt new file mode 100644 index 0000000000000..191ea951274d2 --- /dev/null +++ b/Zend/tests/bug81631.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #81631: ::class with dynamic class name may yield wrong line number +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $b in %s on line 3 + +Fatal error: Uncaught TypeError: Cannot use "::class" on value of type null in %s:3 +Stack trace: +#0 {main} + thrown in %s on line 3 diff --git a/Zend/tests/class_constant_inheritance_mutable_data.phpt b/Zend/tests/class_constant_inheritance_mutable_data.phpt new file mode 100644 index 0000000000000..0accf79c1dcfb --- /dev/null +++ b/Zend/tests/class_constant_inheritance_mutable_data.phpt @@ -0,0 +1,39 @@ +--TEST-- +Class constant inheritance with mutable data +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +object(B)#1 (0) { +} +string(2) "XY" +string(4) "X2Y2" + +Deprecated: Implicit conversion from float 1.5 to int loses precision in %s on line %d +int(0) +int(0) diff --git a/Zend/tests/weakrefs/weakrefs_006.phpt b/Zend/tests/weakrefs/weakrefs_006.phpt new file mode 100644 index 0000000000000..a15ab6b542d57 --- /dev/null +++ b/Zend/tests/weakrefs/weakrefs_006.phpt @@ -0,0 +1,116 @@ +--TEST-- +WeakReference overwriting existing value +--FILE-- + +--EXPECT-- +In destruct +object(WeakMap)#1 (11) { + [0]=> + array(2) { + ["key"]=> + object(stdClass)#2 (0) { + } + ["value"]=> + int(123) + } + [1]=> + array(2) { + ["key"]=> + object(stdClass)#4 (0) { + } + ["value"]=> + int(0) + } + [2]=> + array(2) { + ["key"]=> + object(stdClass)#5 (0) { + } + ["value"]=> + int(1) + } + [3]=> + array(2) { + ["key"]=> + object(stdClass)#6 (0) { + } + ["value"]=> + int(2) + } + [4]=> + array(2) { + ["key"]=> + object(stdClass)#7 (0) { + } + ["value"]=> + int(3) + } + [5]=> + array(2) { + ["key"]=> + object(stdClass)#8 (0) { + } + ["value"]=> + int(4) + } + [6]=> + array(2) { + ["key"]=> + object(stdClass)#9 (0) { + } + ["value"]=> + int(5) + } + [7]=> + array(2) { + ["key"]=> + object(stdClass)#10 (0) { + } + ["value"]=> + int(6) + } + [8]=> + array(2) { + ["key"]=> + object(stdClass)#11 (0) { + } + ["value"]=> + int(7) + } + [9]=> + array(2) { + ["key"]=> + object(stdClass)#12 (0) { + } + ["value"]=> + int(8) + } + [10]=> + array(2) { + ["key"]=> + object(stdClass)#13 (0) { + } + ["value"]=> + int(9) + } +} \ No newline at end of file diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 2ecfc6db2d913..3ef291c315596 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1325,12 +1325,19 @@ ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_ zend_hash_extend(constants_table, zend_hash_num_elements(&class_type->constants_table), 0); ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) { - if (Z_TYPE(c->value) == IS_CONSTANT_AST) { - new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant)); - memcpy(new_c, c, sizeof(zend_class_constant)); - c = new_c; + if (c->ce == class_type) { + if (Z_TYPE(c->value) == IS_CONSTANT_AST) { + new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant)); + memcpy(new_c, c, sizeof(zend_class_constant)); + c = new_c; + } + Z_TRY_ADDREF(c->value); + } else { + if (Z_TYPE(c->value) == IS_CONSTANT_AST) { + c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(c->ce), key); + ZEND_ASSERT(c); + } } - Z_TRY_ADDREF(c->value); _zend_hash_append_ptr(constants_table, key, c); } ZEND_HASH_FOREACH_END(); @@ -1412,8 +1419,18 @@ ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) / } else { constants_table = &class_type->constants_table; } - ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) { + + zend_string *name; + ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(constants_table, name, val) { + c = Z_PTR_P(val); if (Z_TYPE(c->value) == IS_CONSTANT_AST) { + if (c->ce != class_type) { + Z_PTR_P(val) = c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(c->ce), name); + if (Z_TYPE(c->value) != IS_CONSTANT_AST) { + continue; + } + } + val = &c->value; if (UNEXPECTED(zval_update_constant_ex(val, c->ce) != SUCCESS)) { return FAILURE; diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index a064927f93a87..0d69bfbaca369 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -482,7 +482,7 @@ static zend_result zend_ast_add_unpacked_element(zval *result, zval *expr) { zend_class_entry *zend_ast_fetch_class(zend_ast *ast, zend_class_entry *scope) { - return zend_fetch_class(zend_ast_get_str(ast), ast->attr | ZEND_FETCH_CLASS_EXCEPTION); + return zend_fetch_class_with_scope(zend_ast_get_str(ast), ast->attr | ZEND_FETCH_CLASS_EXCEPTION, scope); } ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope) diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 278afc9c10fa3..d13087a5b0264 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -349,6 +349,7 @@ ZEND_API void zend_set_timeout(zend_long seconds, bool reset_signals); ZEND_API void zend_unset_timeout(void); ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void); ZEND_API zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type); +ZEND_API zend_class_entry *zend_fetch_class_with_scope(zend_string *class_name, int fetch_type, zend_class_entry *scope); ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *lcname, int fetch_type); ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 96ee0f33c3d0f..fed3ae1d29963 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1062,10 +1062,12 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * zval *zv; zend_string *lc_name; zend_string *autoload_name; + uint32_t ce_cache = 0; - if (ZSTR_HAS_CE_CACHE(name)) { - ce = ZSTR_GET_CE_CACHE(name); - if (ce) { + if (ZSTR_HAS_CE_CACHE(name) && ZSTR_VALID_CE_CACHE(name)) { + ce_cache = GC_REFCOUNT(name); + ce = GET_CE_CACHE(ce_cache); + if (EXPECTED(ce)) { return ce; } } @@ -1106,9 +1108,9 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * } /* Don't populate CE_CACHE for mutable classes during compilation. * The class may be freed while persisting. */ - if (ZSTR_HAS_CE_CACHE(name) && + if (ce_cache && (!CG(in_compilation) || (ce->ce_flags & ZEND_ACC_IMMUTABLE))) { - ZSTR_SET_CE_CACHE(name, ce); + SET_CE_CACHE(ce_cache, ce); } return ce; } @@ -1164,8 +1166,8 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string * } if (ce) { ZEND_ASSERT(!CG(in_compilation)); - if (ZSTR_HAS_CE_CACHE(name)) { - ZSTR_SET_CE_CACHE(name, ce); + if (ce_cache) { + SET_CE_CACHE(ce_cache, ce); } } return ce; @@ -1508,6 +1510,28 @@ void zend_unset_timeout(void) /* {{{ */ } /* }}} */ +static ZEND_COLD void report_class_fetch_error(zend_string *class_name, int fetch_type) +{ + if (fetch_type & ZEND_FETCH_CLASS_SILENT) { + return; + } + + if (EG(exception)) { + if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) { + zend_exception_uncaught_error("During class fetch"); + } + return; + } + + if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) { + zend_throw_or_error(fetch_type, NULL, "Interface \"%s\" not found", ZSTR_VAL(class_name)); + } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) { + zend_throw_or_error(fetch_type, NULL, "Trait \"%s\" not found", ZSTR_VAL(class_name)); + } else { + zend_throw_or_error(fetch_type, NULL, "Class \"%s\" not found", ZSTR_VAL(class_name)); + } +} + zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type) /* {{{ */ { zend_class_entry *ce, *scope; @@ -1549,41 +1573,51 @@ zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type) /* { ce = zend_lookup_class_ex(class_name, NULL, fetch_type); if (!ce) { - if (!(fetch_type & ZEND_FETCH_CLASS_SILENT) && !EG(exception)) { - if (fetch_sub_type == ZEND_FETCH_CLASS_INTERFACE) { - zend_throw_or_error(fetch_type, NULL, "Interface \"%s\" not found", ZSTR_VAL(class_name)); - } else if (fetch_sub_type == ZEND_FETCH_CLASS_TRAIT) { - zend_throw_or_error(fetch_type, NULL, "Trait \"%s\" not found", ZSTR_VAL(class_name)); - } else { - zend_throw_or_error(fetch_type, NULL, "Class \"%s\" not found", ZSTR_VAL(class_name)); - } - } + report_class_fetch_error(class_name, fetch_type); return NULL; } return ce; } /* }}} */ +zend_class_entry *zend_fetch_class_with_scope( + zend_string *class_name, int fetch_type, zend_class_entry *scope) +{ + zend_class_entry *ce; + switch (fetch_type & ZEND_FETCH_CLASS_MASK) { + case ZEND_FETCH_CLASS_SELF: + if (UNEXPECTED(!scope)) { + zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active"); + } + return scope; + case ZEND_FETCH_CLASS_PARENT: + if (UNEXPECTED(!scope)) { + zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active"); + return NULL; + } + if (UNEXPECTED(!scope->parent)) { + zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent"); + } + return scope->parent; + case 0: + break; + /* Other fetch types are not supported by this function. */ + EMPTY_SWITCH_DEFAULT_CASE() + } + + ce = zend_lookup_class_ex(class_name, NULL, fetch_type); + if (!ce) { + report_class_fetch_error(class_name, fetch_type); + return NULL; + } + return ce; +} + zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *key, int fetch_type) /* {{{ */ { zend_class_entry *ce = zend_lookup_class_ex(class_name, key, fetch_type); if (!ce) { - if (fetch_type & ZEND_FETCH_CLASS_SILENT) { - return NULL; - } - if (EG(exception)) { - if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) { - zend_exception_uncaught_error("During class fetch"); - } - return NULL; - } - if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) { - zend_throw_or_error(fetch_type, NULL, "Interface \"%s\" not found", ZSTR_VAL(class_name)); - } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) { - zend_throw_or_error(fetch_type, NULL, "Trait \"%s\" not found", ZSTR_VAL(class_name)); - } else { - zend_throw_or_error(fetch_type, NULL, "Class \"%s\" not found", ZSTR_VAL(class_name)); - } + report_class_fetch_error(class_name, fetch_type); return NULL; } return ce; diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 24c4ced4b434a..02c316a95a2d0 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -664,6 +664,7 @@ static zend_always_inline Bucket *zend_hash_find_bucket(const HashTable *ht, zen if (known_hash) { h = ZSTR_H(key); + ZEND_ASSERT(h != 0 && "Hash must be known"); } else { h = zend_string_hash_val(key); } diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index b7559257d27e5..e004439029f6e 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -1093,7 +1093,7 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht, _ptr = Z_PTR_P(_z); #define ZEND_HASH_REVERSE_FOREACH_PTR(ht, _ptr) \ - _ZEND_HASH_REVERSE_FOREACH_VAL(ht, 0); \ + _ZEND_HASH_REVERSE_FOREACH_VAL(ht); \ _ptr = Z_PTR_P(_z); #define ZEND_HASH_FOREACH_NUM_KEY(ht, _h) \ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 3a4aaba0a3dba..55d67a59144e9 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2768,9 +2768,6 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string } zv = zend_hash_find_known_hash(CG(class_table), key); Z_CE_P(zv) = ret; - if (ZSTR_HAS_CE_CACHE(ret->name)) { - ZSTR_SET_CE_CACHE(ret->name, ret); - } return ret; } @@ -2995,9 +2992,6 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_ if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) { return NULL; } - if (ZSTR_HAS_CE_CACHE(ret->name)) { - ZSTR_SET_CE_CACHE(ret->name, ret); - } return ret; } } else { diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index a63b67a1c18ac..ac4fb75e986ae 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -250,7 +250,9 @@ ZEND_API void zend_cleanup_mutable_class_data(zend_class_entry *ce) zend_class_constant *c; ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) { - zval_ptr_dtor_nogc(&c->value); + if (c->ce == ce) { + zval_ptr_dtor_nogc(&c->value); + } } ZEND_HASH_FOREACH_END(); zend_hash_destroy(constants_table); mutable_data->constants_table = NULL; diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 6f7fef32a0e23..151afadec2258 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -726,10 +726,25 @@ static zend_always_inline uint32_t zval_gc_info(uint32_t gc_type_info) { /* Fast class cache */ #define ZSTR_HAS_CE_CACHE(s) (GC_FLAGS(s) & IS_STR_CLASS_NAME_MAP_PTR) -#define ZSTR_GET_CE_CACHE(s) \ - (*(zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR(GC_REFCOUNT(s))) -#define ZSTR_SET_CE_CACHE(s, ce) do { \ - *((zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR(GC_REFCOUNT(s))) = ce; \ +#define ZSTR_GET_CE_CACHE(s) ZSTR_GET_CE_CACHE_EX(s, 1) +#define ZSTR_SET_CE_CACHE(s, ce) ZSTR_SET_CE_CACHE_EX(s, ce, 1) + +#define ZSTR_VALID_CE_CACHE(s) EXPECTED((GC_REFCOUNT(s)-1)/sizeof(void *) < CG(map_ptr_last)) + +#define ZSTR_GET_CE_CACHE_EX(s, validate) \ + ((!(validate) || ZSTR_VALID_CE_CACHE(s)) ? GET_CE_CACHE(GC_REFCOUNT(s)) : NULL) + +#define ZSTR_SET_CE_CACHE_EX(s, ce, validate) do { \ + if (!(validate) || ZSTR_VALID_CE_CACHE(s)) { \ + SET_CE_CACHE(GC_REFCOUNT(s), ce); \ + } \ + } while (0) + +#define GET_CE_CACHE(ce_cache) \ + (*(zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR(ce_cache)) + +#define SET_CE_CACHE(ce_cache, ce) do { \ + *((zend_class_entry **)ZEND_MAP_PTR_OFFSET2PTR(ce_cache)) = ce; \ } while (0) /* Recursion protection macros must be used only for arrays and objects */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 551d1394cf241..bf12c06df7b48 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8517,8 +8517,8 @@ ZEND_VM_HANDLER(157, ZEND_FETCH_CLASS_NAME, CV|TMPVAR|UNUSED|CLASS_FETCH, ANY) USE_OPLINE if (OP1_TYPE != IS_UNUSED) { - zval *op = GET_OP1_ZVAL_PTR(BP_VAR_R); SAVE_OPLINE(); + zval *op = GET_OP1_ZVAL_PTR(BP_VAR_R); if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index ff838bf71259a..f2d73fd451d8b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -14753,8 +14753,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_TMPVAR_H USE_OPLINE if ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) { - zval *op = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); SAVE_OPLINE(); + zval *op = _get_zval_ptr_var(opline->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { @@ -31197,8 +31197,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_UNUSED_H USE_OPLINE if (IS_UNUSED != IS_UNUSED) { - zval *op = NULL; SAVE_OPLINE(); + zval *op = NULL; if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { @@ -38779,8 +38779,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_NAME_SPEC_CV_HANDL USE_OPLINE if (IS_CV != IS_UNUSED) { - zval *op = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); SAVE_OPLINE(); + zval *op = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(Z_TYPE_P(op) != IS_OBJECT)) { ZVAL_DEREF(op); if (Z_TYPE_P(op) != IS_OBJECT) { diff --git a/Zend/zend_weakrefs.c b/Zend/zend_weakrefs.c index a4b16fbe97002..e4cfadb73c5d5 100644 --- a/Zend/zend_weakrefs.c +++ b/Zend/zend_weakrefs.c @@ -87,9 +87,9 @@ static void zend_weakref_register(zend_object *object, void *payload) { GC_ADD_FLAGS(object, IS_OBJ_WEAKLY_REFERENCED); zend_ulong obj_addr = (zend_ulong) object; - zval *zv = zend_hash_index_find(&EG(weakrefs), obj_addr); - if (!zv) { - zend_hash_index_add_new_ptr(&EG(weakrefs), obj_addr, payload); + zval *zv = zend_hash_index_lookup(&EG(weakrefs), obj_addr); + if (Z_TYPE_P(zv) == IS_NULL) { + ZVAL_PTR(zv, payload); return; } @@ -127,9 +127,11 @@ static void zend_weakref_unregister(zend_object *object, void *payload) { } HashTable *ht = ptr; - tagged_ptr = zend_hash_index_find_ptr(ht, (zend_ulong) payload); - ZEND_ASSERT(tagged_ptr && "Weakref not registered?"); - ZEND_ASSERT(tagged_ptr == payload); +#if ZEND_DEBUG + void *old_payload = zend_hash_index_find_ptr(ht, (zend_ulong) payload); + ZEND_ASSERT(old_payload && "Weakref not registered?"); + ZEND_ASSERT(old_payload == payload); +#endif zend_hash_index_del(ht, (zend_ulong) payload); if (zend_hash_num_elements(ht) == 0) { GC_DEL_FLAGS(object, IS_OBJ_WEAKLY_REFERENCED); @@ -346,8 +348,12 @@ static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval zval *zv = zend_hash_index_find(&wm->ht, (zend_ulong) obj_key); if (zv) { - zval_ptr_dtor(zv); + /* Because the destructors can have side effects such as resizing or rehashing the WeakMap storage, + * free the zval only after overwriting the original value. */ + zval zv_orig; + ZVAL_COPY_VALUE(&zv_orig, zv); ZVAL_COPY_VALUE(zv, value); + zval_ptr_dtor(&zv_orig); return; } diff --git a/build/gen_stub.php b/build/gen_stub.php index ecbad1eb19440..5f74d26dbc37d 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3310,7 +3310,7 @@ function initPhpParser() { } if (isset($options["h"]) || isset($options["help"])) { - die("\nusage: gen_stub.php [ -f | --force-regeneration ] [ --generate-classsynopses ] [ --replace-classsynopses ] [ --generate-methodsynopses ] [ --replace-methodsynopses ] [ --parameter-stats ] [ --verify ] [ -h | --help ] [ name.stub.php | directory ] [ directory ]\n\n"); + die("\nusage: gen_stub.php [ -f | --force-regeneration ] [ --generate-classsynopses ] [ --replace-classsynopses ] [ --generate-methodsynopses ] [ --replace-methodsynopses ] [ --parameter-stats ] [ --verify ] [ --generate-optimizer-info ] [ -h | --help ] [ name.stub.php | directory ] [ directory ]\n\n"); } $fileInfos = []; diff --git a/ext/date/lib/timelib.c b/ext/date/lib/timelib.c index f363d8a616e65..060c2d79db46e 100644 --- a/ext/date/lib/timelib.c +++ b/ext/date/lib/timelib.c @@ -200,7 +200,7 @@ void timelib_decimal_hour_to_hms(double h, int *hour, int *min, int *sec) void timelib_hms_to_decimal_hour(int hour, int min, int sec, double *h) { - if (hour > 0) { + if (hour >= 0) { *h = ((double)hour + (double)min / 60 + (double)sec / 3600); } else { *h = ((double)hour - (double)min / 60 - (double)sec / 3600); @@ -209,7 +209,7 @@ void timelib_hms_to_decimal_hour(int hour, int min, int sec, double *h) void timelib_hmsf_to_decimal_hour(int hour, int min, int sec, int us, double *h) { - if (hour > 0) { + if (hour >= 0) { *h = ((double)hour + (double)min / MINS_PER_HOUR + (double)sec / SECS_PER_HOUR) + (double)us / USECS_PER_HOUR; } else { *h = ((double)hour - (double)min / MINS_PER_HOUR - (double)sec / SECS_PER_HOUR) - (double)us / USECS_PER_HOUR; diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index bb04cad07063d..6b5b259a57a44 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202110 -#define TIMELIB_EXTENDED_VERSION 20211001 -#define TIMELIB_ASCII_VERSION "2021.10" +#define TIMELIB_VERSION 202111 +#define TIMELIB_EXTENDED_VERSION 20211101 +#define TIMELIB_ASCII_VERSION "2021.11" #include #include diff --git a/ext/date/tests/bug81458.phpt b/ext/date/tests/bug81458.phpt index ab0c46faffaca..709bedfde60eb 100644 --- a/ext/date/tests/bug81458.phpt +++ b/ext/date/tests/bug81458.phpt @@ -7,7 +7,14 @@ $second = new DateTime('2018-07-02 00:00:00.000000 America/Toronto'); var_dump($first->diff($second)->days); var_dump($first->diff($second)->d); + +date_default_timezone_set('UTC'); +$a = new DateTime('2018-12-01 00:00'); +$b = new DateTime('2018-12-02 00:01'); + +var_dump($a->diff($b)->days); ?> --EXPECT-- int(1) int(1) +int(1) diff --git a/ext/ftp/ftp.stub.php b/ext/ftp/ftp.stub.php index 6693641e2b497..13708c6be6d96 100644 --- a/ext/ftp/ftp.stub.php +++ b/ext/ftp/ftp.stub.php @@ -27,6 +27,11 @@ function ftp_pwd(FTP\Connection $ftp): string|false {} function ftp_cdup(FTP\Connection $ftp): bool {} function ftp_chdir(FTP\Connection $ftp, string $directory): bool {} function ftp_exec(FTP\Connection $ftp, string $command): bool {} + + /** + * @return array|null + * @refcount 1 + */ function ftp_raw(FTP\Connection $ftp, string $command): ?array {} function ftp_mkdir(FTP\Connection $ftp, string $directory): string|false {} function ftp_rmdir(FTP\Connection $ftp, string $directory): bool {} @@ -34,9 +39,25 @@ function ftp_chmod(FTP\Connection $ftp, int $permissions, string $filename): int /** @param string $response */ function ftp_alloc(FTP\Connection $ftp, int $size, &$response = null): bool {} + + /** + * @return array|false + * @refcount 1 + */ function ftp_nlist(FTP\Connection $ftp, string $directory): array|false {} + + /** + * @return array|false + * @refcount 1 + */ function ftp_rawlist(FTP\Connection $ftp, string $directory, bool $recursive = false): array|false {} + + /** + * @return array|false + * @refcount 1 + */ function ftp_mlsd(FTP\Connection $ftp, string $directory): array|false {} + function ftp_systype(FTP\Connection $ftp): string|false {} /** @param resource $stream */ diff --git a/ext/ftp/ftp_arginfo.h b/ext/ftp/ftp_arginfo.h index 92c580ca28bb7..654f2dae450a7 100644 --- a/ext/ftp/ftp_arginfo.h +++ b/ext/ftp/ftp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6de0997e9f07a8e1079764ab1841d3ac4651cc53 */ + * Stub hash: 2b1726dd5652839a37e533e20dfcf6782b3c766d */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_ftp_connect, 0, 1, FTP\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 315da803de661..c75e2788b869a 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -2017,3 +2017,48 @@ ZEND_FUNCTION(gmp_scan1) FREE_GMP_TEMP(temp_a); } /* }}} */ + +ZEND_METHOD(GMP, __serialize) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zval zv; + array_init(return_value); + + mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(ZEND_THIS); + gmp_strval(&zv, gmpnum, 16); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &zv); + + HashTable *props = Z_OBJ_P(ZEND_THIS)->properties; + if (props && zend_hash_num_elements(props) != 0) { + ZVAL_ARR(&zv, zend_proptable_to_symtable( + zend_std_get_properties(Z_OBJ_P(ZEND_THIS)), /* always duplicate */ 1)); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &zv); + } +} + +ZEND_METHOD(GMP, __unserialize) +{ + HashTable *data; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY_HT(data) + ZEND_PARSE_PARAMETERS_END(); + + zval *num = zend_hash_index_find(data, 0); + if (!num || Z_TYPE_P(num) != IS_STRING || + convert_to_gmp(GET_GMP_FROM_ZVAL(ZEND_THIS), num, 16, 0) == FAILURE) { + zend_throw_exception(NULL, "Could not unserialize number", 0); + RETURN_THROWS(); + } + + zval *props = zend_hash_index_find(data, 1); + if (props) { + if (Z_TYPE_P(props) != IS_ARRAY) { + zend_throw_exception(NULL, "Could not unserialize properties", 0); + RETURN_THROWS(); + } + + object_properties_load(Z_OBJ_P(ZEND_THIS), Z_ARRVAL_P(props)); + } +} diff --git a/ext/gmp/gmp.stub.php b/ext/gmp/gmp.stub.php index 06e96c8392691..280fa6abd7db6 100644 --- a/ext/gmp/gmp.stub.php +++ b/ext/gmp/gmp.stub.php @@ -4,6 +4,9 @@ class GMP { + public function __serialize(): array {} + + public function __unserialize(array $data): void {} } function gmp_init(int|string $num, int $base = 0): GMP {} @@ -22,6 +25,10 @@ function gmp_sub(GMP|int|string $num1, GMP|int|string $num2): GMP {} function gmp_mul(GMP|int|string $num1, GMP|int|string $num2): GMP {} +/** + * @return array + * @refcount 1 + */ function gmp_div_qr(GMP|int|string $num1, GMP|int|string $num2, int $rounding_mode = GMP_ROUND_ZERO): array {} function gmp_div_q(GMP|int|string $num1, GMP|int|string $num2, int $rounding_mode = GMP_ROUND_ZERO): GMP {} @@ -43,10 +50,18 @@ function gmp_fact(GMP|int|string $num): GMP {} function gmp_sqrt(GMP|int|string $num): GMP {} +/** + * @return array + * @refcount 1 + */ function gmp_sqrtrem(GMP|int|string $num): array {} function gmp_root(GMP|int|string $num, int $nth): GMP {} +/** + * @return array + * @refcount 1 + */ function gmp_rootrem(GMP|int|string $num, int $nth): array {} function gmp_pow(GMP|int|string $num, int $exponent): GMP {} @@ -61,6 +76,10 @@ function gmp_prob_prime(GMP|int|string $num, int $repetitions = 10): int {} function gmp_gcd(GMP|int|string $num1, GMP|int|string $num2): GMP {} +/** + * @return array + * @refcount 1 + */ function gmp_gcdext(GMP|int|string $num1, GMP|int|string $num2): array {} function gmp_lcm(GMP|int|string $num1, GMP|int|string $num2): GMP {} diff --git a/ext/gmp/gmp_arginfo.h b/ext/gmp/gmp_arginfo.h index 2bb36745457ed..8091359df9df5 100644 --- a/ext/gmp/gmp_arginfo.h +++ b/ext/gmp/gmp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 69215fb94adb4156c974360e5698e842471cb27d */ + * Stub hash: be077a57bc9ddbb9100fadfb212857c0b8f21ebf */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_init, 0, 1, GMP, 0) ZEND_ARG_TYPE_MASK(0, num, MAY_BE_LONG|MAY_BE_STRING, NULL) @@ -184,6 +184,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_gmp_binomial, 0, 2, GMP, 0) ZEND_ARG_TYPE_INFO(0, k, IS_LONG, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_GMP___serialize, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_GMP___unserialize, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_FUNCTION(gmp_init); ZEND_FUNCTION(gmp_import); @@ -235,6 +242,8 @@ ZEND_FUNCTION(gmp_popcount); ZEND_FUNCTION(gmp_hamdist); ZEND_FUNCTION(gmp_nextprime); ZEND_FUNCTION(gmp_binomial); +ZEND_METHOD(GMP, __serialize); +ZEND_METHOD(GMP, __unserialize); static const zend_function_entry ext_functions[] = { @@ -294,6 +303,8 @@ static const zend_function_entry ext_functions[] = { static const zend_function_entry class_GMP_methods[] = { + ZEND_ME(GMP, __serialize, arginfo_class_GMP___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(GMP, __unserialize, arginfo_class_GMP___unserialize, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/gmp/tests/serialize.phpt b/ext/gmp/tests/serialize.phpt index e54530107ea20..4b42db7606d6a 100644 --- a/ext/gmp/tests/serialize.phpt +++ b/ext/gmp/tests/serialize.phpt @@ -11,7 +11,10 @@ var_dump(unserialize($s)); $n = gmp_init(13); $n->foo = "bar"; -var_dump(unserialize(serialize($n))); +var_dump($s = serialize($n)); +var_dump(unserialize($s)); + +var_dump(unserialize('C:3:"GMP":15:{s:2:"42";a:0:{}}')); try { unserialize('C:3:"GMP":0:{}'); @@ -21,22 +24,47 @@ try { unserialize('C:3:"GMP":9:{s:2:"42";}'); } catch (Exception $e) { var_dump($e->getMessage()); } +try { + unserialize('O:3:"GMP":0:{}'); +} catch (Exception $e) { var_dump($e->getMessage()); } + +try { + unserialize('O:3:"GMP":1:{i:0;i:0;}'); +} catch (Exception $e) { var_dump($e->getMessage()); } + +try { + unserialize('O:3:"GMP":1:{i:0;s:0:"";}'); +} catch (Exception $e) { var_dump($e->getMessage()); } + +try { + unserialize('O:3:"GMP":2:{i:0;s:1:"0";i:1;i:0;}'); +} catch (Exception $e) { var_dump($e->getMessage()); } + ?> --EXPECTF-- object(GMP)#%d (1) { ["num"]=> string(2) "42" } -string(30) "C:3:"GMP":15:{s:2:"42";a:0:{}}" +string(27) "O:3:"GMP":1:{i:0;s:2:"2a";}" object(GMP)#%d (1) { ["num"]=> string(2) "42" } +string(56) "O:3:"GMP":2:{i:0;s:1:"d";i:1;a:1:{s:3:"foo";s:3:"bar";}}" object(GMP)#%d (2) { ["foo"]=> string(3) "bar" ["num"]=> string(2) "13" } +object(GMP)#1 (1) { + ["num"]=> + string(2) "42" +} +string(28) "Could not unserialize number" +string(32) "Could not unserialize properties" +string(28) "Could not unserialize number" +string(28) "Could not unserialize number" string(28) "Could not unserialize number" string(32) "Could not unserialize properties" diff --git a/ext/intl/calendar/calendar.stub.php b/ext/intl/calendar/calendar.stub.php index ed491cb2c4e20..709d0e3667c7f 100644 --- a/ext/intl/calendar/calendar.stub.php +++ b/ext/intl/calendar/calendar.stub.php @@ -74,6 +74,7 @@ public function getActualMaximum(int $field): int|false {} public function getActualMinimum(int $field): int|false {} /** + * @return array * @tentative-return-type * @alias intlcal_get_available_locales */ diff --git a/ext/intl/calendar/calendar_arginfo.h b/ext/intl/calendar/calendar_arginfo.h index 6f3733372f90e..7be45231f9c90 100644 --- a/ext/intl/calendar/calendar_arginfo.h +++ b/ext/intl/calendar/calendar_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2265c2a4f478d6ccd576ce09a19a158df38a2bdb */ + * Stub hash: 7be0e49d2b898587c4bbefaaf613932ae4786c52 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlCalendar___construct, 0, 0, 0) ZEND_END_ARG_INFO() diff --git a/ext/intl/converter/converter.stub.php b/ext/intl/converter/converter.stub.php index 7e2b207e44e79..9e07341778b20 100644 --- a/ext/intl/converter/converter.stub.php +++ b/ext/intl/converter/converter.stub.php @@ -15,10 +15,16 @@ public function convert(string $str, bool $reverse = false): string|false {} */ public function fromUCallback(int $reason, array $source, int $codePoint, &$error): string|int|array|null {} - /** @tentative-return-type */ + /** + * @return array|false|null + * @tentative-return-type + */ public static function getAliases(string $name): array|false|null {} - /** @tentative-return-type */ + /** + * @return array + * @tentative-return-type + */ public static function getAvailable(): array {} /** @tentative-return-type */ diff --git a/ext/intl/converter/converter_arginfo.h b/ext/intl/converter/converter_arginfo.h index 663c68271a5ae..fa88dd2ab630e 100644 --- a/ext/intl/converter/converter_arginfo.h +++ b/ext/intl/converter/converter_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a6b352ba1b6ad2367bd4705ac941e763f74c8fac */ + * Stub hash: 2a6d8499e1a2d414130e366783a1c084f47a3293 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_UConverter___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, destination_encoding, IS_STRING, 1, "null") diff --git a/ext/intl/dateformat/dateformat.stub.php b/ext/intl/dateformat/dateformat.stub.php index e00e654b131c2..11c0d05dc41e6 100644 --- a/ext/intl/dateformat/dateformat.stub.php +++ b/ext/intl/dateformat/dateformat.stub.php @@ -134,6 +134,7 @@ public function parse(string $string, &$offset = null): int|float|false {} /** * @param int $offset + * @return array|false * @tentative-return-type * @alias datefmt_localtime */ diff --git a/ext/intl/dateformat/dateformat_arginfo.h b/ext/intl/dateformat/dateformat_arginfo.h index 2ec4da71d29e0..ccad07cd60a9d 100644 --- a/ext/intl/dateformat/dateformat_arginfo.h +++ b/ext/intl/dateformat/dateformat_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 767e5d064aef6d68f860a79c721eb728436c4eb9 */ + * Stub hash: 82f90e7b0528b2b3515c086763dba4de0f92dfa7 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_IntlDateFormatter___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1) diff --git a/ext/intl/locale/locale.stub.php b/ext/intl/locale/locale.stub.php index 144cdbc12e044..e5a4194a261ac 100644 --- a/ext/intl/locale/locale.stub.php +++ b/ext/intl/locale/locale.stub.php @@ -35,6 +35,7 @@ public static function getScript(string $locale): ?string {} public static function getRegion(string $locale): ?string {} /** + * @return array|false|null * @tentative-return-type * @alias locale_get_keywords */ diff --git a/ext/intl/locale/locale_arginfo.h b/ext/intl/locale/locale_arginfo.h index 57544eba306be..679a4ca9d9034 100644 --- a/ext/intl/locale/locale_arginfo.h +++ b/ext/intl/locale/locale_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a0c2cf74b0d2e8309f0cd39fd9969d14586d0988 */ + * Stub hash: 539e559bc038e18358540b3b3f4db7b09e532dae */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Locale_getDefault, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() diff --git a/ext/intl/msgformat/msgformat.stub.php b/ext/intl/msgformat/msgformat.stub.php index efa1164fd8f71..c85a9b92b3a32 100644 --- a/ext/intl/msgformat/msgformat.stub.php +++ b/ext/intl/msgformat/msgformat.stub.php @@ -25,12 +25,14 @@ public function format(array $values): string|false {} public static function formatMessage(string $locale, string $pattern, array $values): string|false {} /** + * @return array|false * @tentative-return-type * @alias msgfmt_parse */ public function parse(string $string): array|false {} /** + * @return array|false * @tentative-return-type * @alias msgfmt_parse_message */ diff --git a/ext/intl/msgformat/msgformat_arginfo.h b/ext/intl/msgformat/msgformat_arginfo.h index 90eeab215300c..8f0456f6cbb05 100644 --- a/ext/intl/msgformat/msgformat_arginfo.h +++ b/ext/intl/msgformat/msgformat_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3fc29ffe87caf85a84e97470d0b59a26c801457c */ + * Stub hash: 44bc7b87c0b6c674bf94764b3f036006e3933713 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MessageFormatter___construct, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 0) diff --git a/ext/intl/php_intl.stub.php b/ext/intl/php_intl.stub.php index ae8657eb61a5c..7ed23ee3946f2 100644 --- a/ext/intl/php_intl.stub.php +++ b/ext/intl/php_intl.stub.php @@ -15,6 +15,10 @@ function intlcal_get_keyword_values_for_locale(string $keyword, string $locale, function intlcal_get_now(): float {} +/** + * @return array + * @refcount 1 + */ function intlcal_get_available_locales(): array {} function intlcal_get(IntlCalendar $calendar, int $field): int|false {} @@ -206,7 +210,11 @@ function datefmt_format_object($datetime, $format = null, ?string $locale = null /** @param int $offset */ function datefmt_parse(IntlDateFormatter $formatter, string $string, &$offset = null): int|float|false {} -/** @param int $offset */ +/** + * @param int $offset + * @return array|false + * @refcount 1 + */ function datefmt_localtime(IntlDateFormatter $formatter, string $string, &$offset = null): array|false {} function datefmt_get_error_code(IntlDateFormatter $formatter): int {} @@ -294,6 +302,10 @@ function locale_get_script(string $locale): ?string {} function locale_get_region(string $locale): ?string {} +/** + * @return array|false|null + * @refcount 1 + */ function locale_get_keywords(string $locale): array|false|null {} function locale_get_display_script(string $locale, ?string $displayLocale = null): string|false {} @@ -328,8 +340,16 @@ function msgfmt_format(MessageFormatter $formatter, array $values): string|false function msgfmt_format_message(string $locale, string $pattern, array $values): string|false {} +/** + * @return array|false + * @refcount 1 + */ function msgfmt_parse(MessageFormatter $formatter, string $string): array|false {} +/** + * @return array|false + * @refcount 1 + */ function msgfmt_parse_message(string $locale, string $pattern, string $message): array|false {} function msgfmt_set_pattern(MessageFormatter $formatter, string $pattern): bool {} @@ -361,6 +381,10 @@ function resourcebundle_get(ResourceBundle $bundle, $index, bool $fallback = tru function resourcebundle_count(ResourceBundle $bundle): int {} +/** + * @return array|false + * @refcount 1 + */ function resourcebundle_locales(string $bundle): array|false {} function resourcebundle_get_error_code(ResourceBundle $bundle): int {} @@ -431,6 +455,10 @@ function transliterator_create(string $id, int $direction = Transliterator::FORW function transliterator_create_from_rules(string $rules, int $direction = Transliterator::FORWARD): ?Transliterator {} +/** + * @return array|false + * @refcount 1 + */ function transliterator_list_ids(): array|false {} function transliterator_create_inverse(Transliterator $transliterator): ?Transliterator {} diff --git a/ext/intl/php_intl_arginfo.h b/ext/intl/php_intl_arginfo.h index d3df7f8b31b78..443341941ac75 100644 --- a/ext/intl/php_intl_arginfo.h +++ b/ext/intl/php_intl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: dc9632b2417200deb39cc5cce25aa26a44128707 */ + * Stub hash: 09aa0aa66c78b86c0e6e0e554c3ebe205a0e5f59 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_intlcal_create_instance, 0, 0, IntlCalendar, 1) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, timezone, "null") diff --git a/ext/intl/resourcebundle/resourcebundle.stub.php b/ext/intl/resourcebundle/resourcebundle.stub.php index 79374e2951241..4247fca318a4e 100644 --- a/ext/intl/resourcebundle/resourcebundle.stub.php +++ b/ext/intl/resourcebundle/resourcebundle.stub.php @@ -26,6 +26,7 @@ public function get($index, bool $fallback = true): mixed {} public function count(): int {} /** + * @return array|false * @tentative-return-type * @alias resourcebundle_locales */ diff --git a/ext/intl/resourcebundle/resourcebundle_arginfo.h b/ext/intl/resourcebundle/resourcebundle_arginfo.h index 6d138768f3f72..0564b026dc39b 100644 --- a/ext/intl/resourcebundle/resourcebundle_arginfo.h +++ b/ext/intl/resourcebundle/resourcebundle_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a299d2a45a3575e6da71560979e2f9301b3c952f */ + * Stub hash: d27fa5a4dc092b94e48fc876070f440c247fa6c2 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ResourceBundle___construct, 0, 0, 2) ZEND_ARG_TYPE_INFO(0, locale, IS_STRING, 1) diff --git a/ext/intl/transliterator/transliterator.stub.php b/ext/intl/transliterator/transliterator.stub.php index 4ae7c3a645dd7..6d52263e0646f 100644 --- a/ext/intl/transliterator/transliterator.stub.php +++ b/ext/intl/transliterator/transliterator.stub.php @@ -27,6 +27,7 @@ public static function createFromRules(string $rules, int $direction = Translite public function createInverse(): ?Transliterator {} /** + * @return array|false * @tentative-return-type * @alias transliterator_list_ids */ diff --git a/ext/intl/transliterator/transliterator_arginfo.h b/ext/intl/transliterator/transliterator_arginfo.h index 76d10000b106f..c80be4f5b3460 100644 --- a/ext/intl/transliterator/transliterator_arginfo.h +++ b/ext/intl/transliterator/transliterator_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fbc9a196271c276e5af658115571cacde2ad3a3a */ + * Stub hash: 8a6aaab7dd89a014726bd1fdf1f40f7b6fa98ea5 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Transliterator___construct, 0, 0, 0) ZEND_END_ARG_INFO() diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index e06d3ca67250f..91e42c821ee58 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2286,11 +2286,15 @@ static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce, entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload); if (entry) { if (!needs_autoload) { + replay_warnings(entry->num_warnings, entry->warnings); if (ZCSG(map_ptr_last) > CG(map_ptr_last)) { zend_map_ptr_extend(ZCSG(map_ptr_last)); } - replay_warnings(entry->num_warnings, entry->warnings); - return entry->ce; + ce = entry->ce; + if (ZSTR_HAS_CE_CACHE(ce->name)) { + ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0); + } + return ce; } for (i = 0; i < entry->dependencies_count; i++) { @@ -2417,11 +2421,12 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, } entry->ce = new_ce = zend_persist_class_entry(ce); zend_update_parent_ce(new_ce); - entry->next = proto->inheritance_cache; - proto->inheritance_cache = entry; entry->num_warnings = EG(num_errors); entry->warnings = zend_persist_warnings(EG(num_errors), EG(errors)); + entry->next = proto->inheritance_cache; + proto->inheritance_cache = entry; + EG(num_errors) = 0; EG(errors) = NULL; diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index b3c143b3599fe..b6e8c91c460b4 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -830,11 +830,10 @@ static bool logical_immediate_p(uint64_t value, uint32_t reg_size) |.endmacro |.macro UNDEF_OPLINE_RESULT_IF_USED, tmp_reg1, tmp_reg2 -| ldr REG0, EX->opline -| ldrb tmp_reg1, OP:REG0->result_type +| ldrb tmp_reg1, OP:RX->result_type | TST_32_WITH_CONST tmp_reg1, (IS_TMP_VAR|IS_VAR), tmp_reg2 | beq >1 -| ldr REG0w, OP:REG0->result.var +| ldr REG0w, OP:RX->result.var | add REG0, FP, REG0 | SET_Z_TYPE_INFO REG0, IS_UNDEF, tmp_reg1 |1: @@ -1850,6 +1849,48 @@ static int zend_jit_exception_handler_undef_stub(dasm_State **Dst) return 1; } +static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst) +{ + zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); + + |->exception_handler_free_op1_op2: + | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w + | ldrb TMP1w, OP:RX->op1_type + | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w + | beq >9 + | ldr REG0w, OP:RX->op1.var + | add REG0, REG0, FP + | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 + |9: + | ldrb TMP1w, OP:RX->op2_type + | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w + | beq >9 + | ldr REG0w, OP:RX->op2.var + | add REG0, REG0, FP + | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 + |9: + | b ->exception_handler + return 1; +} + +static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst) +{ + zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); + + |->exception_handler_free_op2: + | MEM_LOAD_64_ZTS ldr, RX, executor_globals, opline_before_exception, REG0 + | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w + | ldrb TMP1w, OP:RX->op2_type + | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w + | beq >9 + | ldr REG0w, OP:RX->op2.var + | add REG0, REG0, FP + | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 + |9: + | b ->exception_handler + return 1; +} + static int zend_jit_leave_function_stub(dasm_State **Dst) { |->leave_function_handler: @@ -2121,57 +2162,23 @@ static int zend_jit_undefined_function_stub(dasm_State **Dst) static int zend_jit_negative_shift_stub(dasm_State **Dst) { - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - |->negative_shift: | ldr RX, EX->opline - | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w | LOAD_ADDR CARG1, zend_ce_arithmetic_error | LOAD_ADDR CARG2, "Bit shift by negative number" | EXT_CALL zend_throw_error, REG0 - | ldrb TMP1w, OP:RX->op1_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op1.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | ldrb TMP1w, OP:RX->op2_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op2.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | b ->exception_handler + | b ->exception_handler_free_op1_op2 return 1; } static int zend_jit_mod_by_zero_stub(dasm_State **Dst) { - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - |->mod_by_zero: | ldr RX, EX->opline - | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w | LOAD_ADDR CARG1, zend_ce_division_by_zero_error | LOAD_ADDR CARG2, "Modulo by zero" | EXT_CALL zend_throw_error, REG0 - | ldrb TMP1w, OP:RX->op1_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op1.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | ldrb TMP1w, OP:RX->op2_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op2.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | b ->exception_handler + | b ->exception_handler_free_op1_op2 return 1; } @@ -2701,6 +2708,8 @@ static const zend_jit_stub zend_jit_stubs[] = { JIT_STUB(interrupt_handler, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(exception_handler, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(exception_handler_undef, SP_ADJ_JIT, SP_ADJ_VM), + JIT_STUB(exception_handler_free_op1_op2, SP_ADJ_JIT, SP_ADJ_VM), + JIT_STUB(exception_handler_free_op2, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(leave_function, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(leave_throw, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(icall_throw, SP_ADJ_JIT, SP_ADJ_VM), @@ -4873,7 +4882,10 @@ static int zend_jit_long_math_helper(dasm_State **Dst, | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 if (may_throw) { - if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { + if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) { + | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1 + | cbnz TMP2, ->exception_handler_free_op2 + } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { zend_jit_check_exception_undef_result(Dst, opline); } else { zend_jit_check_exception(Dst); @@ -4939,6 +4951,8 @@ static int zend_jit_concat_helper(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2x, op2_addr | EXT_CALL zend_jit_fast_assign_concat_helper, REG0 + /* concatination with itself may reduce refcount */ + op2_info |= MAY_BE_RC1; } else { if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { | LOAD_ZVAL_ADDR FCARG1x, res_addr diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 4224d62d3259f..297cf30161b43 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1166,6 +1166,9 @@ static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op result_str = perealloc(Z_STR_P(op1), ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(result_len)), 0); ZSTR_LEN(result_str) = result_len; zend_string_forget_hash_val(result_str); + if (UNEXPECTED(Z_STR_P(op1) == Z_STR_P(op2))) { + ZVAL_NEW_STR(op2, result_str); + } break; } GC_DELREF(Z_STR_P(op1)); diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 987cdac5d1fcd..b082dd75a5719 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -541,10 +541,9 @@ static size_t tsrm_tls_offset; |.endmacro |.macro UNDEF_OPLINE_RESULT_IF_USED -| mov r0, EX->opline -| test byte OP:r0->result_type, (IS_TMP_VAR|IS_VAR) +| test byte OP:RX->result_type, (IS_TMP_VAR|IS_VAR) | jz >1 -| mov eax, dword OP:r0->result.var +| mov eax, dword OP:RX->result.var | SET_Z_TYPE_INFO FP + r0, IS_UNDEF |1: |.endmacro @@ -1788,6 +1787,42 @@ static int zend_jit_exception_handler_undef_stub(dasm_State **Dst) return 1; } + +static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst) +{ + |->exception_handler_free_op1_op2: + | UNDEF_OPLINE_RESULT_IF_USED + | test byte OP:RX->op1_type, (IS_TMP_VAR|IS_VAR) + | je >9 + | mov eax, dword OP:RX->op1.var + | add r0, FP + | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL + |9: + | test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR) + | je >9 + | mov eax, dword OP:RX->op2.var + | add r0, FP + | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL + |9: + | jmp ->exception_handler + return 1; +} + +static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst) +{ + |->exception_handler_free_op2: + | MEM_LOAD_ZTS RX, aword, executor_globals, opline_before_exception, r0 + | UNDEF_OPLINE_RESULT_IF_USED + | test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR) + | je >9 + | mov eax, dword OP:RX->op2.var + | add r0, FP + | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL + |9: + | jmp ->exception_handler + return 1; +} + static int zend_jit_leave_function_stub(dasm_State **Dst) { |->leave_function_handler: @@ -2102,7 +2137,6 @@ static int zend_jit_negative_shift_stub(dasm_State **Dst) { |->negative_shift: | mov RX, EX->opline - | UNDEF_OPLINE_RESULT_IF_USED |.if X64 |.if WIN | LOAD_ADDR CARG1, &zend_ce_arithmetic_error @@ -2124,19 +2158,7 @@ static int zend_jit_negative_shift_stub(dasm_State **Dst) | EXT_CALL zend_throw_error, r0 | add r4, 16 |.endif - | test byte OP:RX->op1_type, (IS_TMP_VAR|IS_VAR) - | je >9 - | mov eax, dword OP:RX->op1.var - | add r0, FP - | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL - |9: - | test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR) - | je >9 - | mov eax, dword OP:RX->op2.var - | add r0, FP - | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL - |9: - | jmp ->exception_handler + | jmp ->exception_handler_free_op1_op2 return 1; } @@ -2144,7 +2166,6 @@ static int zend_jit_mod_by_zero_stub(dasm_State **Dst) { |->mod_by_zero: | mov RX, EX->opline - | UNDEF_OPLINE_RESULT_IF_USED |.if X64 |.if WIN | LOAD_ADDR CARG1, &zend_ce_division_by_zero_error @@ -2166,19 +2187,7 @@ static int zend_jit_mod_by_zero_stub(dasm_State **Dst) | EXT_CALL zend_throw_error, r0 | add r4, 16 |.endif - | test byte OP:RX->op1_type, (IS_TMP_VAR|IS_VAR) - | je >9 - | mov eax, dword OP:RX->op1.var - | add r0, FP - | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL - |9: - | test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR) - | je >9 - | mov eax, dword OP:RX->op2.var - | add r0, FP - | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL - |9: - | jmp ->exception_handler + | jmp ->exception_handler_free_op1_op2 return 1; } @@ -2788,6 +2797,8 @@ static const zend_jit_stub zend_jit_stubs[] = { JIT_STUB(interrupt_handler, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(exception_handler, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(exception_handler_undef, SP_ADJ_JIT, SP_ADJ_VM), + JIT_STUB(exception_handler_free_op1_op2, SP_ADJ_JIT, SP_ADJ_VM), + JIT_STUB(exception_handler_free_op2, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(leave_function, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(leave_throw, SP_ADJ_JIT, SP_ADJ_VM), JIT_STUB(icall_throw, SP_ADJ_JIT, SP_ADJ_VM), @@ -2950,7 +2961,7 @@ static int zend_jit_setup(void) # elif defined(__GNUC__) && defined(__x86_64__) tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset(); if (tsrm_ls_cache_tcb_offset == 0) { -#if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) +#if defined(__has_attribute) && __has_attribute(tls_model) && !defined(__FreeBSD__) && !defined(__OpenBSD__) size_t ret; asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0" @@ -2969,7 +2980,7 @@ static int zend_jit_setup(void) # elif defined(__GNUC__) && defined(__i386__) tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset(); if (tsrm_ls_cache_tcb_offset == 0) { -#if !defined(__FreeBSD__) +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) size_t ret; asm ("leal _tsrm_ls_cache@ntpoff,%0\n" @@ -5316,7 +5327,10 @@ static int zend_jit_long_math_helper(dasm_State **Dst, | FREE_OP op1_type, op1, op1_info, 0, NULL | FREE_OP op2_type, op2, op2_info, 0, NULL if (may_throw) { - if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { + if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) { + | MEM_CMP_ZTS aword, executor_globals, exception, 0, r0 + | jne ->exception_handler_free_op2 + } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { zend_jit_check_exception_undef_result(Dst, opline); } else { zend_jit_check_exception(Dst); @@ -5383,6 +5397,8 @@ static int zend_jit_concat_helper(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2a, op2_addr | EXT_CALL zend_jit_fast_assign_concat_helper, r0 + /* concatination with itself may reduce refcount */ + op2_info |= MAY_BE_RC1; } else { if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { | LOAD_ZVAL_ADDR FCARG1a, res_addr diff --git a/ext/opcache/tests/bug81607.inc b/ext/opcache/tests/bug81607.inc new file mode 100644 index 0000000000000..a50dceebf6ffa --- /dev/null +++ b/ext/opcache/tests/bug81607.inc @@ -0,0 +1,2 @@ + 0) { + pcntl_wait($status); + var_dump(new FooBar); +} else { + echo "pcntl_fork() failed\n"; +} + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Class "FooBar" not found in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/assign_op_006.phpt b/ext/opcache/tests/jit/assign_op_006.phpt new file mode 100644 index 0000000000000..8d4caa97094e5 --- /dev/null +++ b/ext/opcache/tests/jit/assign_op_006.phpt @@ -0,0 +1,19 @@ +--TEST-- +JIT ASSIGN_OP: 006 concationation with itself +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/ext/opcache/tests/jit/mod_004.phpt b/ext/opcache/tests/jit/mod_004.phpt new file mode 100644 index 0000000000000..a80a487a9799c --- /dev/null +++ b/ext/opcache/tests/jit/mod_004.phpt @@ -0,0 +1,21 @@ +--TEST-- +JIT MOD: 004 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +--FILE-- + +--EXPECTF-- +Warning: Undefined array key "xy" in %smod_004.php on line 4 + +Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %smod_004.php:4 +Stack trace: +#0 {main} + thrown in %smod_004.php on line 4 \ No newline at end of file diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 002ea3e5d22b5..28b458235c4e0 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -220,7 +220,7 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source) if ((ce->ce_flags & ZEND_ACC_LINKED) && ZSTR_HAS_CE_CACHE(ce->name) && ZSTR_VAL(p->key)[0]) { - ZSTR_SET_CE_CACHE(ce->name, ce); + ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0); } } } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 0523f052ebd13..c438e6b38b81c 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -889,7 +889,7 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce) if (!(ce->ce_flags & ZEND_ACC_CACHED)) { if (ZSTR_HAS_CE_CACHE(ce->name)) { - ZSTR_SET_CE_CACHE(ce->name, NULL); + ZSTR_SET_CE_CACHE_EX(ce->name, NULL, 0); } zend_accel_store_interned_string(ce->name); if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS) diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index a7c5dbb3d8b76..d8ed75f5b764e 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -1207,7 +1207,7 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str, if (subpats != NULL) { subpats = zend_try_array_init(subpats); if (!subpats) { - return; + RETURN_THROWS(); } } diff --git a/ext/pcre/php_pcre.stub.php b/ext/pcre/php_pcre.stub.php index 52d82bd223d06..498219b3c41e5 100644 --- a/ext/pcre/php_pcre.stub.php +++ b/ext/pcre/php_pcre.stub.php @@ -6,7 +6,7 @@ function preg_match(string $pattern, string $subject, &$matches = null, int $flags = 0, int $offset = 0): int|false {} /** @param array $matches */ -function preg_match_all(string $pattern, string $subject, &$matches = null, int $flags = 0, int $offset = 0): int|false|null {} +function preg_match_all(string $pattern, string $subject, &$matches = null, int $flags = 0, int $offset = 0): int|false {} /** * @param int $count diff --git a/ext/pcre/php_pcre_arginfo.h b/ext/pcre/php_pcre_arginfo.h index 68ac761750250..96c8331c0d611 100644 --- a/ext/pcre/php_pcre_arginfo.h +++ b/ext/pcre/php_pcre_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 62ab532c890b5421bfe8b784c803829cf71a1423 */ + * Stub hash: bc6f31ac17d4f5d1a60dd3dad5f671058f40a224 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_match, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) @@ -9,13 +9,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_match, 0, 2, MAY_BE_LONG|MA ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_match_all, 0, 2, MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_NULL) - ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, subject, IS_STRING, 0) - ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, matches, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, offset, IS_LONG, 0, "0") -ZEND_END_ARG_INFO() +#define arginfo_preg_match_all arginfo_preg_match ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_replace, 0, 3, MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_NULL) ZEND_ARG_TYPE_MASK(0, pattern, MAY_BE_STRING|MAY_BE_ARRAY, NULL) diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 479959db42bb0..34d6d2043a6fa 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -419,6 +419,10 @@ PHP_METHOD(PDO, __construct) } /* the connection failed; things will tidy up in free_storage */ + if (is_persistent) { + dbh->refcount--; + } + /* XXX raise exception */ zend_restore_error_handling(&zeh); if (!EG(exception)) { diff --git a/ext/pdo_mysql/tests/construct_persistent_failure.phpt b/ext/pdo_mysql/tests/construct_persistent_failure.phpt new file mode 100644 index 0000000000000..65c3b65329eed --- /dev/null +++ b/ext/pdo_mysql/tests/construct_persistent_failure.phpt @@ -0,0 +1,16 @@ +--TEST-- +Failure when creating persistent connection +--EXTENSIONS-- +pdo_mysql +--FILE-- + true, + ]); +} catch (PDOException $e) { + echo "Caught\n"; +} +?> +--EXPECT-- +Caught diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 820520c0aedd1..64cdc053f7638 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5116,18 +5116,15 @@ ZEND_METHOD(ReflectionClass, getTraitAliases) if (!class_name) { uint32_t j = 0; - zval *zv; - zend_class_entry *trait; zend_string *lcname = zend_string_tolower(cur_ref->method_name); for (j = 0; j < ce->num_traits; j++) { - zv = zend_hash_find_known_hash(CG(class_table), ce->trait_names[j].lc_name); - if (zv) { - trait = Z_CE_P(zv); - if (zend_hash_exists(&trait->function_table, lcname)) { - class_name = trait->name; - break; - } + zend_class_entry *trait = + zend_hash_find_ptr(CG(class_table), ce->trait_names[j].lc_name); + ZEND_ASSERT(trait && "Trait must exist"); + if (zend_hash_exists(&trait->function_table, lcname)) { + class_name = trait->name; + break; } } zend_string_release_ex(lcname, 0); diff --git a/ext/reflection/tests/bug81611.phpt b/ext/reflection/tests/bug81611.phpt new file mode 100644 index 0000000000000..94bebf359cbef --- /dev/null +++ b/ext/reflection/tests/bug81611.phpt @@ -0,0 +1,64 @@ +--TEST-- +Reflection Bug #81611 (ArgumentCountError when getting default value from ReflectionParameter with new) +--FILE-- +getMethod($method)->getParameters(); + + foreach ($params as $param) { + echo "isDefaultValueAvailable:\n"; + var_dump($param->isDefaultValueAvailable()); + + echo "isDefaultValueConstant:\n"; + var_dump($param->isDefaultValueConstant()); + + echo "getDefaultValueConstantName:\n"; + var_dump($param->getDefaultValueConstantName()); + + echo "getDefaultValue:\n"; + var_dump($param->getDefaultValue()); + + echo "\n"; + } +} +?> +--EXPECT-- +isDefaultValueAvailable: +bool(true) +isDefaultValueConstant: +bool(false) +getDefaultValueConstantName: +NULL +getDefaultValue: +object(Foo)#2 (0) { +} + +isDefaultValueAvailable: +bool(true) +isDefaultValueConstant: +bool(false) +getDefaultValueConstantName: +NULL +getDefaultValue: +object(Bar)#3 (0) { +} diff --git a/ext/standard/array.c b/ext/standard/array.c index 8137bfcbd8d79..f438c474e7ece 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -939,8 +939,10 @@ static void php_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compar zend_hash_sort(arr, compare_func, renumber); - zval_ptr_dtor(array); + zval garbage; + ZVAL_COPY_VALUE(&garbage, array); ZVAL_ARR(array, arr); + zval_ptr_dtor(&garbage); PHP_ARRAY_CMP_FUNC_RESTORE(); RETURN_TRUE; diff --git a/sapi/cli/tests/006.phpt b/sapi/cli/tests/006.phpt index 907b60330ea92..4f33e37c71089 100644 --- a/sapi/cli/tests/006.phpt +++ b/sapi/cli/tests/006.phpt @@ -85,7 +85,7 @@ string(%d) "Extension [ extension #%d pcre version %s ] { Parameter #3 [ int $flags = 0 ] Parameter #4 [ int $offset = 0 ] } - - Return [ int|false|null ] + - Return [ int|false ] } Function [ function preg_replace ] { diff --git a/sapi/fpm/tests/proc-idle-timeout.phpt b/sapi/fpm/tests/proc-idle-timeout.phpt index a6d3395c14a84..9f6d4377b8ce4 100644 --- a/sapi/fpm/tests/proc-idle-timeout.phpt +++ b/sapi/fpm/tests/proc-idle-timeout.phpt @@ -4,7 +4,6 @@ FPM: Process manager config pm.process_idle_timeout --FILE-- start(); $tester->expectLogStartNotices(); -$tester->multiRequest(2); +$tester->multiRequest(2, null, null, null, false, 7000); $tester->status([ 'total processes' => 2, ]); // wait for process idle timeout -sleep(6); +sleep(5); $tester->status([ 'total processes' => 1, ]); diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index 3d169f052c5d5..cd043072ba031 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -624,6 +624,7 @@ class Tester * @param string|null $successMessage * @param string|null $errorMessage * @param bool $connKeepAlive + * @param int $readTimeout * @return Response[] * @throws \Exception */ @@ -632,7 +633,8 @@ class Tester string $address = null, string $successMessage = null, string $errorMessage = null, - bool $connKeepAlive = false + bool $connKeepAlive = false, + int $readTimeout = 0 ) { if ($this->hasError()) { return new Response(null, true); @@ -658,8 +660,8 @@ class Tester ]; }, $requests); - $responses = array_map(function ($conn) { - $response = new Response($conn['client']->wait_for_response_data($conn['requestId'])); + $responses = array_map(function ($conn) use ($readTimeout) { + $response = new Response($conn['client']->wait_for_response_data($conn['requestId'], $readTimeout)); if ($this->debug) { $response->debugOutput(); }