From 4467f33e89b1f9c9eb402dce164c74949e80ccd2 Mon Sep 17 00:00:00 2001 From: Pierrick Charron Date: Tue, 15 Aug 2023 16:08:52 -0400 Subject: [PATCH 01/38] PHP-8.2 is now for PHP 8.2.11-dev --- NEWS | 4 +++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 8d8884ef7757b..a961fde049189 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.10 +?? ??? ????, PHP 8.2.11 + +31 Aug 2023, PHP 8.2.10 - CLI: . Fixed bug GH-11716 (cli server crashes on SIGINT when compiled with diff --git a/Zend/zend.h b/Zend/zend.h index c7ef9d12fc2c7..eb2105abfa57d 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.10-dev" +#define ZEND_VERSION "4.2.11-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 23827974270d6..b7721b2fb6003 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.2.10-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.11-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index 7e4f058576ce5..afeeec17ccc3e 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 2 -#define PHP_RELEASE_VERSION 10 +#define PHP_RELEASE_VERSION 11 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.10-dev" -#define PHP_VERSION_ID 80210 +#define PHP_VERSION "8.2.11-dev" +#define PHP_VERSION_ID 80211 From c1103a97725060e3fa1418d83e25875aa4a0f400 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Fri, 24 Mar 2023 13:52:20 +0000 Subject: [PATCH 02/38] Fix implicit/explicit port in mysqlnd --- NEWS | 4 +++- ext/mysqli/tests/gh8978.phpt | 29 +++++++++++++++++++++++++++++ ext/mysqlnd/mysqlnd_commands.c | 2 ++ ext/mysqlnd/mysqlnd_connection.c | 17 +++++++++-------- ext/mysqlnd/mysqlnd_vio.c | 1 - 5 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 ext/mysqli/tests/gh8978.phpt diff --git a/NEWS b/NEWS index 58a89b81cc318..0d2bd565067b8 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.1.24 - +- MySQLnd: + . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: + "trying to connect via (null)"). (Kamil Tekiela) 31 Aug 2023, PHP 8.1.23 diff --git a/ext/mysqli/tests/gh8978.phpt b/ext/mysqli/tests/gh8978.phpt new file mode 100644 index 0000000000000..394c07ee954ff --- /dev/null +++ b/ext/mysqli/tests/gh8978.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug GH-8267 (Invalid error message when connection via SSL fails) +--EXTENSIONS-- +mysqli +--SKIPIF-- + +--FILE-- +getMessage()."\n"; +} + +echo 'done!'; +?> +--EXPECTF-- +Warning: failed loading cafile stream: `x509.ca' in %s +Cannot connect to MySQL using SSL +done! diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index 40821bb1efedd..ae64560850531 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -571,6 +571,8 @@ MYSQLND_METHOD(mysqlnd_command, enable_ssl)(MYSQLND_CONN_DATA * const conn, cons conn->vio->data->m.set_client_option(conn->vio, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify); if (FAIL == conn->vio->data->m.enable_ssl(conn->vio)) { + SET_CONNECTION_STATE(&conn->state, CONN_QUIT_SENT); + SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Cannot connect to MySQL using SSL"); goto end; } } diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 4f720cdb15495..c905e38c8573d 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -289,7 +289,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn) mysqlnd_set_persistent_string(&conn->unix_socket, NULL, 0, pers); DBG_INF_FMT("scheme=%s", conn->scheme.s); mysqlnd_set_persistent_string(&conn->scheme, NULL, 0, pers); - + if (conn->server_version) { mnd_pefree(conn->server_version, pers); conn->server_version = NULL; @@ -726,19 +726,20 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, DBG_RETURN(PASS); } err: - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } - - DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); + DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, transport.s ? transport.s : conn->scheme.s); if (!conn->error_info->error_no) { + /* There was an unknown error if the connection failed but we have no error number */ char * msg; - mnd_sprintf(&msg, 0, "%s (trying to connect via %s)",conn->error_info->error, conn->scheme.s); + mnd_sprintf(&msg, 0, "Unknown error while trying to connect via %s", transport.s ? transport.s : conn->scheme.s); SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, msg); mnd_sprintf_free(msg); } + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } + conn->m->free_contents(conn); MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE); DBG_RETURN(FAIL); diff --git a/ext/mysqlnd/mysqlnd_vio.c b/ext/mysqlnd/mysqlnd_vio.c index 2bd77906a1b9a..cd9c714f23bb9 100644 --- a/ext/mysqlnd/mysqlnd_vio.c +++ b/ext/mysqlnd/mysqlnd_vio.c @@ -569,7 +569,6 @@ MYSQLND_METHOD(mysqlnd_vio, enable_ssl)(MYSQLND_VIO * const net) php_stream_xport_crypto_enable(net_stream, 1) < 0) { DBG_ERR("Cannot connect to MySQL by using SSL"); - php_error_docref(NULL, E_WARNING, "Cannot connect to MySQL by using SSL"); DBG_RETURN(FAIL); } net->data->ssl = TRUE; From f78d1d0d10284b3599a099b783b56f16b338f728 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 12 Aug 2023 16:11:29 +0200 Subject: [PATCH 03/38] Fix segfault in format_default_value due to unexpected enum/object Evaluating constants at comptime can result in arrays that contain objects. This is problematic for printing the default value of constant ASTs containing objects, because we don't actually know what the constructor arguments were. Avoid this by not propagating array constants. Fixes GH-11937 Closes GH-11947 --- NEWS | 3 +++ Zend/zend_compile.c | 40 +++++++++++++++++++++++++++-- ext/reflection/php_reflection.c | 1 + ext/reflection/tests/gh11937_1.inc | 13 ++++++++++ ext/reflection/tests/gh11937_1.phpt | 30 ++++++++++++++++++++++ ext/reflection/tests/gh11937_2.inc | 4 +++ ext/reflection/tests/gh11937_2.phpt | 27 +++++++++++++++++++ 7 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 ext/reflection/tests/gh11937_1.inc create mode 100644 ext/reflection/tests/gh11937_1.phpt create mode 100644 ext/reflection/tests/gh11937_2.inc create mode 100644 ext/reflection/tests/gh11937_2.phpt diff --git a/NEWS b/NEWS index 0d2bd565067b8..010acdaf17c63 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.1.24 +- Core: + . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) + - MySQLnd: . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: "trying to connect via (null)"). (Kamil Tekiela) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index af9be18d10f5b..351c2708bf409 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1458,6 +1458,35 @@ ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, con } /* }}} */ +static bool array_is_const_ex(zend_array *array, uint32_t *max_checks) +{ + if (zend_hash_num_elements(array) > *max_checks) { + return false; + } + *max_checks -= zend_hash_num_elements(array); + + zval *element; + ZEND_HASH_FOREACH_VAL(array, element) { + if (Z_TYPE_P(element) < IS_ARRAY) { + continue; + } else if (Z_TYPE_P(element) == IS_ARRAY) { + if (!array_is_const_ex(array, max_checks)) { + return false; + } + } else if (UNEXPECTED(Z_TYPE_P(element) >=IS_OBJECT)) { + return false; + } + } ZEND_HASH_FOREACH_END(); + + return true; +} + +static bool array_is_const(zend_array *array) +{ + uint32_t max_checks = 50; + return array_is_const_ex(array, &max_checks); +} + static bool can_ct_eval_const(zend_constant *c) { if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { return 0; @@ -1468,9 +1497,13 @@ static bool can_ct_eval_const(zend_constant *c) { && (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) { return 1; } - if (Z_TYPE(c->value) < IS_OBJECT + if (Z_TYPE(c->value) < IS_ARRAY && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { return 1; + } else if (Z_TYPE(c->value) == IS_ARRAY + && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) + && array_is_const(Z_ARR(c->value))) { + return 1; } return 0; } @@ -1690,7 +1723,10 @@ static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend c = &cc->value; /* Substitute case-sensitive (or lowercase) persistent class constants */ - if (Z_TYPE_P(c) < IS_OBJECT) { + if (Z_TYPE_P(c) < IS_ARRAY) { + ZVAL_COPY_OR_DUP(zv, c); + return 1; + } else if (Z_TYPE_P(c) == IS_ARRAY && array_is_const(Z_ARR_P(c))) { ZVAL_COPY_OR_DUP(zv, c); return 1; } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index d3d5914866a1e..876338f4ab127 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -639,6 +639,7 @@ static int format_default_value(smart_str *str, zval *value) { } ZEND_HASH_FOREACH_END(); smart_str_appendc(str, ']'); } else if (Z_TYPE_P(value) == IS_OBJECT) { + /* This branch may only be reached for default properties, which don't support arbitrary objects. */ zend_object *obj = Z_OBJ_P(value); zend_class_entry *class = obj->ce; ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM); diff --git a/ext/reflection/tests/gh11937_1.inc b/ext/reflection/tests/gh11937_1.inc new file mode 100644 index 0000000000000..4d55213f2f831 --- /dev/null +++ b/ext/reflection/tests/gh11937_1.inc @@ -0,0 +1,13 @@ +getAttributes('Attr')[0]; + +?> +--EXPECT-- +array(2) { + [0]=> + enum(TestEnum::One) + [1]=> + enum(TestEnum::Two) +} +Attribute [ Attr ] { + - Arguments [1] { + Argument #0 [ new \Foo(TestEnum::CASES) ] + } +} diff --git a/ext/reflection/tests/gh11937_2.inc b/ext/reflection/tests/gh11937_2.inc new file mode 100644 index 0000000000000..d6e21e6ba5c55 --- /dev/null +++ b/ext/reflection/tests/gh11937_2.inc @@ -0,0 +1,4 @@ +getAttributes('Attr')[0]; + +?> +--EXPECT-- +array(1) { + [0]=> + object(Foo)#1 (0) { + } +} +Attribute [ Attr ] { + - Arguments [1] { + Argument #0 [ FOOS ] + } +} From dd01c74a6fd7813fc41c658005447f9e2fc9e586 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 17 Aug 2023 18:54:30 +0200 Subject: [PATCH 04/38] Remove redundant condition Never refactor code just before pushing --- Zend/zend_compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 351c2708bf409..75127b8b8d18a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1473,7 +1473,7 @@ static bool array_is_const_ex(zend_array *array, uint32_t *max_checks) if (!array_is_const_ex(array, max_checks)) { return false; } - } else if (UNEXPECTED(Z_TYPE_P(element) >=IS_OBJECT)) { + } else { return false; } } ZEND_HASH_FOREACH_END(); From ffd398b4feed1069ffd3dd0d0ceeeafd5d76994b Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Thu, 17 Aug 2023 18:45:10 +0100 Subject: [PATCH 05/38] Fix failing test on nightly --- ext/mysqli/tests/gh8978.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysqli/tests/gh8978.phpt b/ext/mysqli/tests/gh8978.phpt index 394c07ee954ff..92de63b381ca8 100644 --- a/ext/mysqli/tests/gh8978.phpt +++ b/ext/mysqli/tests/gh8978.phpt @@ -16,7 +16,7 @@ $mysql = mysqli_init(); mysqli_ssl_set($mysql, 'x509.key', 'x509.pem', 'x509.ca', null, null); try { // There should be no warning here, only exception - mysqli_real_connect($mysql, '127.0.0.1:3306', 'username', 'password', null, null, null, MYSQLI_CLIENT_SSL); + mysqli_real_connect($mysql, $host, $user, $passwd, null, $port, null, MYSQLI_CLIENT_SSL); } catch (mysqli_sql_exception $e) { echo $e->getMessage()."\n"; } From 85661a35f01604d8180eb20370803ce039c4c5a7 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 30 Jul 2023 14:58:46 +0200 Subject: [PATCH 06/38] Remove `mysqli.reconnect` from php.ini files (#11836) The `mysqli.reconnect` ini directive was removed in PHP 8.2.0. --- php.ini-development | 3 --- php.ini-production | 3 --- 2 files changed, 6 deletions(-) diff --git a/php.ini-development b/php.ini-development index 62320e36e066d..61cd33e89504c 100644 --- a/php.ini-development +++ b/php.ini-development @@ -1201,9 +1201,6 @@ mysqli.default_user = ; https://php.net/mysqli.default-pw mysqli.default_pw = -; Allow or prevent reconnect -mysqli.reconnect = Off - ; If this option is enabled, closing a persistent connection will rollback ; any pending transactions of this connection, before it is put back ; into the persistent connection pool. diff --git a/php.ini-production b/php.ini-production index cb36654a72672..2189660c02c48 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1203,9 +1203,6 @@ mysqli.default_user = ; https://php.net/mysqli.default-pw mysqli.default_pw = -; Allow or prevent reconnect -mysqli.reconnect = Off - ; If this option is enabled, closing a persistent connection will rollback ; any pending transactions of this connection, before it is put back ; into the persistent connection pool. From fc8d5c72e5e62a9486981960d4a94b39789044c4 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 19 Aug 2023 19:20:01 +0100 Subject: [PATCH 07/38] ext/iconv: fix build for netbsd. NetBSD still adopts the old iconv signature for buffer inputs. The next release will too so we can assume it will remain that way for a while. Close GH-12001 --- NEWS | 4 ++++ ext/iconv/iconv.c | 26 +++++++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 010acdaf17c63..d3e73e95c9752 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Core: . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) +- Iconv: + . Fixed build for NetBSD which still uses the old iconv signature. + (David Carlier) + - MySQLnd: . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: "trying to connect via (null)"). (Kamil Tekiela) diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index f05e58aa1d953..83d89a0df4835 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -44,6 +44,14 @@ #undef iconv #endif +#if defined(__NetBSD__) +// unfortunately, netbsd has still the old non posix conformant signature +// libiconv tends to match the eventual system's iconv too. +#define ICONV_CONST const +#else +#define ICONV_CONST +#endif + #include "zend_smart_str.h" #include "ext/standard/base64.h" #include "ext/standard/quot_print.h" @@ -360,7 +368,7 @@ static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, out_p = ZSTR_VAL((d)->s) + ZSTR_LEN((d)->s); - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: return PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -456,7 +464,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, out_p = ZSTR_VAL(out_buf); while (in_left > 0) { - result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left); + result = iconv(cd, (ICONV_CONST char **) &in_p, &in_left, (char **) &out_p, &out_left); out_size = bsz - out_left; if (result == (size_t)(-1)) { if (ignore_ilseq && errno == EILSEQ) { @@ -576,7 +584,7 @@ static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_ more = in_left > 0; - iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } else { @@ -683,7 +691,7 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval, more = in_left > 0 && len > 0; - iconv(cd1, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv(cd1, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -805,7 +813,7 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval, more = in_left > 0; - iconv_ret = iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv_ret = iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -1012,7 +1020,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn out_left = out_size - out_reserved; - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: err = PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -1096,7 +1104,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn out_p = buf; out_left = out_size; - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: err = PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -2373,7 +2381,7 @@ static int php_iconv_stream_filter_append_bucket( tcnt = self->stub_len; while (tcnt > 0) { - if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) { + if (iconv(self->cd, (ICONV_CONST char **)&pt, &tcnt, &pd, &ocnt) == (size_t)-1) { switch (errno) { case EILSEQ: php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); @@ -2439,7 +2447,7 @@ static int php_iconv_stream_filter_append_bucket( while (icnt > 0) { if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt): - iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { + iconv(self->cd, (ICONV_CONST char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { switch (errno) { case EILSEQ: php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); From 20ac42e1b065e23376e7ea548995636369809a7d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 19 Aug 2023 23:54:53 +0200 Subject: [PATCH 08/38] Fix memory leak when setting an invalid DOMDocument encoding Because the failure path did not release the string, there was a memory leak. As the only valid types for this function are IS_NULL and IS_STRING, we and IS_NULL is always rejected in practice, solve the issue by not using a function that increments the refcount in the first place. Closes GH-12002. --- NEWS | 3 +++ ext/dom/document.c | 19 ++++++++++++------- ext/dom/tests/gh12002.phpt | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 ext/dom/tests/gh12002.phpt diff --git a/NEWS b/NEWS index d3e73e95c9752..a4d3499a58315 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,9 @@ PHP NEWS - Core: . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) +- DOM: + . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) + - Iconv: . Fixed build for NetBSD which still uses the old iconv signature. (David Carlier) diff --git a/ext/dom/document.c b/ext/dom/document.c index ea6daafeb30fb..64da4f051be2c 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -139,7 +139,6 @@ int dom_document_encoding_read(dom_object *obj, zval *retval) zend_result dom_document_encoding_write(dom_object *obj, zval *newval) { xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj); - zend_string *str; xmlCharEncodingHandlerPtr handler; if (docp == NULL) { @@ -147,11 +146,15 @@ zend_result dom_document_encoding_write(dom_object *obj, zval *newval) return FAILURE; } - str = zval_try_get_string(newval); - if (UNEXPECTED(!str)) { - return FAILURE; + /* Typed property, can only be IS_STRING or IS_NULL. */ + ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING || Z_TYPE_P(newval) == IS_NULL); + + if (Z_TYPE_P(newval) == IS_NULL) { + goto invalid_encoding; } + zend_string *str = Z_STR_P(newval); + handler = xmlFindCharEncodingHandler(ZSTR_VAL(str)); if (handler != NULL) { @@ -161,12 +164,14 @@ zend_result dom_document_encoding_write(dom_object *obj, zval *newval) } docp->encoding = xmlStrdup((const xmlChar *) ZSTR_VAL(str)); } else { - zend_value_error("Invalid document encoding"); - return FAILURE; + goto invalid_encoding; } - zend_string_release_ex(str, 0); return SUCCESS; + +invalid_encoding: + zend_value_error("Invalid document encoding"); + return FAILURE; } /* }}} */ diff --git a/ext/dom/tests/gh12002.phpt b/ext/dom/tests/gh12002.phpt new file mode 100644 index 0000000000000..7d1ae944646ae --- /dev/null +++ b/ext/dom/tests/gh12002.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-12002 (DOMDocument::encoding memory leak with invalid encoding) +--EXTENSIONS-- +dom +--FILE-- +encoding = make_nonconst('utf-8'); +var_dump($dom->encoding); +try { + $dom->encoding = make_nonconst('foobar'); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->encoding); +$dom->encoding = make_nonconst('utf-16le'); +var_dump($dom->encoding); +try { + $dom->encoding = NULL; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->encoding); + +?> +--EXPECT-- +string(5) "utf-8" +Invalid document encoding +string(5) "utf-8" +string(8) "utf-16le" +Invalid document encoding +string(8) "utf-16le" From ba07a0b8461f7c5c46eb61c0c543a6f688d830f5 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 23 Aug 2023 10:56:12 +0200 Subject: [PATCH 09/38] Move installation of oracle instant client in GHA Closes GH-12033 --- .github/actions/apt-x64/action.yml | 12 ------------ .github/actions/install-linux-x32/action.yml | 2 +- .github/actions/install-linux/action.yml | 4 +--- .github/actions/setup-oracle/action.yml | 17 +++++++++++++++++ .github/workflows/nightly.yml | 2 +- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/.github/actions/apt-x64/action.yml b/.github/actions/apt-x64/action.yml index 621b18532e05f..4e1a03dd58cc5 100644 --- a/.github/actions/apt-x64/action.yml +++ b/.github/actions/apt-x64/action.yml @@ -59,15 +59,3 @@ runs: libjpeg-dev \ libpng-dev \ libfreetype6-dev - - mkdir /opt/oracle - wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip - unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip - wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip - unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip - mv instantclient_*_* /opt/oracle/instantclient - # interferes with libldap2 headers - rm /opt/oracle/instantclient/sdk/include/ldap.h - # fix debug build warning: zend_signal: handler was replaced for signal (2) after startup - echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora - sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig' diff --git a/.github/actions/install-linux-x32/action.yml b/.github/actions/install-linux-x32/action.yml index bf5f09cd779d4..4ef87ee03fd3f 100644 --- a/.github/actions/install-linux-x32/action.yml +++ b/.github/actions/install-linux-x32/action.yml @@ -6,7 +6,7 @@ runs: run: | set -x make install - mkdir /etc/php.d + mkdir -p /etc/php.d chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini diff --git a/.github/actions/install-linux/action.yml b/.github/actions/install-linux/action.yml index 7ac2ae4c4fcb1..576357b94f1c5 100644 --- a/.github/actions/install-linux/action.yml +++ b/.github/actions/install-linux/action.yml @@ -6,9 +6,7 @@ runs: run: | set -x sudo make install - sudo mkdir /etc/php.d + sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini - echo extension=oci8.so > /etc/php.d/oci8.ini - echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini diff --git a/.github/actions/setup-oracle/action.yml b/.github/actions/setup-oracle/action.yml index 11c16fe93d525..1208e93a24893 100644 --- a/.github/actions/setup-oracle/action.yml +++ b/.github/actions/setup-oracle/action.yml @@ -11,3 +11,20 @@ runs: --name oracle \ -h oracle \ -d gvenzl/oracle-xe:slim + + mkdir /opt/oracle + wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip + unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip + wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip + unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip + mv instantclient_*_* /opt/oracle/instantclient + # interferes with libldap2 headers + rm /opt/oracle/instantclient/sdk/include/ldap.h + # fix debug build warning: zend_signal: handler was replaced for signal (2) after startup + echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora + sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig' + + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo extension=oci8.so > /etc/php.d/oci8.ini + echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3e8ce86f9dda9..1ff8b6847a4a0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -555,7 +555,7 @@ jobs: - name: make install run: | sudo make install - sudo mkdir /etc/php.d + sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini From b1ce1d1f21b9e5395ce8d0c7f8b8d8200b837ced Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Thu, 24 Aug 2023 21:05:26 +0100 Subject: [PATCH 10/38] Fix param name in implode() error message --- ext/standard/string.c | 2 +- ext/standard/tests/strings/implode1.phpt | 6 +++--- ext/standard/tests/strings/join_error.phpt | 2 +- ext/standard/tests/strings/join_variation2.phpt | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/standard/string.c b/ext/standard/string.c index 623ce7d365bff..da1a97f49dac7 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1238,7 +1238,7 @@ PHP_FUNCTION(implode) if (pieces == NULL) { if (arg1_array == NULL) { - zend_type_error("%s(): Argument #1 ($pieces) must be of type array, string given", get_active_function_name()); + zend_type_error("%s(): Argument #1 ($array) must be of type array, string given", get_active_function_name()); RETURN_THROWS(); } diff --git a/ext/standard/tests/strings/implode1.phpt b/ext/standard/tests/strings/implode1.phpt index 7092efe94248b..d467a37dd3175 100644 --- a/ext/standard/tests/strings/implode1.phpt +++ b/ext/standard/tests/strings/implode1.phpt @@ -236,7 +236,7 @@ string(35) "2000-639010PHP000 0string%0with%0...%0" string(43) "2\00\0-639\01\0PHP\0\0\0 \0string%0with%0...%0" *** Testing implode() on empty string *** -implode(): Argument #1 ($pieces) must be of type array, string given +implode(): Argument #1 ($array) must be of type array, string given *** Testing implode() on sub-arrays *** @@ -266,9 +266,9 @@ array(2) { string(%d) "Resource id #%d::Resource id #%d" *** Testing error conditions *** -implode(): Argument #1 ($pieces) must be of type array, string given +implode(): Argument #1 ($array) must be of type array, string given implode(): Argument #2 ($array) must be of type ?array, int given -implode(): Argument #1 ($pieces) must be of type array, string given +implode(): Argument #1 ($array) must be of type array, string given string(0) "" implode(): Argument #2 ($array) must be of type ?array, string given diff --git a/ext/standard/tests/strings/join_error.phpt b/ext/standard/tests/strings/join_error.phpt index f52c4c1184d6f..c3cee28812d30 100644 --- a/ext/standard/tests/strings/join_error.phpt +++ b/ext/standard/tests/strings/join_error.phpt @@ -20,5 +20,5 @@ echo "Done\n"; *** Testing join() : error conditions *** -- Testing join() with less than expected no. of arguments -- -join(): Argument #1 ($pieces) must be of type array, string given +join(): Argument #1 ($array) must be of type array, string given Done diff --git a/ext/standard/tests/strings/join_variation2.phpt b/ext/standard/tests/strings/join_variation2.phpt index 57f570b258703..3991e0c52a6d8 100644 --- a/ext/standard/tests/strings/join_variation2.phpt +++ b/ext/standard/tests/strings/join_variation2.phpt @@ -138,13 +138,13 @@ join(): Argument #2 ($array) must be of type ?array, string given -- Iteration 18 -- join(): Argument #2 ($array) must be of type ?array, string given -- Iteration 19 -- -join(): Argument #1 ($pieces) must be of type array, string given +join(): Argument #1 ($array) must be of type array, string given -- Iteration 20 -- -join(): Argument #1 ($pieces) must be of type array, string given +join(): Argument #1 ($array) must be of type array, string given -- Iteration 21 -- join(): Argument #2 ($array) must be of type ?array, resource given -- Iteration 22 -- -join(): Argument #1 ($pieces) must be of type array, string given +join(): Argument #1 ($array) must be of type array, string given -- Iteration 23 -- -join(): Argument #1 ($pieces) must be of type array, string given +join(): Argument #1 ($array) must be of type array, string given Done From bffc74474b04cfec0e680267318c0aa6a33c0647 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 26 Aug 2023 18:37:42 +0200 Subject: [PATCH 11/38] Add missing EXTENSIONS section to DOM tests --- ext/dom/tests/bug80602.phpt | 2 ++ ext/dom/tests/bug80602_2.phpt | 2 ++ ext/dom/tests/bug80602_3.phpt | 2 ++ ext/dom/tests/bug80602_4.phpt | 2 ++ ext/dom/tests/gh11288.phpt | 2 ++ ext/dom/tests/gh11289.phpt | 2 ++ ext/dom/tests/gh11290.phpt | 2 ++ ext/dom/tests/gh9142.phpt | 2 ++ 8 files changed, 16 insertions(+) diff --git a/ext/dom/tests/bug80602.phpt b/ext/dom/tests/bug80602.phpt index 844d829cb08d0..9f6334ed36be0 100644 --- a/ext/dom/tests/bug80602.phpt +++ b/ext/dom/tests/bug80602.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #80602 (Segfault when using DOMChildNode::before()) +--EXTENSIONS-- +dom --FILE-- Date: Mon, 28 Aug 2023 12:14:55 +0100 Subject: [PATCH 12/38] Fix flaky file stat tests due to changing nature of atime --- ext/standard/tests/file/file.inc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/file/file.inc b/ext/standard/tests/file/file.inc index 0292bea118281..d4ad02a363bd5 100644 --- a/ext/standard/tests/file/file.inc +++ b/ext/standard/tests/file/file.inc @@ -590,6 +590,8 @@ $all_stat_keys = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, "rdev", "size", "atime", "mtime", "ctime", "blksize", "blocks"); +$stat_time_diff_keys = array(8, 'atime'); + function compare_stats($stat1, $stat2, $fields, $op = "==", $flag = false ) { // dump the stat if requested if ( $flag == true ) { @@ -606,8 +608,13 @@ function compare_stats($stat1, $stat2, $fields, $op = "==", $flag = false ) { { case "==": if ( $stat1[ $fields[$index] ] != $stat2[ $fields[$index] ] ) { - $result = false; - echo "Error: stat1 do not match with stat2 at key value: $fields[$index]\n"; + if ( ! in_array( $index, $stat_time_diff_keys ) ) { + $result = false; + echo "Error: stat1 do not match with stat2 at key value: $fields[$index]\n"; + } elseif (abs($stat1[ $fields[$index] ] - $stat2[ $fields[$index] ]) > 1) { + $result = false; + echo "Error: stat1 differs too much from stat2 at key value: $fields[$index]\n"; + } } break; From f3bd027b6985ce0c488bae93eae4e7acd7159ed8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 28 Aug 2023 12:55:39 +0200 Subject: [PATCH 13/38] Fix missing instantclient in CI We should only pass the --with-pdo-oci and --with-oci8 flags if instantclient is installed. Closes GH-12066 --- .github/actions/configure-x64/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/configure-x64/action.yml b/.github/actions/configure-x64/action.yml index ee802334490ae..3c3264ae07f5e 100644 --- a/.github/actions/configure-x64/action.yml +++ b/.github/actions/configure-x64/action.yml @@ -74,8 +74,8 @@ runs: --with-imap \ --with-imap-ssl \ --with-pdo-odbc=unixODBC,/usr \ - --with-pdo-oci=shared,instantclient,/opt/oracle/instantclient \ - --with-oci8=shared,instantclient,/opt/oracle/instantclient \ + $([ -d "/opt/oracle/instantclient" ] && echo '--with-pdo-oci=shared,instantclient,/opt/oracle/instantclient') \ + $([ -d "/opt/oracle/instantclient" ] && echo '--with-oci8=shared,instantclient,/opt/oracle/instantclient') \ --with-config-file-path=/etc \ --with-config-file-scan-dir=/etc/php.d \ --with-pdo-firebird \ From c8f6ee8c6f27f4119d7e2a9864b748f42d94a6b9 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 28 Aug 2023 17:24:45 +0200 Subject: [PATCH 14/38] [skip ci] Fix trailing data in unserialize in soap test --- ext/soap/tests/bug71610.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/soap/tests/bug71610.phpt b/ext/soap/tests/bug71610.phpt index 92491d0576996..ef0803134fb42 100644 --- a/ext/soap/tests/bug71610.phpt +++ b/ext/soap/tests/bug71610.phpt @@ -8,7 +8,7 @@ if (getenv("SKIP_ONLINE_TESTS")) die("skip online test"); ?> --FILE-- blahblah(); } catch(SoapFault $e) { From bf3fb4e5c969db276553eab5c9da9abb792b36e3 Mon Sep 17 00:00:00 2001 From: Jeremie Courreges-Anglas Date: Mon, 28 Aug 2023 19:47:19 +0200 Subject: [PATCH 15/38] On riscv64 require libatomic if actually needed clang and newer gcc releases support byte-sized atomic accesses on riscv64 through inline builtins. In both cases the hard dependency on libatomic added by GH-11321 isn't useful. Stop using AC_CHECK_LIB() which is too naive to notice that libatomic isn't needed. Instead, PHP_CHECK_FUNC() will retry the check with -latomic if required. Closes GH-11790 --- NEWS | 2 ++ configure.ac | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index a4d3499a58315..f5c7d0c199bee 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS - Core: . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) + . Fixed bug GH-11790 (On riscv64 require libatomic if actually needed). + (Jeremie Courreges-Anglas) - DOM: . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) diff --git a/configure.ac b/configure.ac index 0c723046adfdc..93e8bd96b76db 100644 --- a/configure.ac +++ b/configure.ac @@ -369,11 +369,7 @@ AC_CHECK_LIB(m, sin) case $host_alias in riscv64*) - AC_CHECK_LIB(atomic, __atomic_exchange_1, [ - PHP_ADD_LIBRARY(atomic) - ], [ - AC_MSG_ERROR([Problem with enabling atomic. Please check config.log for details.]) - ]) + PHP_CHECK_FUNC(__atomic_exchange_1, atomic) ;; esac From f2c16b7ba3f6b37a9acbad9fe9fdbc6be15f9a8d Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 29 Aug 2023 12:43:11 +0200 Subject: [PATCH 16/38] Make unrepeatable tests retriable This was an error in thinking on my side. The reason these tests are unrepeatable is because --repeat executes the same request in the same process, and does not run the CLEAN section in between runs. This is not the case when retrying tests. We could potentially make CLEAN tests repeatable by including the CLEAN section in the tested script. This does however not work for all tests (e.g. tests that set open_basedir). Closes GH-12072 --- run-tests.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/run-tests.php b/run-tests.php index 11fe91d7a6cce..12e03ae615a82 100755 --- a/run-tests.php +++ b/run-tests.php @@ -1886,7 +1886,6 @@ function run_test(string $php, $file, array $env): string $skipCache = new SkipCache($enableSkipCache, $cfg['keep']['skip']); } - $retriable = true; $retried = false; retry: @@ -1935,7 +1934,6 @@ function run_test(string $php, $file, array $env): string $tested = $test->getName(); if ($test->hasSection('FILE_EXTERNAL')) { - $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, 'Test with FILE_EXTERNAL might not be repeatable'); } @@ -1964,7 +1962,6 @@ function run_test(string $php, $file, array $env): string } $php = $php_cgi . ' -C '; $uses_cgi = true; - $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, 'CGI does not support --repeat'); } @@ -1982,7 +1979,6 @@ function run_test(string $php, $file, array $env): string } else { return skip_test($tested, $tested_file, $shortname, 'phpdbg not available'); } - $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, 'phpdbg does not support --repeat'); } @@ -1990,7 +1986,6 @@ function run_test(string $php, $file, array $env): string foreach (['CLEAN', 'STDIN', 'CAPTURE_STDIO'] as $section) { if ($test->hasSection($section)) { - $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, "Test with $section might not be repeatable"); } @@ -2173,7 +2168,6 @@ function run_test(string $php, $file, array $env): string settings2array(preg_split("/[\n\r]+/", $ini), $ini_settings); if (isset($ini_settings['opcache.opt_debug_level'])) { - $retriable = false; if ($num_repeats > 1) { return skip_test($tested, $tested_file, $shortname, 'opt_debug_level tests are not repeatable'); } @@ -2747,7 +2741,7 @@ function run_test(string $php, $file, array $env): string $wanted_re = null; } - if (!$passed && !$retried && $retriable && error_may_be_retried($test, $output)) { + if (!$passed && !$retried && error_may_be_retried($test, $output)) { $retried = true; goto retry; } From ffd7018fcdd13ca2966149e5141197a02707aff1 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 30 Aug 2023 21:25:03 +0200 Subject: [PATCH 17/38] Fix GH-11972: RecursiveCallbackFilterIterator regression in 8.1.18 When you do an assignment between two zvals (no, not zval*), you copy all fields. This includes the additional u2 data. So that means for example the Z_NEXT index gets copied, which in some cases can therefore cause a cycle in zend_hash lookups. Instead of doing an assignment, we should be doing a ZVAL_COPY (or ZVAL_COPY_VALUE for non-refcounting cases). This avoids copying u2. Closes GH-12086. --- NEWS | 4 + ext/spl/spl_array.c | 5 +- ext/spl/tests/gh11972.phpt | 196 +++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 ext/spl/tests/gh11972.phpt diff --git a/NEWS b/NEWS index f5c7d0c199bee..05710a643eb0d 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ PHP NEWS . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: "trying to connect via (null)"). (Kamil Tekiela) +- SPL: + . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). + (nielsdos) + 31 Aug 2023, PHP 8.1.23 - CLI: diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 676f68fb6b276..01756186fa525 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1128,13 +1128,12 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array))); if (intern->is_child) { - Z_TRY_DELREF_P(&intern->bucket->val); + Z_TRY_DELREF(intern->bucket->val); /* * replace bucket->val with copied array, so the changes between * parent and child object can affect each other. */ - intern->bucket->val = intern->array; - Z_TRY_ADDREF_P(&intern->array); + ZVAL_COPY(&intern->bucket->val, &intern->array); } } } else { diff --git a/ext/spl/tests/gh11972.phpt b/ext/spl/tests/gh11972.phpt new file mode 100644 index 0000000000000..d88d7c5ecae40 --- /dev/null +++ b/ext/spl/tests/gh11972.phpt @@ -0,0 +1,196 @@ +--TEST-- +GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18) +--EXTENSIONS-- +spl +--FILE-- +setMaxDepth(20); + foreach ($recursive_iterator as $value) { + // Avoid recursion by marking where we've been. + $value['#override_mode_breadcrumb'] = true; + } + return \iterator_to_array($recursive_iterator); + } + + public function isCyclic($current, string $key, \RecursiveArrayIterator $iterator): bool { + var_dump($current); + if (!is_array($current)) { + return false; + } + // Avoid infinite loops by checking if we've been here before. + // e.g. View > query > view > query ... + if (isset($current['#override_mode_breadcrumb'])) { + return false; + } + return true; + } +} + +$test_array['e']['p'][] = ['a', 'a']; +$test_array['e']['p'][] = ['b', 'b']; +$test_array['e']['p'][] = ['c', 'c']; +$serialized = serialize($test_array); +$unserialized = unserialize($serialized); + +$test_class = new RecursiveFilterTest(); +$test_class->traverse($unserialized); + +echo "Done\n"; + +?> +--EXPECT-- +array(1) { + ["p"]=> + array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } + } +} +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" +} +string(1) "a" +string(1) "a" +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" +} +string(1) "b" +string(1) "b" +array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" +} +string(1) "c" +string(1) "c" +array(1) { + ["p"]=> + array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } + } +} +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" +} +string(1) "a" +string(1) "a" +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" +} +string(1) "b" +string(1) "b" +array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" +} +string(1) "c" +string(1) "c" +Done From fb0f4215de04bdd8b8802cb50b5db03a9e80d616 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 30 Aug 2023 22:20:51 +0200 Subject: [PATCH 18/38] Skip dl() tests on ASAN --- ext/dl_test/tests/skip.inc | 4 ++++ ext/opcache/tests/bug68104.phpt | 4 ++++ ext/standard/tests/general_functions/dl-check-enabled.phpt | 1 + ext/standard/tests/general_functions/dl-cve-2007-4887.phpt | 1 + .../tests/general_functions/dl-full-path-not-supported.phpt | 1 + 5 files changed, 11 insertions(+) diff --git a/ext/dl_test/tests/skip.inc b/ext/dl_test/tests/skip.inc index e7558c7635082..1149c235d5280 100644 --- a/ext/dl_test/tests/skip.inc +++ b/ext/dl_test/tests/skip.inc @@ -12,3 +12,7 @@ if (PHP_OS_FAMILY === 'Windows') { if (!file_exists($path)) { die(sprintf('skip dl_test extension is not built (tried %s)', $path)); } + +if (getenv('SKIP_ASAN')) { + die('xleak dl() crashes LSan'); +} diff --git a/ext/opcache/tests/bug68104.phpt b/ext/opcache/tests/bug68104.phpt index 0726d96a1cd08..00c9551e974c2 100644 --- a/ext/opcache/tests/bug68104.phpt +++ b/ext/opcache/tests/bug68104.phpt @@ -8,6 +8,10 @@ opcache.enable_cli=1 disable_functions=dl --EXTENSIONS-- opcache +--SKIPIF-- + --FILE-- --INI-- enable_dl=0 diff --git a/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt b/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt index effae83464ed5..d392d41304feb 100644 --- a/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt +++ b/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt @@ -6,6 +6,7 @@ $enabled_sapi = array('cgi-fcgi', 'cli', 'embed', 'fpm'); if (!in_array(php_sapi_name(), $enabled_sapi)) { die('skip dl() is not enabled for ' . php_sapi_name()); } +if (getenv('SKIP_ASAN')) die('xleak dl() crashes LSan'); ?> --INI-- enable_dl=1 diff --git a/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt b/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt index aaf7d042e536a..2b7ec7dc53190 100644 --- a/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt +++ b/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt @@ -9,6 +9,7 @@ $enabled_sapi = array('cgi-fcgi', 'cli', 'embed', 'fpm'); if (!in_array(php_sapi_name(), $enabled_sapi)) { die('skip dl() is not enabled for ' . php_sapi_name()); } +if (getenv('SKIP_ASAN')) die('xleak dl() crashes LSan'); ?> --INI-- enable_dl=1 From d229a480ad5a63b029cc0d74ba251c5ddb8738e4 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Tue, 8 Aug 2023 10:44:04 +0100 Subject: [PATCH 19/38] Fix GH-11876: ini_parse_quantity() accepts invalid quantities Closes GH-11910 --- NEWS | 2 ++ Zend/tests/zend_ini/gh11876.phpt | 51 ++++++++++++++++++++++++++++++++ Zend/zend_ini.c | 40 +++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 Zend/tests/zend_ini/gh11876.phpt diff --git a/NEWS b/NEWS index dc48ab5182215..8e9c36ecdd9fd 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) . Fixed bug GH-11790 (On riscv64 require libatomic if actually needed). (Jeremie Courreges-Anglas) + . Fixed bug GH-11876: ini_parse_quantity() accepts invalid quantities. + (Girgias) - DOM: . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) diff --git a/Zend/tests/zend_ini/gh11876.phpt b/Zend/tests/zend_ini/gh11876.phpt new file mode 100644 index 0000000000000..b83061bf161e3 --- /dev/null +++ b/Zend/tests/zend_ini/gh11876.phpt @@ -0,0 +1,51 @@ +--TEST-- +Invalid INI quantities, base prefix followed by stuff eaten by strtoull() +--EXTENSIONS-- +zend_test +--FILE-- + Date: Wed, 30 Aug 2023 21:25:03 +0200 Subject: [PATCH 20/38] Fix GH-11972: RecursiveCallbackFilterIterator regression in 8.1.18 When you do an assignment between two zvals (no, not zval*), you copy all fields. This includes the additional u2 data. So that means for example the Z_NEXT index gets copied, which in some cases can therefore cause a cycle in zend_hash lookups. Instead of doing an assignment, we should be doing a ZVAL_COPY (or ZVAL_COPY_VALUE for non-refcounting cases). This avoids copying u2. Closes GH-12086. --- NEWS | 4 + ext/spl/spl_array.c | 5 +- ext/spl/tests/gh11972.phpt | 196 +++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 ext/spl/tests/gh11972.phpt diff --git a/NEWS b/NEWS index f5c7d0c199bee..05710a643eb0d 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ PHP NEWS . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: "trying to connect via (null)"). (Kamil Tekiela) +- SPL: + . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). + (nielsdos) + 31 Aug 2023, PHP 8.1.23 - CLI: diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 676f68fb6b276..01756186fa525 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1128,13 +1128,12 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array))); if (intern->is_child) { - Z_TRY_DELREF_P(&intern->bucket->val); + Z_TRY_DELREF(intern->bucket->val); /* * replace bucket->val with copied array, so the changes between * parent and child object can affect each other. */ - intern->bucket->val = intern->array; - Z_TRY_ADDREF_P(&intern->array); + ZVAL_COPY(&intern->bucket->val, &intern->array); } } } else { diff --git a/ext/spl/tests/gh11972.phpt b/ext/spl/tests/gh11972.phpt new file mode 100644 index 0000000000000..d88d7c5ecae40 --- /dev/null +++ b/ext/spl/tests/gh11972.phpt @@ -0,0 +1,196 @@ +--TEST-- +GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18) +--EXTENSIONS-- +spl +--FILE-- +setMaxDepth(20); + foreach ($recursive_iterator as $value) { + // Avoid recursion by marking where we've been. + $value['#override_mode_breadcrumb'] = true; + } + return \iterator_to_array($recursive_iterator); + } + + public function isCyclic($current, string $key, \RecursiveArrayIterator $iterator): bool { + var_dump($current); + if (!is_array($current)) { + return false; + } + // Avoid infinite loops by checking if we've been here before. + // e.g. View > query > view > query ... + if (isset($current['#override_mode_breadcrumb'])) { + return false; + } + return true; + } +} + +$test_array['e']['p'][] = ['a', 'a']; +$test_array['e']['p'][] = ['b', 'b']; +$test_array['e']['p'][] = ['c', 'c']; +$serialized = serialize($test_array); +$unserialized = unserialize($serialized); + +$test_class = new RecursiveFilterTest(); +$test_class->traverse($unserialized); + +echo "Done\n"; + +?> +--EXPECT-- +array(1) { + ["p"]=> + array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } + } +} +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" +} +string(1) "a" +string(1) "a" +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" +} +string(1) "b" +string(1) "b" +array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" +} +string(1) "c" +string(1) "c" +array(1) { + ["p"]=> + array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } + } +} +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" +} +string(1) "a" +string(1) "a" +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" +} +string(1) "b" +string(1) "b" +array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" +} +string(1) "c" +string(1) "c" +Done From f4a6a6d096efdd17ad6d1b2c8bdc1fb663745723 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 30 Aug 2023 22:31:27 +0200 Subject: [PATCH 21/38] Increase run-tests.php timeout for asan Closes GH-12087 --- run-tests.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/run-tests.php b/run-tests.php index 12e03ae615a82..404fd3e457a6a 100755 --- a/run-tests.php +++ b/run-tests.php @@ -1284,6 +1284,10 @@ function system_with_timeout( } $timeout = $valgrind ? 300 : ($env['TEST_TIMEOUT'] ?? 60); + /* ASAN can cause a ~2-3x slowdown. */ + if (isset($env['SKIP_ASAN'])) { + $timeout *= 3; + } while (true) { /* hide errors from interrupted syscalls */ From b21df69848bb32594ae7fc7e62f8908806551157 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 1 Sep 2023 12:39:03 +0200 Subject: [PATCH 22/38] [skip ci] Fix borked xleak skip on --FILE-- --INI-- enable_dl=0 diff --git a/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt b/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt index d392d41304feb..d4920365574d8 100644 --- a/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt +++ b/ext/standard/tests/general_functions/dl-cve-2007-4887.phpt @@ -6,7 +6,7 @@ $enabled_sapi = array('cgi-fcgi', 'cli', 'embed', 'fpm'); if (!in_array(php_sapi_name(), $enabled_sapi)) { die('skip dl() is not enabled for ' . php_sapi_name()); } -if (getenv('SKIP_ASAN')) die('xleak dl() crashes LSan'); +if (getenv('SKIP_ASAN')) die('skip dl() crashes LSan'); ?> --INI-- enable_dl=1 diff --git a/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt b/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt index 2b7ec7dc53190..ac317df429b02 100644 --- a/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt +++ b/ext/standard/tests/general_functions/dl-full-path-not-supported.phpt @@ -9,7 +9,7 @@ $enabled_sapi = array('cgi-fcgi', 'cli', 'embed', 'fpm'); if (!in_array(php_sapi_name(), $enabled_sapi)) { die('skip dl() is not enabled for ' . php_sapi_name()); } -if (getenv('SKIP_ASAN')) die('xleak dl() crashes LSan'); +if (getenv('SKIP_ASAN')) die('skip dl() crashes LSan'); ?> --INI-- enable_dl=1 From a022ec53bdad139adcfb1fbd06ed7a5059bffbf4 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Thu, 31 Aug 2023 15:25:46 -0300 Subject: [PATCH 23/38] Fix memory leak with failed SQLPrepare Closes GH-12095 Signed-off-by: George Peter Banyard --- NEWS | 3 +++ ext/odbc/php_odbc.c | 1 + 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 05710a643eb0d..be860fb96d185 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,9 @@ PHP NEWS . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: "trying to connect via (null)"). (Kamil Tekiela) +- ODBC: + . Fixed memory leak with failed SQLPrepare. (NattyNarwhal) + - SPL: . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). (nielsdos) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index dd2bbd03e79b8..71fd397900204 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -923,6 +923,7 @@ PHP_FUNCTION(odbc_prepare) break; default: odbc_sql_error(conn, result->stmt, "SQLPrepare"); + efree(result); RETURN_FALSE; } From a579fa807c260cd571e41486678758d277a541f7 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 3 Sep 2023 00:59:20 +0100 Subject: [PATCH 24/38] Fixed bug GH-12020: intl_get_error_message() broken after MessageFormatter::formatMessage() fails Passing NULL as the pointer to intl_error* will use the global error stack. This is what we need to do instead of pushing it onto the temporary format object that is released. --- NEWS | 4 ++++ ext/intl/msgformat/msgformat_format.c | 13 ++++++------- ext/intl/tests/gh11658.phpt | 6 ++++++ ext/intl/tests/gh12020.phpt | 22 ++++++++++++++++++++++ 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 ext/intl/tests/gh12020.phpt diff --git a/NEWS b/NEWS index be860fb96d185..e001635a235b6 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,10 @@ PHP NEWS . Fixed build for NetBSD which still uses the old iconv signature. (David Carlier) +- Intl: + . Fixed bug GH-12020 (intl_get_error_message() broken after + MessageFormatter::formatMessage() fails). (Girgias) + - MySQLnd: . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: "trying to connect via (null)"). (Kamil Tekiela) diff --git a/ext/intl/msgformat/msgformat_format.c b/ext/intl/msgformat/msgformat_format.c index 098c6a2b92286..f6ec60fe19942 100644 --- a/ext/intl/msgformat/msgformat_format.c +++ b/ext/intl/msgformat/msgformat_format.c @@ -98,7 +98,7 @@ PHP_FUNCTION( msgfmt_format_message ) intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo)); if( U_FAILURE(INTL_DATA_ERROR_CODE((mfo))) ) { - intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + intl_error_set(/* intl_error* */ NULL, U_ILLEGAL_ARGUMENT_ERROR, "msgfmt_format_message: error converting pattern to UTF-16", 0 ); RETURN_FALSE; } @@ -113,7 +113,7 @@ PHP_FUNCTION( msgfmt_format_message ) #ifdef MSG_FORMAT_QUOTE_APOS if(msgformat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) { - intl_error_set( NULL, U_INVALID_FORMAT_ERROR, + intl_error_set(/* intl_error* */ NULL, U_INVALID_FORMAT_ERROR, "msgfmt_format_message: error converting pattern to quote-friendly format", 0 ); RETURN_FALSE; } @@ -134,15 +134,14 @@ PHP_FUNCTION( msgfmt_format_message ) spprintf( &msg, 0, "pattern syntax error (%s)", parse_error_str.s? ZSTR_VAL(parse_error_str.s) : "unknown parser error" ); smart_str_free( &parse_error_str ); - intl_error_set_code( NULL, INTL_DATA_ERROR_CODE( mfo ) ); - intl_errors_set_custom_msg( INTL_DATA_ERROR_P( mfo ), msg, 1 ); + /* Pass NULL to intl_error* parameter to store message in global Intl error msg stack */ + intl_error_set_code(/* intl_error* */ NULL, INTL_DATA_ERROR_CODE( mfo ) ); + intl_errors_set_custom_msg(/* intl_error* */ NULL, msg, 1 ); efree( msg ); } else { - intl_errors_set_custom_msg( INTL_DATA_ERROR_P(mfo), "Creating message formatter failed", 0 ); + intl_errors_set_custom_msg(/* intl_error* */ NULL, "Creating message formatter failed", 0 ); } - /* Reset custom error message as this is a static method that has no object */ - intl_errors_reset(INTL_DATA_ERROR_P(mfo)); umsg_close(MSG_FORMAT_OBJECT(mfo)); RETURN_FALSE; } diff --git a/ext/intl/tests/gh11658.phpt b/ext/intl/tests/gh11658.phpt index b29786255cacb..f0cfab9280ef6 100644 --- a/ext/intl/tests/gh11658.phpt +++ b/ext/intl/tests/gh11658.phpt @@ -9,7 +9,13 @@ ini_set("intl.error_level", E_WARNING); $s = MessageFormatter::formatMessage('en', 'some {wrong.format}', []); var_dump($s); + +$s = msgfmt_format_message('en', 'some {wrong.format}', []); +var_dump($s); ?> --EXPECTF-- Warning: MessageFormatter::formatMessage(): pattern syntax error (parse error at offset 6, after "some {", before or at "wrong.format}") in %s on line %d bool(false) + +Warning: msgfmt_format_message(): pattern syntax error (parse error at offset 6, after "some {", before or at "wrong.format}") in %s on line %d +bool(false) diff --git a/ext/intl/tests/gh12020.phpt b/ext/intl/tests/gh12020.phpt new file mode 100644 index 0000000000000..e4102606ca54e --- /dev/null +++ b/ext/intl/tests/gh12020.phpt @@ -0,0 +1,22 @@ +--TEST-- +GitHub #12020 intl_get_error_message() broken after MessageFormatter::formatMessage() fails +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +bool(false) +string(128) "pattern syntax error (parse error at offset 19, after " message with {", before or at "invalid format}"): U_PATTERN_SYNTAX_ERROR" +bool(false) +string(116) "pattern syntax error (parse error at offset 6, after "some {", before or at "wrong.format}"): U_PATTERN_SYNTAX_ERROR" +bool(false) +string(128) "pattern syntax error (parse error at offset 19, after " message with {", before or at "invalid format}"): U_PATTERN_SYNTAX_ERROR" +bool(false) +string(116) "pattern syntax error (parse error at offset 6, after "some {", before or at "wrong.format}"): U_PATTERN_SYNTAX_ERROR" From 8cca0e80efe57493527a67e2d48da7837f593d61 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 4 Sep 2023 13:52:59 +0200 Subject: [PATCH 25/38] [skip ci] Skip github actions when editing other ci files --- .github/workflows/push.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 10590f355424b..4a00fbcaad8a3 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -9,6 +9,9 @@ on: - README.md - CONTRIBUTING.md - CODING_STANDARDS.md + - .cirrus.yml + - .travis.yml + - travis/* branches: - PHP-7.4 - PHP-8.0 From e3df233aca53b58d02fba53dc081fd8ea50c69eb Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 4 Sep 2023 13:57:48 +0200 Subject: [PATCH 26/38] [skip ci] Backport GA paths-ignore changes --- .github/workflows/push.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 4a00fbcaad8a3..b346bb491d670 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -6,7 +6,7 @@ on: - NEWS - UPGRADING - UPGRADING.INTERNALS - - README.md + - '**/README.*' - CONTRIBUTING.md - CODING_STANDARDS.md - .cirrus.yml @@ -18,6 +18,17 @@ on: - PHP-8.1 - master pull_request: + paths-ignore: + - docs/* + - NEWS + - UPGRADING + - UPGRADING.INTERNALS + - '**/README.*' + - CONTRIBUTING.md + - CODING_STANDARDS.md + - .cirrus.yml + - .travis.yml + - travis/* branches: - '**' concurrency: From af2110e664635329cbd7038727d4c7f222bb8a0e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 29 Aug 2023 16:53:38 +0200 Subject: [PATCH 27/38] Fix freeing of incompletely initialized closures Addref to relevant fields before allocating any memory. Also only set/remove the ZEND_ACC_HEAP_RT_CACHE flag after allocating memory. Fixes GH-12073 Closes GH-12074 --- NEWS | 2 ++ Zend/tests/gh12073.phpt | 28 ++++++++++++++++++++++++++++ Zend/zend_closures.c | 13 +++++++------ 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 Zend/tests/gh12073.phpt diff --git a/NEWS b/NEWS index e001635a235b6..c85c5c0da553b 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) . Fixed bug GH-11790 (On riscv64 require libatomic if actually needed). (Jeremie Courreges-Anglas) + . Fixed bug GH-12073 (Segfault when freeing incompletely initialized + closures). (ilutov) - DOM: . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) diff --git a/Zend/tests/gh12073.phpt b/Zend/tests/gh12073.phpt new file mode 100644 index 0000000000000..ef115685ce7d4 --- /dev/null +++ b/Zend/tests/gh12073.phpt @@ -0,0 +1,28 @@ +--TEST-- +GH-12073: Freeing of non-ZMM pointer of incompletely allocated closure +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 0dab5537a3752..dd5ae16c9f13a 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -689,6 +689,11 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; closure->func.common.fn_flags &= ~ZEND_ACC_IMMUTABLE; + zend_string_addref(closure->func.op_array.function_name); + if (closure->func.op_array.refcount) { + (*closure->func.op_array.refcount)++; + } + /* For fake closures, we want to reuse the static variables of the original function. */ if (!is_fake) { if (closure->func.op_array.static_variables) { @@ -722,24 +727,20 @@ static void zend_create_closure_ex(zval *res, zend_function *func, zend_class_en if (func->common.scope != scope) { func->common.scope = scope; } - closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE; ptr = zend_arena_alloc(&CG(arena), func->op_array.cache_size); ZEND_MAP_PTR_SET(func->op_array.run_time_cache, ptr); ZEND_MAP_PTR_SET(closure->func.op_array.run_time_cache, ptr); + closure->func.op_array.fn_flags &= ~ZEND_ACC_HEAP_RT_CACHE; } else { /* Otherwise, we use a non-shared runtime cache */ - closure->func.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; ptr = emalloc(sizeof(void*) + func->op_array.cache_size); ZEND_MAP_PTR_INIT(closure->func.op_array.run_time_cache, ptr); ptr = (char*)ptr + sizeof(void*); ZEND_MAP_PTR_SET(closure->func.op_array.run_time_cache, ptr); + closure->func.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE; } memset(ptr, 0, func->op_array.cache_size); } - zend_string_addref(closure->func.op_array.function_name); - if (closure->func.op_array.refcount) { - (*closure->func.op_array.refcount)++; - } } else { memcpy(&closure->func, func, sizeof(zend_internal_function)); closure->func.common.fn_flags |= ZEND_ACC_CLOSURE; From f1f608bf53c6482d633ea2b41c77e525a20f34b0 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 5 Sep 2023 10:11:54 +0300 Subject: [PATCH 28/38] Fixed uninitialized EX(opline) access (possible Zend/tests/gh12073.phpt crash) --- Zend/zend_vm_def.h | 1 + Zend/zend_vm_execute.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 646dab4ae685a..90704993bb253 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8002,6 +8002,7 @@ ZEND_VM_HANDLER(142, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, NUM) called_scope = Z_CE(EX(This)); object = NULL; } + SAVE_OPLINE(); zend_create_closure(EX_VAR(opline->result.var), func, EX(func)->op_array.scope, called_scope, object); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5675f89412159..530fd7d3e117c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5366,6 +5366,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_C called_scope = Z_CE(EX(This)); object = NULL; } + SAVE_OPLINE(); zend_create_closure(EX_VAR(opline->result.var), func, EX(func)->op_array.scope, called_scope, object); From 9658d9ada48eddead8d3763a519011a98b3e5bb7 Mon Sep 17 00:00:00 2001 From: ju1ius Date: Sun, 27 Aug 2023 18:06:10 +0200 Subject: [PATCH 29/38] adds failing test case for #12060 Signed-off-by: George Peter Banyard --- ext/zend_test/config.m4 | 2 +- ext/zend_test/config.w32 | 2 +- ext/zend_test/iterators.c | 121 ++++++++++++++++++ ext/zend_test/iterators.h | 21 +++ ext/zend_test/iterators.stub.php | 14 ++ ext/zend_test/iterators_arginfo.h | 31 +++++ ext/zend_test/test.c | 2 + .../tests/iterators/double-rewind.phpt | 40 ++++++ 8 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 ext/zend_test/iterators.c create mode 100644 ext/zend_test/iterators.h create mode 100644 ext/zend_test/iterators.stub.php create mode 100644 ext/zend_test/iterators_arginfo.h create mode 100644 ext/zend_test/tests/iterators/double-rewind.phpt diff --git a/ext/zend_test/config.m4 b/ext/zend_test/config.m4 index c33ad74f0c8a6..4fda9d2cab5d2 100644 --- a/ext/zend_test/config.m4 +++ b/ext/zend_test/config.m4 @@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test], [Enable zend_test extension])]) if test "$PHP_ZEND_TEST" != "no"; then - PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) + PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi diff --git a/ext/zend_test/config.w32 b/ext/zend_test/config.w32 index a44a7fc3d9d8a..8d68facffb308 100644 --- a/ext/zend_test/config.w32 +++ b/ext/zend_test/config.w32 @@ -3,6 +3,6 @@ ARG_ENABLE("zend-test", "enable zend_test extension", "no"); if (PHP_ZEND_TEST != "no") { - EXTENSION("zend_test", "test.c observer.c fiber.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS "); } diff --git a/ext/zend_test/iterators.c b/ext/zend_test/iterators.c new file mode 100644 index 0000000000000..53756ca79e132 --- /dev/null +++ b/ext/zend_test/iterators.c @@ -0,0 +1,121 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#include "iterators.h" +#include "zend_API.h" +#include "iterators_arginfo.h" + +#include +#include "php.h" + +#define DUMP(s) php_output_write((s), sizeof((s)) - 1) + +static zend_class_entry *traversable_test_ce; + +// Dummy iterator that yields numbers from 0..4, +// while printing operations to the output buffer +typedef struct { + zend_object_iterator intern; + zval current; +} test_traversable_it; + +static test_traversable_it *test_traversable_it_fetch(zend_object_iterator *iter) { + return (test_traversable_it *)iter; +} + +static void test_traversable_it_dtor(zend_object_iterator *iter) { + DUMP("TraversableTest::drop\n"); + test_traversable_it *iterator = test_traversable_it_fetch(iter); + zval_ptr_dtor(&iterator->intern.data); +} + +static void test_traversable_it_rewind(zend_object_iterator *iter) { + DUMP("TraversableTest::rewind\n"); + test_traversable_it *iterator = test_traversable_it_fetch(iter); + ZVAL_LONG(&iterator->current, 0); +} + +static void test_traversable_it_next(zend_object_iterator *iter) { + DUMP("TraversableTest::next\n"); + test_traversable_it *iterator = test_traversable_it_fetch(iter); + ZVAL_LONG(&iterator->current, Z_LVAL(iterator->current) + 1); +} + +static int test_traversable_it_valid(zend_object_iterator *iter) { + DUMP("TraversableTest::valid\n"); + test_traversable_it *iterator = test_traversable_it_fetch(iter); + if (Z_LVAL(iterator->current) < 4) { + return SUCCESS; + } + return FAILURE; +} + +static void test_traversable_it_key(zend_object_iterator *iter, zval *return_value) { + DUMP("TraversableTest::key\n"); + test_traversable_it *iterator = test_traversable_it_fetch(iter); + ZVAL_LONG(return_value, Z_LVAL(iterator->current)); +} + +static zval *test_traversable_it_current(zend_object_iterator *iter) { + DUMP("TraversableTest::current\n"); + test_traversable_it *iterator = test_traversable_it_fetch(iter); + return &iterator->current; +} + +static const zend_object_iterator_funcs test_traversable_it_vtable = { + test_traversable_it_dtor, + test_traversable_it_valid, + test_traversable_it_current, + test_traversable_it_key, + test_traversable_it_next, + test_traversable_it_rewind, + NULL, // invalidate_current + NULL, // get_gc +}; + +static zend_object_iterator *test_traversable_get_iterator( + zend_class_entry *ce, + zval *object, + int by_ref +) { + test_traversable_it *iterator; + + if (by_ref) { + zend_throw_error(NULL, "An iterator cannot be used with foreach by reference"); + return NULL; + } + + iterator = emalloc(sizeof(test_traversable_it)); + zend_iterator_init((zend_object_iterator*)iterator); + + ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object)); + iterator->intern.funcs = &test_traversable_it_vtable; + ZVAL_LONG(&iterator->current, 0); + + return (zend_object_iterator*)iterator; +} + +ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct) { + ZEND_PARSE_PARAMETERS_NONE(); +} + +ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator) { + ZEND_PARSE_PARAMETERS_NONE(); + zend_create_internal_iterator_zval(return_value, ZEND_THIS); +} + +void zend_test_iterators_init(void) { + traversable_test_ce = register_class_ZendTest_Iterators_TraversableTest(zend_ce_aggregate); + traversable_test_ce->get_iterator = test_traversable_get_iterator; +} diff --git a/ext/zend_test/iterators.h b/ext/zend_test/iterators.h new file mode 100644 index 0000000000000..cef09109e239a --- /dev/null +++ b/ext/zend_test/iterators.h @@ -0,0 +1,21 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | https://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_TEST_ITERATORS_H +#define ZEND_TEST_ITERATORS_H + +void zend_test_iterators_init(void); + +#endif + diff --git a/ext/zend_test/iterators.stub.php b/ext/zend_test/iterators.stub.php new file mode 100644 index 0000000000000..9b681e36b949e --- /dev/null +++ b/ext/zend_test/iterators.stub.php @@ -0,0 +1,14 @@ +ce_flags |= ZEND_ACC_FINAL; + zend_class_implements(class_entry, 1, class_entry_IteratorAggregate); + + return class_entry; +} diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index d612aedc9920b..c1c65450ea907 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -24,6 +24,7 @@ #include "php_test.h" #include "observer.h" #include "fiber.h" +#include "iterators.h" #include "zend_attributes.h" #include "zend_enum.h" #include "zend_interfaces.h" @@ -660,6 +661,7 @@ PHP_MINIT_FUNCTION(zend_test) zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU); zend_test_fiber_init(); + zend_test_iterators_init(); return SUCCESS; } diff --git a/ext/zend_test/tests/iterators/double-rewind.phpt b/ext/zend_test/tests/iterators/double-rewind.phpt new file mode 100644 index 0000000000000..179dd1de10775 --- /dev/null +++ b/ext/zend_test/tests/iterators/double-rewind.phpt @@ -0,0 +1,40 @@ +--TEST-- +Tests that internal iterator's rewind function is called once +--EXTENSIONS-- +zend_test +--FILE-- +getIterator(); +var_dump($it); +foreach ($it as $key => $value) { + echo "{$key} => {$value}\n"; +} +?> +--EXPECT-- +object(InternalIterator)#3 (0) { +} +TraversableTest::rewind +TraversableTest::valid +TraversableTest::current +TraversableTest::key +0 => 0 +TraversableTest::next +TraversableTest::valid +TraversableTest::current +TraversableTest::key +1 => 1 +TraversableTest::next +TraversableTest::valid +TraversableTest::current +TraversableTest::key +2 => 2 +TraversableTest::next +TraversableTest::valid +TraversableTest::current +TraversableTest::key +3 => 3 +TraversableTest::next +TraversableTest::valid +TraversableTest::drop From da7a66d6474933561bd6dace42001b2b1fd1988e Mon Sep 17 00:00:00 2001 From: ju1ius Date: Sun, 27 Aug 2023 18:18:34 +0200 Subject: [PATCH 30/38] Prevents double call to internal iterator rewind handler Closes GH-12060 Signed-off-by: George Peter Banyard --- NEWS | 2 ++ Zend/zend_interfaces.c | 1 + 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index c85c5c0da553b..ae734998d2284 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ PHP NEWS (Jeremie Courreges-Anglas) . Fixed bug GH-12073 (Segfault when freeing incompletely initialized closures). (ilutov) + . Fixed bug GH-12060 (Internal iterator rewind handler is called twice). + (ju1ius) - DOM: . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) diff --git a/Zend/zend_interfaces.c b/Zend/zend_interfaces.c index 3297b9f82aac6..8250359de5c10 100644 --- a/Zend/zend_interfaces.c +++ b/Zend/zend_interfaces.c @@ -585,6 +585,7 @@ ZEND_METHOD(InternalIterator, rewind) { RETURN_THROWS(); } + intern->rewind_called = 1; if (!intern->iter->funcs->rewind) { /* Allow calling rewind() if no iteration has happened yet, * even if the iterator does not support rewinding. */ From 5a2b251610bc3ca72f96cd8d9bf39c95d17e29ad Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Thu, 31 Aug 2023 16:14:30 -0300 Subject: [PATCH 31/38] Fix persistent procedural ODBC connections not getting closed Like oci8, procedural ODBC uses an apply function on the hash list to enumerate persistent connections and close the specific one. However, this function take zvals, not resources. However, it was getting casted as such, causing it to interpret the pointer incorrectly. This could have caused other issues, but mostly manifested as failing to close the connection even fi it matched. The function now takes a zval and gets the resource from that. In addition, it also removes the cast of the function pointer and moves casting to the function body, to avoid possible confusion like this in refactors again. It also cleans up style and uses constants in the function body. Closes GH-12132 Signed-off-by: George Peter Banyard --- NEWS | 2 + ext/odbc/php_odbc.c | 16 +++--- ext/odbc/tests/odbc_persistent_close.phpt | 65 +++++++++++++++++++++++ 3 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 ext/odbc/tests/odbc_persistent_close.phpt diff --git a/NEWS b/NEWS index ae734998d2284..568ce7c0f097b 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,8 @@ PHP NEWS - ODBC: . Fixed memory leak with failed SQLPrepare. (NattyNarwhal) + . Fixed persistent procedural ODBC connections not getting closed. + (NattyNarwhal) - SPL: . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 71fd397900204..b5e91da880644 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -753,12 +753,14 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) /* }}} */ /* {{{ _close_pconn_with_res */ -static int _close_pconn_with_res(zend_resource *le, zend_resource *res) +static int _close_pconn_with_res(zval *zv, void *p) { - if (le->type == le_pconn && (((odbc_connection *)(le->ptr))->res == res)){ - return 1; - }else{ - return 0; + zend_resource *le = Z_RES_P(zv); + zend_resource *res = (zend_resource*)p; + if (le->type == le_pconn && (((odbc_connection *)(le->ptr))->res == res)) { + return ZEND_HASH_APPLY_REMOVE; + } else { + return ZEND_HASH_APPLY_KEEP; } } /* }}} */ @@ -837,7 +839,7 @@ PHP_FUNCTION(odbc_close_all) zend_list_close(p); /* Delete the persistent connection */ zend_hash_apply_with_argument(&EG(persistent_list), - (apply_func_arg_t) _close_pconn_with_res, (void *)p); + _close_pconn_with_res, (void *)p); } } } ZEND_HASH_FOREACH_END(); @@ -2365,7 +2367,7 @@ PHP_FUNCTION(odbc_close) zend_list_close(Z_RES_P(pv_conn)); if(is_pconn){ - zend_hash_apply_with_argument(&EG(persistent_list), (apply_func_arg_t) _close_pconn_with_res, (void *) Z_RES_P(pv_conn)); + zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) Z_RES_P(pv_conn)); } } /* }}} */ diff --git a/ext/odbc/tests/odbc_persistent_close.phpt b/ext/odbc/tests/odbc_persistent_close.phpt new file mode 100644 index 0000000000000..bee936bf959f0 --- /dev/null +++ b/ext/odbc/tests/odbc_persistent_close.phpt @@ -0,0 +1,65 @@ +--TEST-- +odbc_pconnect(): Make sure closing a persistent connection works +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(22) "PHP odbc_pconnect test" +string(22) "PHP odbc_pconnect test" +NULL From a648d3929743b9fad7984ac4c2beda4960cdcee6 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Tue, 5 Sep 2023 11:24:22 -0300 Subject: [PATCH 32/38] ODBC unit tests shouldn't override odbc.ini location `ext/odbc/tests/config.inc` overrides the INIs used for the ODBC driver manager pointlessly. It's not pointing to some custom PHP test suite specific one, but the system one in `/etc/odbc(inst).ini`. Which doesn't necessarily exist, on i.e. NixOS, MacPorts, etc. Closes GH-12133 Signed-off-by: George Peter Banyard --- ext/odbc/tests/config.inc | 3 --- 1 file changed, 3 deletions(-) diff --git a/ext/odbc/tests/config.inc b/ext/odbc/tests/config.inc index 78be4b2d99adb..8d74feeb6ffb7 100644 --- a/ext/odbc/tests/config.inc +++ b/ext/odbc/tests/config.inc @@ -1,8 +1,5 @@ Date: Wed, 6 Sep 2023 13:22:59 +0200 Subject: [PATCH 33/38] Fix zend_separate_if_call_and_write for FUNC_ARGs Fixes GH-12102 Closees GH-12140 --- NEWS | 2 ++ Zend/Optimizer/optimize_func_calls.c | 23 +++++++++++++-- Zend/tests/gh12102_1.phpt | 30 +++++++++++++++++++ Zend/tests/gh12102_2.phpt | 43 ++++++++++++++++++++++++++++ Zend/tests/gh12102_3.phpt | 32 +++++++++++++++++++++ Zend/zend_compile.c | 6 +++- 6 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/gh12102_1.phpt create mode 100644 Zend/tests/gh12102_2.phpt create mode 100644 Zend/tests/gh12102_3.phpt diff --git a/NEWS b/NEWS index 568ce7c0f097b..f074747f7085c 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS closures). (ilutov) . Fixed bug GH-12060 (Internal iterator rewind handler is called twice). (ju1ius) + . Fixed bug GH-12102 (Incorrect compile error when using array access on TMP + value in function call). (ilutov) - DOM: . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) diff --git a/Zend/Optimizer/optimize_func_calls.c b/Zend/Optimizer/optimize_func_calls.c index 154baddc65426..c54c531bcfc1a 100644 --- a/Zend/Optimizer/optimize_func_calls.c +++ b/Zend/Optimizer/optimize_func_calls.c @@ -38,6 +38,7 @@ typedef struct _optimizer_call_info { zend_function *func; zend_op *opline; + zend_op *last_check_func_arg_opline; bool is_prototype; bool try_inline; uint32_t func_arg_num; @@ -252,6 +253,14 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) if (call_stack[call - 1].func_arg_num != (uint32_t)-1 && has_known_send_mode(&call_stack[call - 1], call_stack[call - 1].func_arg_num)) { if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, call_stack[call - 1].func_arg_num)) { + /* There's no TMP specialization for FETCH_OBJ_W/FETCH_DIM_W. Avoid + * converting it and error at runtime in the FUNC_ARG variant. */ + if ((opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) + && (opline->op1_type == IS_TMP_VAR || call_stack[call - 1].last_check_func_arg_opline == NULL)) { + /* Don't remove the associated CHECK_FUNC_ARG opcode. */ + call_stack[call - 1].last_check_func_arg_opline = NULL; + break; + } if (opline->opcode != ZEND_FETCH_STATIC_PROP_FUNC_ARG) { opline->opcode -= 9; } else { @@ -298,11 +307,21 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx) if (has_known_send_mode(&call_stack[call - 1], opline->op2.num)) { call_stack[call - 1].func_arg_num = opline->op2.num; - MAKE_NOP(opline); + call_stack[call - 1].last_check_func_arg_opline = opline; } break; - case ZEND_SEND_VAR_EX: case ZEND_SEND_FUNC_ARG: + /* Don't transform SEND_FUNC_ARG if any FETCH opcodes weren't transformed. */ + if (call_stack[call - 1].last_check_func_arg_opline == NULL) { + if (opline->op2_type == IS_CONST) { + call_stack[call - 1].try_inline = 0; + } + break; + } + MAKE_NOP(call_stack[call - 1].last_check_func_arg_opline); + call_stack[call - 1].last_check_func_arg_opline = NULL; + ZEND_FALLTHROUGH; + case ZEND_SEND_VAR_EX: if (opline->op2_type == IS_CONST) { call_stack[call - 1].try_inline = 0; break; diff --git a/Zend/tests/gh12102_1.phpt b/Zend/tests/gh12102_1.phpt new file mode 100644 index 0000000000000..1d548d6b28f3c --- /dev/null +++ b/Zend/tests/gh12102_1.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-12102: Incorrect "Cannot use temporary expression in write context" error for BP_VAR_FUNC_ARG +--FILE-- +getMessage(), "\n"; + } +} + +/* Intentionally declared after test() to avoid compile-time checking of ref args. */ + +function byVal($arg) { + var_dump($arg); +} + +function byRef(&$arg) { + var_dump($arg); +} + +test('y'); + +?> +--EXPECT-- +string(1) "y" +Cannot use temporary expression in write context diff --git a/Zend/tests/gh12102_2.phpt b/Zend/tests/gh12102_2.phpt new file mode 100644 index 0000000000000..dacc11c03081a --- /dev/null +++ b/Zend/tests/gh12102_2.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-12102: Incorrect "Cannot use temporary expression in write context" error for BP_VAR_FUNC_ARG +--FILE-- + +--EXPECTF-- +Warning: Undefined array key 0 in %s on line %d +array(0) { +} +array(1) { + [0]=> + array(1) { + [0]=> + int(42) + } +} diff --git a/Zend/tests/gh12102_3.phpt b/Zend/tests/gh12102_3.phpt new file mode 100644 index 0000000000000..741bce5ab1ba1 --- /dev/null +++ b/Zend/tests/gh12102_3.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-12102: Incorrect "Cannot use temporary expression in write context" error for BP_VAR_FUNC_ARG +--FILE-- +getMessage(), "\n"; + } +} + +/* Intentionally declared after test() to avoid compile-time checking of ref args. */ + +const C = ['foo']; + +function byVal($arg) { + var_dump($arg); +} + +function byRef(&$arg) { + var_dump($arg); +} + +test('y'); + +?> +--EXPECT-- +string(3) "foo" +Cannot use temporary expression in write context diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 75127b8b8d18a..c0cd3c97341f9 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2816,7 +2816,11 @@ static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t t static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type) /* {{{ */ { - if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) { + if (type != BP_VAR_R + && type != BP_VAR_IS + /* Whether a FUNC_ARG is R may only be determined at runtime. */ + && type != BP_VAR_FUNC_ARG + && zend_is_call(ast)) { if (node->op_type == IS_VAR) { zend_op *opline = zend_emit_op(NULL, ZEND_SEPARATE, node, NULL); opline->result_type = IS_VAR; From be0245c7569b55751bea1923881e834e3f26be60 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 8 Sep 2023 18:27:13 +0300 Subject: [PATCH 34/38] Fixed tracing JIT support for CALLABLE_CONVERT (#12156) --- ext/opcache/jit/zend_jit_trace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 88ce671b86188..03eae6c453ec8 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1065,6 +1065,7 @@ static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, c case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: call_level++; break; } @@ -6227,6 +6228,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: + case ZEND_CALLABLE_CONVERT: frame->call_level--; } From 07a9d2fb3274e130c6883d579d1360f7f0acb8ab Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 8 Sep 2023 19:56:36 +0200 Subject: [PATCH 35/38] Fix GH-11878: SQLite3 callback functions cause a memory leak with a callable array In this test file, the free_obj handler is called with a refcount of 2, caused by the fact we do a GC_ADDREF() to increase its refcount while its refcount is still 1 because the Foo object hasn't been destroyed yet (due to the cycle caused by the sqlite function callback). Solve this by introducing a get_gc handler. Closes GH-11881. --- NEWS | 4 ++++ ext/sqlite3/sqlite3.c | 37 ++++++++++++++++++++++++++++++++++ ext/sqlite3/tests/gh11878.phpt | 31 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 ext/sqlite3/tests/gh11878.phpt diff --git a/NEWS b/NEWS index f074747f7085c..a68a41ad39229 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,10 @@ PHP NEWS . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). (nielsdos) +- SQLite3: + . Fixed bug GH-11878 (SQLite3 callback functions cause a memory leak with + a callable array). (nielsdos, arnaud-lb) + 31 Aug 2023, PHP 8.1.23 - CLI: diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index de6d55a3879fb..61159de3f257a 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -2194,6 +2194,42 @@ static void php_sqlite3_object_free_storage(zend_object *object) /* {{{ */ } /* }}} */ +static HashTable *php_sqlite3_get_gc(zend_object *object, zval **table, int *n) +{ + php_sqlite3_db_object *intern = php_sqlite3_db_from_obj(object); + + if (intern->funcs == NULL && intern->collations == NULL) { + /* Fast path without allocations */ + *table = NULL; + *n = 0; + return zend_std_get_gc(object, table, n); + } else { + zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); + + php_sqlite3_func *func = intern->funcs; + while (func != NULL) { + zend_get_gc_buffer_add_zval(gc_buffer, &func->func); + zend_get_gc_buffer_add_zval(gc_buffer, &func->step); + zend_get_gc_buffer_add_zval(gc_buffer, &func->fini); + func = func->next; + } + + php_sqlite3_collation *collation = intern->collations; + while (collation != NULL) { + zend_get_gc_buffer_add_zval(gc_buffer, &collation->cmp_func); + collation = collation->next; + } + + zend_get_gc_buffer_use(gc_buffer, table, n); + + if (object->properties == NULL && object->ce->default_properties_count == 0) { + return NULL; + } else { + return zend_std_get_properties(object); + } + } +} + static void php_sqlite3_stmt_object_free_storage(zend_object *object) /* {{{ */ { php_sqlite3_stmt *intern = php_sqlite3_stmt_from_obj(object); @@ -2327,6 +2363,7 @@ PHP_MINIT_FUNCTION(sqlite3) sqlite3_object_handlers.offset = XtOffsetOf(php_sqlite3_db_object, zo); sqlite3_object_handlers.clone_obj = NULL; sqlite3_object_handlers.free_obj = php_sqlite3_object_free_storage; + sqlite3_object_handlers.get_gc = php_sqlite3_get_gc; php_sqlite3_sc_entry = register_class_SQLite3(); php_sqlite3_sc_entry->create_object = php_sqlite3_object_new; diff --git a/ext/sqlite3/tests/gh11878.phpt b/ext/sqlite3/tests/gh11878.phpt new file mode 100644 index 0000000000000..4a8a408a2679b --- /dev/null +++ b/ext/sqlite3/tests/gh11878.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-11878 (SQLite3 callback functions cause a memory leak with a callable array) +--EXTENSIONS-- +sqlite3 +--FILE-- +sqlite = new SQLite3(":memory:"); + if ($aggregates) { + $this->sqlite->createAggregate("indexes", array($this, "SQLiteIndex"), array($this, "SQLiteFinal"), 0); + } + if ($normalFunctions) { + $this->sqlite->createFunction("func", array($this, "SQLiteIndex"), 0); + $this->sqlite->createCollation("collation", array($this, "SQLiteIndex")); + } + } + public function SQLiteIndex() {} + public function SQLiteFinal() {} +} + +// Test different combinations to check for null pointer derefs +$x = new Foo(true, true); +$y = new Foo(false, true); +$z = new Foo(true, false); +$w = new Foo(false, false); +?> +Done +--EXPECT-- +Done From 107443b311a7fef97ae0815203a956d4c35fdcfe Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 9 Sep 2023 21:17:02 +0200 Subject: [PATCH 36/38] Fix #52751: XPath processing-instruction() function is not supported. Closes GH-12165. --- NEWS | 4 +++ ext/simplexml/simplexml.c | 2 +- ext/simplexml/tests/bug52751.phpt | 58 +++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 ext/simplexml/tests/bug52751.phpt diff --git a/NEWS b/NEWS index a68a41ad39229..d8082b1eb7fda 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,10 @@ PHP NEWS . Fixed persistent procedural ODBC connections not getting closed. (NattyNarwhal) +- SimpleXML: + . Fixed bug #52751 (XPath processing-instruction() function is not + supported). (nielsdos) + - SPL: . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). (nielsdos) diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 8743a068cb6b9..57c0627d61a6a 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1322,7 +1322,7 @@ PHP_METHOD(SimpleXMLElement, xpath) for (i = 0; i < result->nodeNr; ++i) { nodeptr = result->nodeTab[i]; - if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE) { + if (nodeptr->type == XML_TEXT_NODE || nodeptr->type == XML_ELEMENT_NODE || nodeptr->type == XML_ATTRIBUTE_NODE || nodeptr->type == XML_PI_NODE) { /** * Detect the case where the last selector is text(), simplexml * always accesses the text() child by default, therefore we assign diff --git a/ext/simplexml/tests/bug52751.phpt b/ext/simplexml/tests/bug52751.phpt new file mode 100644 index 0000000000000..de5d58e9e632a --- /dev/null +++ b/ext/simplexml/tests/bug52751.phpt @@ -0,0 +1,58 @@ +--TEST-- +Bug #52751 (XPath processing-instruction() function is not supported) +--EXTENSIONS-- +simplexml +--FILE-- + + + text node + + + +XML; + +$sxe = simplexml_load_string($xml); + +var_dump( + $sxe->xpath('//bar') +); + +var_dump( + $sxe->xpath('//processing-instruction(\'baz\')') +); + +foreach ($sxe->xpath('//processing-instruction()') as $pi) { + var_dump($pi->getName()); +} + +?> +--EXPECT-- +array(3) { + [0]=> + object(SimpleXMLElement)#2 (1) { + [0]=> + string(9) "text node" + } + [1]=> + object(SimpleXMLElement)#3 (1) { + ["baz"]=> + object(SimpleXMLElement)#5 (0) { + } + } + [2]=> + object(SimpleXMLElement)#4 (1) { + ["foo"]=> + object(SimpleXMLElement)#5 (0) { + } + } +} +array(1) { + [0]=> + object(SimpleXMLElement)#4 (0) { + } +} +string(3) "baz" +string(3) "foo" From 5286bab392f64519c83979b5562cd0c72559f89c Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 11 Sep 2023 11:32:34 +0200 Subject: [PATCH 37/38] [skip ci] Skip arginfo_zpp_mismatch on asan These tests intermittently crash asan. It might be due to some function invoking dl(), which is known to crash lsan. It might also be something else, the version of asan shipped with ubuntu 22.04 is flaky. --- Zend/tests/arginfo_zpp_mismatch.phpt | 1 + Zend/tests/arginfo_zpp_mismatch_strict.phpt | 1 + 2 files changed, 2 insertions(+) diff --git a/Zend/tests/arginfo_zpp_mismatch.phpt b/Zend/tests/arginfo_zpp_mismatch.phpt index f5df299430090..d7aefc6f374f6 100644 --- a/Zend/tests/arginfo_zpp_mismatch.phpt +++ b/Zend/tests/arginfo_zpp_mismatch.phpt @@ -2,6 +2,7 @@ Test that there is no arginfo/zpp mismatch --SKIPIF-- --FILE-- diff --git a/Zend/tests/arginfo_zpp_mismatch_strict.phpt b/Zend/tests/arginfo_zpp_mismatch_strict.phpt index 8e77af9fb4d01..ddee0bd29cfe4 100644 --- a/Zend/tests/arginfo_zpp_mismatch_strict.phpt +++ b/Zend/tests/arginfo_zpp_mismatch_strict.phpt @@ -2,6 +2,7 @@ Test that there is no arginfo/zpp mismatch in strict mode --SKIPIF-- --FILE-- From 27cdbf67d5715c4f9284067fa9b903d16086ec93 Mon Sep 17 00:00:00 2001 From: Sergey Panteleev Date: Tue, 26 Sep 2023 14:04:28 +0300 Subject: [PATCH 38/38] Update versions for PHP 8.2.11 --- NEWS | 2 +- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index f034b80f3fad1..a42c12273558e 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.11 +28 Sep 2023, PHP 8.2.11 - Core: . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) diff --git a/Zend/zend.h b/Zend/zend.h index eb2105abfa57d..b6d0903be5ce6 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.11-dev" +#define ZEND_VERSION "4.2.11" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index aa32a14e8c9b8..e4d1ec79b6313 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.2.11-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.11],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index afeeec17ccc3e..edfd8085aa707 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 2 #define PHP_RELEASE_VERSION 11 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.11-dev" +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.2.11" #define PHP_VERSION_ID 80211