From 07cbe3083ab55d3b7203c1c2d6f9ca2a3977cd4f Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 27 Feb 2024 23:17:17 +0000 Subject: [PATCH 01/69] Revert "Fix GH-13519: PGSQL_CONNECT_FORCE_RENEW with persistent connections." (#13546) This reverts commit b9a9790be0657249fa5e6687883b43570b0a3f1f. From 47dca339a480f5e41719cdf6cb92925c29d3c53b Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 28 Feb 2024 11:46:49 +0000 Subject: [PATCH 02/69] PHP-8.3 is now for PHP-8.3.5-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 70894828371bd..db72a60512066 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.4 +?? ??? ????, PHP 8.3.5 + + +14 Mar 2024, PHP 8.3.4 - Core: . Fix ZTS persistent resource crashes on shutdown. (nielsdos) diff --git a/Zend/zend.h b/Zend/zend.h index 0d574976542bf..074e1f1680317 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.4-dev" +#define ZEND_VERSION "4.3.5-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 12383bfea1a9c..402c801f21cac 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.3.4-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.5-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 2093b37395a45..e10e9f0a96d1d 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 3 -#define PHP_RELEASE_VERSION 4 +#define PHP_RELEASE_VERSION 5 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.4-dev" -#define PHP_VERSION_ID 80304 +#define PHP_VERSION "8.3.5-dev" +#define PHP_VERSION_ID 80305 From 99688dbe7aeb028a8dd005ef098121e5407ca8dd Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Sun, 18 Feb 2024 21:39:00 +0900 Subject: [PATCH 03/69] Removed `REPORT_EXIT_STATUS=no` in libmysql tests --- .github/actions/test-libmysqlclient/action.yml | 1 - ext/pdo_mysql/tests/gh11550.phpt | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/actions/test-libmysqlclient/action.yml b/.github/actions/test-libmysqlclient/action.yml index e408d0608f1c3..74474225e6705 100644 --- a/.github/actions/test-libmysqlclient/action.yml +++ b/.github/actions/test-libmysqlclient/action.yml @@ -14,7 +14,6 @@ runs: export PDO_MYSQL_TEST_HOST=127.0.0.1 export PDO_MYSQL_TEST_USER=root export PDO_MYSQL_TEST_PASS=root - export REPORT_EXIT_STATUS=no sapi/cli/php run-tests.php -P -q \ -g FAIL,BORK,LEAK,XLEAK \ --no-progress --offline --show-diff --show-slow 1000 --set-timeout 120 \ diff --git a/ext/pdo_mysql/tests/gh11550.phpt b/ext/pdo_mysql/tests/gh11550.phpt index 5bf0b26497ca0..6460a77b6a1bd 100644 --- a/ext/pdo_mysql/tests/gh11550.phpt +++ b/ext/pdo_mysql/tests/gh11550.phpt @@ -13,6 +13,8 @@ MySQLPDOTest::skip(); require_once __DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $pdo = MySQLPDOTest::factory(); +$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); + $pdo->exec(<<<'SQL' CREATE TABLE `test_gh11550` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, @@ -51,9 +53,9 @@ array(1) { [0]=> array(4) { ["id"]=> - int(1) + string(1) "1" [0]=> - int(1) + string(1) "1" ["name"]=> string(5) "test1" [1]=> @@ -66,9 +68,9 @@ array(1) { [0]=> array(6) { ["id"]=> - int(1) + string(1) "1" [0]=> - int(1) + string(1) "1" ["name"]=> string(5) "test1" [1]=> From 116166cd3025c7f4e44089123e2f4d6fe629c1b1 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Thu, 29 Feb 2024 08:49:04 +0900 Subject: [PATCH 04/69] Merge branch 'PHP-8.2' into PHP-8.3 * PHP-8.2: Removed `REPORT_EXIT_STATUS=no` in libmysql tests --- .github/actions/test-libmysqlclient/action.yml | 1 - ext/pdo_mysql/tests/gh11550.phpt | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/actions/test-libmysqlclient/action.yml b/.github/actions/test-libmysqlclient/action.yml index e408d0608f1c3..74474225e6705 100644 --- a/.github/actions/test-libmysqlclient/action.yml +++ b/.github/actions/test-libmysqlclient/action.yml @@ -14,7 +14,6 @@ runs: export PDO_MYSQL_TEST_HOST=127.0.0.1 export PDO_MYSQL_TEST_USER=root export PDO_MYSQL_TEST_PASS=root - export REPORT_EXIT_STATUS=no sapi/cli/php run-tests.php -P -q \ -g FAIL,BORK,LEAK,XLEAK \ --no-progress --offline --show-diff --show-slow 1000 --set-timeout 120 \ diff --git a/ext/pdo_mysql/tests/gh11550.phpt b/ext/pdo_mysql/tests/gh11550.phpt index 5bf0b26497ca0..6460a77b6a1bd 100644 --- a/ext/pdo_mysql/tests/gh11550.phpt +++ b/ext/pdo_mysql/tests/gh11550.phpt @@ -13,6 +13,8 @@ MySQLPDOTest::skip(); require_once __DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'; $pdo = MySQLPDOTest::factory(); +$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); + $pdo->exec(<<<'SQL' CREATE TABLE `test_gh11550` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, @@ -51,9 +53,9 @@ array(1) { [0]=> array(4) { ["id"]=> - int(1) + string(1) "1" [0]=> - int(1) + string(1) "1" ["name"]=> string(5) "test1" [1]=> @@ -66,9 +68,9 @@ array(1) { [0]=> array(6) { ["id"]=> - int(1) + string(1) "1" [0]=> - int(1) + string(1) "1" ["name"]=> string(5) "test1" [1]=> From e059498c043c7325d38d2aa2caa8a5a5dfde4669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 29 Feb 2024 18:05:59 +0100 Subject: [PATCH 05/69] random: Fix unknown `mt_srand()` compatibility for unknown modes (#13544) PHP 8.1 and below interpreted unknown modes as `MT_RAND_MT19937`, but PHP 8.2+ interprets them as `MT_RAND_PHP`. Align the behavior with PHP 8.1 and below, because folks should be steered towards the standard mode. --- NEWS | 4 ++++ ext/random/random.c | 8 ++++++- .../01_functions/mt_srand_unknown_mode.phpt | 22 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 ext/random/tests/01_functions/mt_srand_unknown_mode.phpt diff --git a/NEWS b/NEWS index fa1a89dd1b063..18ebec1081fdd 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,10 @@ PHP NEWS . Fixed bug GH-13354 (pg_execute/pg_send_query_params/pg_send_execute with null value passed by reference). (George Barbarosie) +- Random: + . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with + unknown modes). (timwolla) + - Standard: . Fixed array key as hash to string (case insensitive) comparison typo for the second operand buffer size (albeit unused for now). (A. Slepykh) diff --git a/ext/random/random.c b/ext/random/random.c index dda57f0fe7d35..9f9da28962d15 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -688,7 +688,13 @@ PHP_FUNCTION(mt_srand) Z_PARAM_LONG(mode) ZEND_PARSE_PARAMETERS_END(); - state->mode = mode; + switch (mode) { + case MT_RAND_PHP: + state->mode = MT_RAND_PHP; + break; + default: + state->mode = MT_RAND_MT19937; + } if (ZEND_NUM_ARGS() == 0) { php_random_mt19937_seed_default(status->state); diff --git a/ext/random/tests/01_functions/mt_srand_unknown_mode.phpt b/ext/random/tests/01_functions/mt_srand_unknown_mode.phpt new file mode 100644 index 0000000000000..f4a3cc181ccc8 --- /dev/null +++ b/ext/random/tests/01_functions/mt_srand_unknown_mode.phpt @@ -0,0 +1,22 @@ +--TEST-- +mt_srand(): Test unknown modes +--FILE-- + +--EXPECT-- +int(895547922) +int(1244335972) +int(895547922) +int(895547922) From abfe5ffdedd750e89b8a709b6e49d02fa465067d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 29 Feb 2024 18:21:03 +0100 Subject: [PATCH 06/69] [ci skip] Fix version for GH-13544 in NEWS Apparently PHP 8.2.17 was branched off after creating the PR and before merging it, placing the NEWS in the wrong location. --- NEWS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 18ebec1081fdd..503c841e65551 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - PDO: . Fix various PDORow bugs. (Girgias) +- Random: + . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with + unknown modes). (timwolla) + - SPL: . Fixed bug GH-13531 (Unable to resize SplfixedArray after being unserialized in PHP 8.2.15). (nielsdos) @@ -45,10 +49,6 @@ PHP NEWS . Fixed bug GH-13354 (pg_execute/pg_send_query_params/pg_send_execute with null value passed by reference). (George Barbarosie) -- Random: - . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with - unknown modes). (timwolla) - - Standard: . Fixed array key as hash to string (case insensitive) comparison typo for the second operand buffer size (albeit unused for now). (A. Slepykh) From 7c8a3e426e61072dac54bc8584f22f1ee37b8b00 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 1 Mar 2024 17:44:14 +0100 Subject: [PATCH 07/69] Fix GH-11808: Live filesystem modified by tests (security) There's a test that tries to make /etc world-writable, and asserts that it fails. Although this test is guarded by a root user check, there are situations where you don't need to be root to be able to do this. This may thus have unwanted effects on your live filesystem. The simple solution is to remove that part of the test. It doesn't really add value anyway: we're trying to test the chmod error path, but that exact same error path can be reached with any failure condition that the kernel gives. For example, trying to chmod a non-existent file will trigger the same code path. While at it, also prefix the test path for the non-existent file such that we don't accidentally modify the filesystem. The chroot now has a better root-user check, that will not modify the filesystem. Other root-modifying mkdir tests were removed because they added no value either. Closes GH-13566. --- NEWS | 3 +++ ext/standard/tests/file/006_error.phpt | 25 +++---------------- ext/standard/tests/file/chroot_001.phpt | 18 ++++++++++---- ext/standard/tests/file/mkdir-004.phpt | 32 +++++++++++-------------- ext/standard/tests/file/mkdir-005.phpt | 25 ------------------- ext/standard/tests/file/mkdir-006.phpt | 20 ---------------- 6 files changed, 33 insertions(+), 90 deletions(-) delete mode 100644 ext/standard/tests/file/mkdir-005.phpt delete mode 100644 ext/standard/tests/file/mkdir-006.phpt diff --git a/NEWS b/NEWS index 503c841e65551..3f6a05ade1c06 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,9 @@ PHP NEWS . Fixed bug GH-13531 (Unable to resize SplfixedArray after being unserialized in PHP 8.2.15). (nielsdos) +- Standard: + . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) + - XML: . Fixed bug GH-13517 (Multiple test failures when building with --with-expat). (nielsdos) diff --git a/ext/standard/tests/file/006_error.phpt b/ext/standard/tests/file/006_error.phpt index 98caa4d1e11e2..26c977b9ea5c3 100644 --- a/ext/standard/tests/file/006_error.phpt +++ b/ext/standard/tests/file/006_error.phpt @@ -11,20 +11,9 @@ require __DIR__ . '/../skipif_root.inc'; --FILE-- +recursive mkdir() with unclean paths --FILE-- --EXPECT-- -bool(true) -bool(true) -bool(true) -Done +Ok. diff --git a/ext/standard/tests/file/mkdir-005.phpt b/ext/standard/tests/file/mkdir-005.phpt deleted file mode 100644 index 383f8b18e0527..0000000000000 --- a/ext/standard/tests/file/mkdir-005.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -recursive mkdir() tests ---SKIPIF-- - ---FILE-- - ---EXPECT-- -bool(true) -bool(true) -bool(true) -Done diff --git a/ext/standard/tests/file/mkdir-006.phpt b/ext/standard/tests/file/mkdir-006.phpt deleted file mode 100644 index 1974faa0b6036..0000000000000 --- a/ext/standard/tests/file/mkdir-006.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -recursive mkdir() with unclean paths ---FILE-- - ---EXPECT-- -Ok. From 04e8e55f47db1c209bd3c5f623a12284de44b31c Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Mar 2024 21:30:07 +0900 Subject: [PATCH 08/69] Added validation of `\n` in $additional_headers of mail() When $additional_headers of mail() is an array, the same validation as `\r\n` is now applied to `\n` alone too. --- NEWS | 2 + UPGRADING | 2 + ext/standard/mail.c | 53 ++++++++++++++++++++---- ext/standard/php_mail.h | 7 ++++ ext/standard/tests/mail/gh13415.phpt | 52 +++++++++++++++++++++++ ext/standard/tests/mail/mail_basic7.phpt | 2 +- 6 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 ext/standard/tests/mail/gh13415.phpt diff --git a/NEWS b/NEWS index 3f6a05ade1c06..2f32dd10f9f39 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ PHP NEWS - Standard: . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) + . Fixed GH-13402: Added validation of `\n` in `$additional_headers` of `mail()` + (SakiTakamachi) - XML: . Fixed bug GH-13517 (Multiple test failures when building with diff --git a/UPGRADING b/UPGRADING index b025364400f4b..efa74cb42cf9d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -243,6 +243,8 @@ PHP 8.2 UPGRADE NOTES objects. . mail() function reverts back to the mixed LF and CRLF new lines (behavior before PHP 8.0) if mail.mixed_lf_and_crlf INI is on. + . When $additional_headers of mail() is an array, the same validation as + `\r\n` is now applied to `\n` alone too. - XML . xml_parser_set_option() now actually returns false when attempting to set a diff --git a/ext/standard/mail.c b/ext/standard/mail.c index 0323341c3d605..0ddec8d723137 100644 --- a/ext/standard/mail.c +++ b/ext/standard/mail.c @@ -57,7 +57,7 @@ extern zend_long php_getuid(void); -static bool php_mail_build_headers_check_field_value(zval *val) +static php_mail_header_value_error_type php_mail_build_headers_check_field_value(zval *val) { size_t len = 0; zend_string *value = Z_STR_P(val); @@ -66,20 +66,39 @@ static bool php_mail_build_headers_check_field_value(zval *val) /* https://tools.ietf.org/html/rfc2822#section-2.2.3 */ while (len < value->len) { if (*(value->val+len) == '\r') { + if (*(value->val+len+1) != '\n') { + return CONTAINS_CR_ONLY; + } + if (value->len - len >= 3 - && *(value->val+len+1) == '\n' && (*(value->val+len+2) == ' ' || *(value->val+len+2) == '\t')) { len += 3; continue; } - return FAILURE; + + return CONTAINS_CRLF; + } + /** + * The RFC does not allow using LF alone for folding. However, LF is + * often treated similarly to CRLF, and there are likely many user + * environments that use LF for folding. + * Therefore, considering such an environment, folding with LF alone + * is allowed. + */ + if (*(value->val+len) == '\n') { + if (value->len - len >= 2 + && (*(value->val+len+1) == ' ' || *(value->val+len+1) == '\t')) { + len += 2; + continue; + } + return CONTAINS_LF_ONLY; } if (*(value->val+len) == '\0') { - return FAILURE; + return CONTAINS_NULL; } len++; } - return SUCCESS; + return NO_HEADER_ERROR; } @@ -108,9 +127,27 @@ static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *va zend_value_error("Header name \"%s\" contains invalid characters", ZSTR_VAL(key)); return; } - if (php_mail_build_headers_check_field_value(val) != SUCCESS) { - zend_value_error("Header \"%s\" has invalid format, or contains invalid characters", ZSTR_VAL(key)); - return; + + php_mail_header_value_error_type error_type = php_mail_build_headers_check_field_value(val); + switch (error_type) { + case NO_HEADER_ERROR: + break; + case CONTAINS_LF_ONLY: + zend_value_error("Header \"%s\" contains LF character that is not allowed in the header", ZSTR_VAL(key)); + return; + case CONTAINS_CR_ONLY: + zend_value_error("Header \"%s\" contains CR character that is not allowed in the header", ZSTR_VAL(key)); + return; + case CONTAINS_CRLF: + zend_value_error("Header \"%s\" contains CRLF characters that are used as a line separator and are not allowed in the header", ZSTR_VAL(key)); + return; + case CONTAINS_NULL: + zend_value_error("Header \"%s\" contains NULL character that is not allowed in the header", ZSTR_VAL(key)); + return; + default: + // fallback + zend_value_error("Header \"%s\" has invalid format, or contains invalid characters", ZSTR_VAL(key)); + return; } smart_str_append(s, key); smart_str_appendl(s, ": ", 2); diff --git a/ext/standard/php_mail.h b/ext/standard/php_mail.h index 4e2f57749dd90..509233692e051 100644 --- a/ext/standard/php_mail.h +++ b/ext/standard/php_mail.h @@ -49,5 +49,12 @@ do { \ } \ } while(0) +typedef enum { + NO_HEADER_ERROR, + CONTAINS_LF_ONLY, + CONTAINS_CR_ONLY, + CONTAINS_CRLF, + CONTAINS_NULL +} php_mail_header_value_error_type; #endif /* PHP_MAIL_H */ diff --git a/ext/standard/tests/mail/gh13415.phpt b/ext/standard/tests/mail/gh13415.phpt new file mode 100644 index 0000000000000..f507259a8e267 --- /dev/null +++ b/ext/standard/tests/mail/gh13415.phpt @@ -0,0 +1,52 @@ +--TEST-- +GH-13415 (Added validation of line breaks \n in $additional_headers of mail()) +--INI-- +sendmail_path={MAIL:gh13415.out} +--FILE-- + "foo@example.com \nCc: hacker@example.com"]); +} catch (Throwable $e) { + echo $e->getMessage()."\n\n"; +} + +echo "CR only:\n"; +try { + mail('to@example.com', 'Test Subject', 'A Message', ['Reply-To' => "foo@example.com \rCc: hacker@example.com"]); +} catch (Throwable $e) { + echo $e->getMessage()."\n\n"; +} + +echo "CRLF:\n"; +try { + mail('to@example.com', 'Test Subject', 'A Message', ['Reply-To' => "foo@example.com \r\nCc: hacker@example.com"]); +} catch (Throwable $e) { + echo $e->getMessage()."\n\n"; +} + +echo "NULL:\n"; +try { + mail('to@example.com', 'Test Subject', 'A Message', ['Reply-To' => "foo@example.com \0Cc: hacker@example.com"]); +} catch (Throwable $e) { + echo $e->getMessage()."\n\n"; +} +?> +--CLEAN-- + +--EXPECTF-- +LF only: +Header "Reply-To" contains LF character that is not allowed in the header + +CR only: +Header "Reply-To" contains CR character that is not allowed in the header + +CRLF: +Header "Reply-To" contains CRLF characters that are used as a line separator and are not allowed in the header + +NULL: +Header "Reply-To" contains NULL character that is not allowed in the header diff --git a/ext/standard/tests/mail/mail_basic7.phpt b/ext/standard/tests/mail/mail_basic7.phpt index 47614c011eb76..d0c77f0d8f592 100644 --- a/ext/standard/tests/mail/mail_basic7.phpt +++ b/ext/standard/tests/mail/mail_basic7.phpt @@ -258,4 +258,4 @@ Subject: Test Subject foo9: %&$#! A Message -ValueError: Header "foo10" has invalid format, or contains invalid characters +ValueError: Header "foo10" contains NULL character that is not allowed in the header From 6bcce681ef3e57777da05b7cf28801c61f27ea38 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Mar 2024 21:50:37 +0900 Subject: [PATCH 09/69] [skip ci] Fixed NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2f32dd10f9f39..a8afd0b7bde8e 100644 --- a/NEWS +++ b/NEWS @@ -15,7 +15,7 @@ PHP NEWS - Standard: . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) - . Fixed GH-13402: Added validation of `\n` in `$additional_headers` of `mail()` + . Fixed GH-13402 (Added validation of `\n` in $additional_headers of mail()). (SakiTakamachi) - XML: From 29a39eb782f8cf74642152e0e62b5ef6da78301d Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Mar 2024 21:51:02 +0900 Subject: [PATCH 10/69] Fixed handshake response charset. (#13470) The character set ID included in the handshake data at the time of connection actually only includes the lower 8 bits of the ID, so if try to use this to specify a character set, the corresponding character set may not exist. In case of an invalid character set, the default character set is now used without an error. Fixes #13452 Closes #13470 --- NEWS | 3 +++ ext/mysqlnd/mysqlnd_charset.h | 3 +++ ext/mysqlnd/mysqlnd_commands.c | 14 +++++++------- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index a8afd0b7bde8e..c7be80af5607e 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.18 +- MySQLnd: + . Fix GH-13452 (Fixed handshake response [mysqlnd]). (Saki Takamachi) + - PDO: . Fix various PDORow bugs. (Girgias) diff --git a/ext/mysqlnd/mysqlnd_charset.h b/ext/mysqlnd/mysqlnd_charset.h index d7f8053dd8606..a2b1e2f148316 100644 --- a/ext/mysqlnd/mysqlnd_charset.h +++ b/ext/mysqlnd/mysqlnd_charset.h @@ -19,6 +19,9 @@ #ifndef MYSQLND_CHARSET_H #define MYSQLND_CHARSET_H +#define MYSQLND_UTF8_MB3_DEFAULT_ID 33 +#define MYSQLND_UTF8_MB4_DEFAULT_ID 45 + PHPAPI zend_ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char * newstr, const char * escapestr, const size_t escapestr_len); diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index ae64560850531..a02665976851b 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -22,6 +22,7 @@ #include "mysqlnd_auth.h" #include "mysqlnd_wireprotocol.h" #include "mysqlnd_debug.h" +#include "mysqlnd_charset.h" /* {{{ mysqlnd_command::set_option */ @@ -642,13 +643,12 @@ MYSQLND_METHOD(mysqlnd_command, handshake)(MYSQLND_CONN_DATA * const conn, const conn->protocol_version = greet_packet.protocol_version; conn->server_version = mnd_pestrdup(greet_packet.server_version, conn->persistent); - conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no); - if (!conn->greet_charset) { - char * msg; - mnd_sprintf(&msg, 0, "Server sent charset (%d) unknown to the client. Please, report to the developers", greet_packet.charset_no); - SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg); - mnd_sprintf_free(msg); - goto err; + const MYSQLND_CHARSET *read_charset = mysqlnd_find_charset_nr(greet_packet.charset_no); + if (!read_charset) { + greet_packet.charset_no = conn->m->get_server_version(conn) >= 50500 ? MYSQLND_UTF8_MB4_DEFAULT_ID : MYSQLND_UTF8_MB3_DEFAULT_ID; + conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no); + } else { + conn->greet_charset = read_charset; } conn->server_capabilities = greet_packet.server_capabilities; From 7466f9c99c4864fc17900f434b298c1deac9cb58 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Mar 2024 21:51:02 +0900 Subject: [PATCH 11/69] Fixed handshake response charset. (#13470) The character set ID included in the handshake data at the time of connection actually only includes the lower 8 bits of the ID, so if try to use this to specify a character set, the corresponding character set may not exist. In case of an invalid character set, the default character set is now used without an error. Fixes #13452 Closes #13470 --- ext/mysqlnd/mysqlnd_charset.h | 3 +++ ext/mysqlnd/mysqlnd_commands.c | 14 +++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ext/mysqlnd/mysqlnd_charset.h b/ext/mysqlnd/mysqlnd_charset.h index d7f8053dd8606..a2b1e2f148316 100644 --- a/ext/mysqlnd/mysqlnd_charset.h +++ b/ext/mysqlnd/mysqlnd_charset.h @@ -19,6 +19,9 @@ #ifndef MYSQLND_CHARSET_H #define MYSQLND_CHARSET_H +#define MYSQLND_UTF8_MB3_DEFAULT_ID 33 +#define MYSQLND_UTF8_MB4_DEFAULT_ID 45 + PHPAPI zend_ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char * newstr, const char * escapestr, const size_t escapestr_len); diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index ba214e5ff776a..27a5f13a30746 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -22,6 +22,7 @@ #include "mysqlnd_auth.h" #include "mysqlnd_wireprotocol.h" #include "mysqlnd_debug.h" +#include "mysqlnd_charset.h" /* {{{ mysqlnd_command::set_option */ @@ -613,13 +614,12 @@ MYSQLND_METHOD(mysqlnd_command, handshake)(MYSQLND_CONN_DATA * const conn, const conn->protocol_version = greet_packet.protocol_version; conn->server_version = mnd_pestrdup(greet_packet.server_version, conn->persistent); - conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no); - if (!conn->greet_charset) { - char * msg; - mnd_sprintf(&msg, 0, "Server sent charset (%d) unknown to the client. Please, report to the developers", greet_packet.charset_no); - SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, msg); - mnd_sprintf_free(msg); - goto err; + const MYSQLND_CHARSET *read_charset = mysqlnd_find_charset_nr(greet_packet.charset_no); + if (!read_charset) { + greet_packet.charset_no = conn->m->get_server_version(conn) >= 50500 ? MYSQLND_UTF8_MB4_DEFAULT_ID : MYSQLND_UTF8_MB3_DEFAULT_ID; + conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no); + } else { + conn->greet_charset = read_charset; } conn->server_capabilities = greet_packet.server_capabilities; From 72779e6d64139d723c19857694a094c37e7a2e36 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Mon, 4 Mar 2024 21:53:09 +0900 Subject: [PATCH 12/69] NEWS --- NEWS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 2b46b639a9b01..1c9d7e4f51117 100644 --- a/NEWS +++ b/NEWS @@ -2,12 +2,17 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.5 +- MySQLnd: + . Fix GH-13452 (Fixed handshake response [mysqlnd]). (Saki Takamachi) + - Random: . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with unknown modes). (timwolla) - Standard: . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) + . Fixed GH-13402 (Added validation of `\n` in $additional_headers of mail()). + (SakiTakamachi) 14 Mar 2024, PHP 8.3.4 From 9999a0cb757344974889a6f548727de6f2c3c10d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 28 Feb 2024 22:43:04 +0000 Subject: [PATCH 13/69] ext/gettext: dcgettext/dcngettext sigabrt on macOs. the man page states `the locale facet is determined by the category argument, which should be one of the LC_xxx constants defined in the header, excluding LC_ALL`, since the 0.22.5 release, sanity checks had been strenghtened leading to an abort with the Zend/tests/arginfo_zpp_mismatch.phpt test setting the category to 0 which is LC_ALL on macOs. close GH-13555 --- NEWS | 4 ++++ UPGRADING | 4 ++++ ext/gettext/gettext.c | 9 +++++++++ ext/gettext/tests/dcgettext_lcall.phpt | 21 +++++++++++++++++++++ ext/gettext/tests/dcngettext.phpt | 4 ++-- 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 ext/gettext/tests/dcgettext_lcall.phpt diff --git a/NEWS b/NEWS index c7be80af5607e..2de10b7bc03e2 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.18 +- Gettext: + - Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 + with category set to LC_ALL. (David Carlier) + - MySQLnd: . Fix GH-13452 (Fixed handshake response [mysqlnd]). (Saki Takamachi) diff --git a/UPGRADING b/UPGRADING index efa74cb42cf9d..de91433d8d2b4 100644 --- a/UPGRADING +++ b/UPGRADING @@ -218,6 +218,10 @@ PHP 8.2 UPGRADE NOTES dba_fetch(string|array $key, $skip, $dba): string|false is still accepted, but it is recommended to use the new standard variant. +- Gettext: + . dcgettext/dcngettext throw now an exception if the category's argument if set to + `LC_ALL`. + - MBString . mb_check_encoding() now checks input encoding more strictly for certain text encodings, including ISO-2022-JP and UTF-7. diff --git a/ext/gettext/gettext.c b/ext/gettext/gettext.c index 05f41552c63fc..e7928795b279d 100644 --- a/ext/gettext/gettext.c +++ b/ext/gettext/gettext.c @@ -23,6 +23,7 @@ #ifdef HAVE_LIBINTL #include +#include #include "ext/standard/info.h" #include "php_gettext.h" #include "gettext_arginfo.h" @@ -61,6 +62,12 @@ ZEND_GET_MODULE(php_gettext) RETURN_THROWS(); \ } +#define PHP_DCGETTEXT_CATEGORY_CHECK(_arg_num, category) \ + if (category == LC_ALL) { \ + zend_argument_value_error(_arg_num, "cannot be LC_ALL"); \ + RETURN_THROWS(); \ + } + PHP_MINFO_FUNCTION(php_gettext) { php_info_print_table_start(); @@ -146,6 +153,7 @@ PHP_FUNCTION(dcgettext) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain)) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid)) + PHP_DCGETTEXT_CATEGORY_CHECK(3, category) msgstr = dcgettext(ZSTR_VAL(domain), ZSTR_VAL(msgid), category); @@ -260,6 +268,7 @@ PHP_FUNCTION(dcngettext) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, domain_len) PHP_GETTEXT_LENGTH_CHECK(2, msgid1_len) PHP_GETTEXT_LENGTH_CHECK(3, msgid2_len) + PHP_DCGETTEXT_CATEGORY_CHECK(5, category) msgstr = dcngettext(domain, msgid1, msgid2, count, category); diff --git a/ext/gettext/tests/dcgettext_lcall.phpt b/ext/gettext/tests/dcgettext_lcall.phpt new file mode 100644 index 0000000000000..004ae89409eca --- /dev/null +++ b/ext/gettext/tests/dcgettext_lcall.phpt @@ -0,0 +1,21 @@ +--TEST-- +dcgettext with LC_ALL is undefined behavior. +--EXTENSIONS-- +gettext +--FILE-- +getMessage() . PHP_EOL; +} + +try { + dcngettext('dngettextTest', 'item', 'item2', 1, LC_ALL); +} catch (ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +dcgettext(): Argument #3 ($category) cannot be LC_ALL +dcngettext(): Argument #5 ($category) cannot be LC_ALL diff --git a/ext/gettext/tests/dcngettext.phpt b/ext/gettext/tests/dcngettext.phpt index 715281ec8296b..2f356b1cf0c6a 100644 --- a/ext/gettext/tests/dcngettext.phpt +++ b/ext/gettext/tests/dcngettext.phpt @@ -11,10 +11,10 @@ if (!function_exists("dcngettext")) die("skip dcngettext() doesn't exist"); var_dump(dcngettext(1,1,1,1,1)); var_dump(dcngettext("test","test","test",1,1)); -var_dump(dcngettext("test","test","test",0,0)); +var_dump(dcngettext("test","test","test",0,1)); var_dump(dcngettext("test","test","test",-1,-1)); var_dump(dcngettext("","","",1,1)); -var_dump(dcngettext("","","",0,0)); +var_dump(dcngettext("","","",0,1)); echo "Done\n"; ?> From 5e12844d4d0053f3c3f1b20635efdb6f30e85190 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Thu, 29 Feb 2024 10:52:54 +0100 Subject: [PATCH 14/69] Fix GH-13217 Test failure with zlib-ng As compressed result may be different - drop or relax expectations on compressed data - rely on uncompressed result of compressed data --- ext/zlib/tests/bug48725_2.phpt | 4 +- ext/zlib/tests/bug71417.phpt | 2 +- ext/zlib/tests/gzcompress_basic1.phpt | 29 +--------- ext/zlib/tests/gzcompress_variation1.phpt | 10 ++-- ext/zlib/tests/gzdeflate_basic1.phpt | 29 +--------- ext/zlib/tests/gzdeflate_variation1.phpt | 10 ++-- ext/zlib/tests/gzencode_basic1.phpt | 67 ++++++++++------------- ext/zlib/tests/gzencode_variation1.phpt | 4 +- ext/zlib/tests/gzinflate-bug42663.phpt | 2 +- ext/zlib/tests/zlib_filter_deflate.phpt | 4 +- 10 files changed, 54 insertions(+), 107 deletions(-) diff --git a/ext/zlib/tests/bug48725_2.phpt b/ext/zlib/tests/bug48725_2.phpt index 3481983e859b6..67b584719d1e1 100644 --- a/ext/zlib/tests/bug48725_2.phpt +++ b/ext/zlib/tests/bug48725_2.phpt @@ -7,7 +7,7 @@ zlib $stream = fopen('data://text/plain;base64,' . base64_encode('Foo bar baz'), 'r'); stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_READ); -print bin2hex(stream_get_contents($stream)); +print gzinflate(stream_get_contents($stream)); ?> --EXPECT-- -72cbcf57484a2c02e22a00000000ffff0300 +Foo bar baz diff --git a/ext/zlib/tests/bug71417.phpt b/ext/zlib/tests/bug71417.phpt index eac0d7efed1de..8d871a329e7fe 100644 --- a/ext/zlib/tests/bug71417.phpt +++ b/ext/zlib/tests/bug71417.phpt @@ -75,7 +75,7 @@ read: bool(false) gzdecode(): Warning: gzdecode(): data error in %s on line %d -read: string(32) "The quick brown fox jumps over t" +read: string(3%d) "The quick brown fox jumps over%s" gzdecode(): Warning: gzdecode(): data error in %s on line %d diff --git a/ext/zlib/tests/gzcompress_basic1.phpt b/ext/zlib/tests/gzcompress_basic1.phpt index b5ad22341ed74..b37aebe33d704 100644 --- a/ext/zlib/tests/gzcompress_basic1.phpt +++ b/ext/zlib/tests/gzcompress_basic1.phpt @@ -25,7 +25,6 @@ $smallstring = "A small string to compress\n"; for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzcompress($data, $i); - var_dump(md5($output)); var_dump(strcmp(gzuncompress($output), $data)); } @@ -33,83 +32,61 @@ for($i = -1; $i < 10; $i++) { for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzcompress($smallstring, $i); - var_dump(bin2hex($output)); var_dump(strcmp(gzuncompress($output), $smallstring)); } // Calling gzcompress() with mandatory arguments echo "\n-- Testing with no specified compression level --\n"; -var_dump( bin2hex(gzcompress($smallstring) )); +$output = gzcompress($smallstring); + var_dump(strcmp(gzuncompress($output), $smallstring)); ?> --EXPECT-- *** Testing gzcompress() : basic functionality *** -- Compression level -1 -- -string(32) "764809aef15bb34cb73ad49ecb600d99" int(0) -- Compression level 0 -- -string(32) "d0136b3fb5424142c0eb26dfec8f56fe" int(0) -- Compression level 1 -- -string(32) "c2e070f4320d1f674965eaab95b53d9c" int(0) -- Compression level 2 -- -string(32) "36922f486410d08209d0d0d21b26030e" int(0) -- Compression level 3 -- -string(32) "a441a2f5169bb303cd45b860a5a9dbf9" int(0) -- Compression level 4 -- -string(32) "d5b7451e9de2864beccc9de1fc55eb87" int(0) -- Compression level 5 -- -string(32) "32ba4a01120449ec25508cabfad41f56" int(0) -- Compression level 6 -- -string(32) "764809aef15bb34cb73ad49ecb600d99" int(0) -- Compression level 7 -- -string(32) "e083e7e8d05471fed3c2182b9cd0d9eb" int(0) -- Compression level 8 -- -string(32) "e083e7e8d05471fed3c2182b9cd0d9eb" int(0) -- Compression level 9 -- -string(32) "e083e7e8d05471fed3c2182b9cd0d9eb" int(0) -- Compression level -1 -- -string(70) "789c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 0 -- -string(76) "7801011b00e4ff4120736d616c6c20737472696e6720746f20636f6d70726573730a87a509cb" int(0) -- Compression level 1 -- -string(70) "7801735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 2 -- -string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 3 -- -string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 4 -- -string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 5 -- -string(70) "785e735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 6 -- -string(70) "789c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 7 -- -string(70) "78da735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 8 -- -string(70) "78da735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Compression level 9 -- -string(70) "78da735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" int(0) -- Testing with no specified compression level -- -string(70) "789c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee6020087a509cb" +int(0) diff --git a/ext/zlib/tests/gzcompress_variation1.phpt b/ext/zlib/tests/gzcompress_variation1.phpt index ce64b5e1a29a5..81dafa737c305 100644 --- a/ext/zlib/tests/gzcompress_variation1.phpt +++ b/ext/zlib/tests/gzcompress_variation1.phpt @@ -10,13 +10,13 @@ echo "*** Testing gzcompress() : variation ***\n"; echo "\n-- Testing multiple compression --\n"; $output = gzcompress($data); -var_dump( md5($output)); -var_dump(md5(gzcompress($output))); +var_dump(strlen($output)); +var_dump(strlen(gzcompress($output))); ?> ---EXPECT-- +--EXPECTF-- *** Testing gzcompress() : variation *** -- Testing multiple compression -- -string(32) "764809aef15bb34cb73ad49ecb600d99" -string(32) "eba942bc2061f23ea8688cc5101872a4" +int(1%d) +int(1%d) diff --git a/ext/zlib/tests/gzdeflate_basic1.phpt b/ext/zlib/tests/gzdeflate_basic1.phpt index 73eb9af3a4b73..0945783800118 100644 --- a/ext/zlib/tests/gzdeflate_basic1.phpt +++ b/ext/zlib/tests/gzdeflate_basic1.phpt @@ -25,7 +25,6 @@ $smallstring = "A small string to compress\n"; for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzdeflate($data, $i); - var_dump(md5($output)); var_dump(strcmp(gzinflate($output), $data)); } @@ -33,83 +32,61 @@ for($i = -1; $i < 10; $i++) { for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzdeflate($smallstring, $i); - var_dump(bin2hex($output)); var_dump(strcmp(gzinflate($output), $smallstring)); } // Calling gzdeflate() with just mandatory arguments echo "\n-- Testing with no specified compression level --\n"; -var_dump( bin2hex(gzdeflate($smallstring) )); +$output = gzdeflate($smallstring); +var_dump(strcmp(gzinflate($output), $smallstring)); ?> --EXPECT-- *** Testing gzdeflate() : basic functionality *** -- Compression level -1 -- -string(32) "078554fe65e06f6ff01eab51cfc7ae9b" int(0) -- Compression level 0 -- -string(32) "a71e54d2499aff9e48643cb1c260b60c" int(0) -- Compression level 1 -- -string(32) "05e80f4dc0d422e1f333cbed555d381f" int(0) -- Compression level 2 -- -string(32) "0fb33656e4ed0750f977df83246fce7a" int(0) -- Compression level 3 -- -string(32) "bc6e9c1dccc3e951e006315ee669ee08" int(0) -- Compression level 4 -- -string(32) "a61727d7a28c634470eb6e97a4a81b24" int(0) -- Compression level 5 -- -string(32) "a2a1a14b7542c82e8943200d093d5f27" int(0) -- Compression level 6 -- -string(32) "078554fe65e06f6ff01eab51cfc7ae9b" int(0) -- Compression level 7 -- -string(32) "078554fe65e06f6ff01eab51cfc7ae9b" int(0) -- Compression level 8 -- -string(32) "078554fe65e06f6ff01eab51cfc7ae9b" int(0) -- Compression level 9 -- -string(32) "078554fe65e06f6ff01eab51cfc7ae9b" int(0) -- Compression level -1 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 0 -- -string(64) "011b00e4ff4120736d616c6c20737472696e6720746f20636f6d70726573730a" int(0) -- Compression level 1 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 2 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 3 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 4 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 5 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 6 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 7 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 8 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Compression level 9 -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" int(0) -- Testing with no specified compression level -- -string(58) "735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200" +int(0) diff --git a/ext/zlib/tests/gzdeflate_variation1.phpt b/ext/zlib/tests/gzdeflate_variation1.phpt index 93de54075f5b4..21456a9887659 100644 --- a/ext/zlib/tests/gzdeflate_variation1.phpt +++ b/ext/zlib/tests/gzdeflate_variation1.phpt @@ -12,13 +12,13 @@ echo "*** Testing gzdeflate() : variation ***\n"; echo "\n-- Testing multiple compression --\n"; $output = gzdeflate($data); -var_dump( md5($output)); -var_dump(md5(gzdeflate($output))); +var_dump(strlen($output)); +var_dump(strlen(gzdeflate($output))); ?> ---EXPECT-- +--EXPECTF-- *** Testing gzdeflate() : variation *** -- Testing multiple compression -- -string(32) "078554fe65e06f6ff01eab51cfc7ae9b" -string(32) "86b9f895ef1377da5269ec3cb2729f71" +int(17%d) +int(17%d) diff --git a/ext/zlib/tests/gzencode_basic1.phpt b/ext/zlib/tests/gzencode_basic1.phpt index 346c5b4aa8362..751c21532055e 100644 --- a/ext/zlib/tests/gzencode_basic1.phpt +++ b/ext/zlib/tests/gzencode_basic1.phpt @@ -25,81 +25,74 @@ $smallstring = "A small string to compress\n"; for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzencode($data, $i); - - // Clear OS byte before encode - $output[9] = "\x00"; - - var_dump(md5($output)); + var_dump(strcmp(gzdecode($output), $data)===0); } // Compressing a smaller string for($i = -1; $i < 10; $i++) { echo "-- Compression level $i --\n"; $output = gzencode($smallstring, $i); - - // Clear OS byte before encode - $output[9] = "\x00"; - - var_dump(md5($output)); + var_dump(strcmp(gzdecode($output), $smallstring)===0); } // Calling gzencode() with mandatory arguments echo "\n-- Testing with no specified compression level --\n"; -var_dump(bin2hex(gzencode($smallstring))); +$output = gzencode($smallstring); +var_dump(strcmp(gzdecode($output), $smallstring)===0); echo "\n-- Testing gzencode with mode specified --\n"; -var_dump(bin2hex(gzencode($smallstring, -1, FORCE_GZIP))); - +$outupt = gzencode($smallstring, -1, FORCE_GZIP); +var_dump(strcmp(gzdecode($output), $smallstring)===0); ?> --EXPECTF-- *** Testing gzencode() : basic functionality *** -- Compression level -1 -- -string(32) "d9ede02415ce91d21e5a94274e2b9c42" +bool(true) -- Compression level 0 -- -string(32) "bbf32d5508e5f1f4e6d42790489dae15" +bool(true) -- Compression level 1 -- -string(32) "0bfaaa7a5a57f8fb533074fca6c85eeb" +bool(true) -- Compression level 2 -- -string(32) "7ddbfed63a76c42808722b66f1c133fc" +bool(true) -- Compression level 3 -- -string(32) "ca2b85d194dfa2a4e8a162b646c99265" +bool(true) -- Compression level 4 -- -string(32) "cfe28033eaf260bc33ddc04b53d3ba39" +bool(true) -- Compression level 5 -- -string(32) "ae357fada2b515422f8bea0aa3bcc48f" +bool(true) -- Compression level 6 -- -string(32) "d9ede02415ce91d21e5a94274e2b9c42" +bool(true) -- Compression level 7 -- -string(32) "d9ede02415ce91d21e5a94274e2b9c42" +bool(true) -- Compression level 8 -- -string(32) "d9ede02415ce91d21e5a94274e2b9c42" +bool(true) -- Compression level 9 -- -string(32) "0f220a09e9895bcb3a1308d2bc99cfdf" +bool(true) -- Compression level -1 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 0 -- -string(32) "9c5005db88490d6fe102ea2c233b2872" +bool(true) -- Compression level 1 -- -string(32) "d24ff7c4c20cef69b9c3abd603368db9" +bool(true) -- Compression level 2 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 3 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 4 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 5 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 6 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 7 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 8 -- -string(32) "f77bd31e1e4dd11d12828fb661a08010" +bool(true) -- Compression level 9 -- -string(32) "8849e9a1543c04b3f882b5ce20839ed2" +bool(true) -- Testing with no specified compression level -- -string(94) "1f8b08000000000000%c%c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200edc4e40b1b000000" +bool(true) -- Testing gzencode with mode specified -- -string(94) "1f8b08000000000000%c%c735428ce4dccc951282e29cacc4b5728c95748cecf2d284a2d2ee60200edc4e40b1b000000" +bool(true) diff --git a/ext/zlib/tests/gzencode_variation1.phpt b/ext/zlib/tests/gzencode_variation1.phpt index 288c14a0b39d4..bbc6dc0c6a8cf 100644 --- a/ext/zlib/tests/gzencode_variation1.phpt +++ b/ext/zlib/tests/gzencode_variation1.phpt @@ -26,8 +26,8 @@ $output = gzencode($data); var_dump(bin2hex(gzencode($output))); ?> ---EXPECT-- +--EXPECTF-- *** Testing gzencode() : variation *** -- Testing multiple compression -- -string(3658) "1f8b0800000000000003010e07f1f81f8b08000000000000036d574d6fe4c80dbdeb57d4ad2f3dfe01eb83e1ec22980e309b4562c067b64449159754dafab0b6e7d7e73d96da1e4c72184c4b2ab2c8f7c847fa25baabba98dc1a8b2b7c38bb324b713ee37f757f56cdc5c7f5b17b9d152f923b157c5ae335e0b75fedd0e2d781c6b98ea3a6ee05affe1dfc3a6527f8f09c52dcb38ba38bb5249934d6ecfe1e53a9ab76ff4c342cf2a64ed2028349fc9a8b139755685352acb82b9fbb67f8bade5cdcb698e1fcec94b7ceba3cb897e806cfc8114350dd1ebbdfa35b62d2478b0056d23ed809b9b95d696d91ce2aa97c911e3fa539c43f84c887554a4d125c9e63ff96711cc08c0866263cb37a0bbe2122ae8f6baecb2284abfb4ddf916db8354cddeef37c1afe5fa02fc7afb3db34f5b3acbdf2eb905490d8f38d7468d253a323d5ebb903760d7944d3b2024e834a99ddce77669bdd823cfbb8e899d4ad4c799677452e6029e80023a03b2374005590641f7d3877df2ad09f3c0e82a54d6a5644fd63049a37ed4bc362016fd9f51264f1e5c630727421ae930b7ed416e93e47b7c71a400390361ffbecb7561bb98f69b5da289e91becc27f08b3b724cb8704f9144d366431d0cb870c56b205deaa2e17636063761a911039fb7e4bf9f06c4f0aecd2ec80e8b41831ca7515e31286166458ea3ef71f2ce7cde2ae269c96d60525724a9c9170b713ed5750758f3cd2a361fc8b288fc92358ce884692e8ea0fe59bd969a0da2eed5831b715749eaae7178f3ebd30fb88c92105f367cce2c882955dc6bf8eca0d5d57540b3092894743ba0fd5b2dad021836191f1afc0bba14dde1642cb0b1aa6879c38907dcefa0720082b801bec61417469219175267dfa047df35b0bd1332001c28cdfafd3bcabe91e74368cdd8d8478e494c190e7ee90c67f2bde288e68ab6b15e883c995be4f8feb6c6dda4278e4f38578ddbdc7be36788daf0c3cb1d1819c73822f7000a0d1813fa94153b572315e51343b536bc64977dff163cebfd8418773261f524017e251fccc60ae29a5770ae097594d52e9c1229d87ce967a36401c46b69945afb249d101c9d420ffa9a123e232c20e76467d5d169202a2dd4c582949e013e745df7958d4b0cc4fd4377a737cd4feea7974070000f314d423e0634cb9a618fdf5dc64fd422181fd59c9230c9f6f9d18dc8fc23e9cccbc7188733b04aa57de83ebea0be3633cff5fa1ff83269be7f44f5a8d84550cc703255fd345dd402034d0b3e11a73ec6e3d4a77f4f685b614329f1b3132ae7af33d02e1e55e291fa6574b758d1f0200e7423dbc852211818043a7c9ce80aa9d59fce0401959f5ea2cf71fde90824f8c9192dbe9d329db143794675ddcf257dd7755273b67340414e3ccad12e3f661f8aad9cf9957dc1275d10a51d3934fa81e68dc6768fb8ee23e373936c8e13feab8b0f50d227f7af76f561fb0950f3d099bbc316c3892a42fb36806d8660e800fa4f43fd4b962d2097d71933a54b77ff948677848eb17bb3a88b621682cfb3bbb49cf42fed6b3944124ad8358ca688aa44dd5f2144c7c9ab16f25b9aca9654ef357ec9ad55c40d324d6cc3d9e3920b863c231d31a95d937fb5520f9c816c79b7dcecc593fb9593cc05a51ebb1eeddd5b49eb437769738d0f64adc579d372b8b7f7c0208487ee3915ebf5766e148ebd77cf4e01f3ec285047011e55838968b6494d517fe29224777b24dd3ddf933101695b102e87db805eef291b74dcfd91628fb2a53f93dbd2968ef2e598746c9204f89fba1f0246fc671610a0591806e46a1346f77c40d910a47c5e20ffb23f003c04b648327a4ed98032c1965bd35bb0044f5344248f56fdb99aa61d6451d68e33489a83bffbe6573541b2da5f64681ea12090f778b2075374778810f73965fa3626a9d41f4df2f83f7c34658cec921b5a9bde49dd5007ec882b02adc514f81aa85898b5cc98e1b137733c0a8789b7f5648d2d231b80bf74978f25d61ce08a8abd11801fd8f995e066676307192ff7641f1cc6e0dee68565b8b22ac3889cd067bf732754a6b270af1044c6a8776811a4f6d8bd0477a9f516064201b920b92d7cd4dc7eee13e6b3eb3528a82f9abb3f388ebe6a8f871393461b73816ec54c99d604174bc5a6801de13908f86aea6a7d0fea107d682bcf1ec348b83872e6b8a316ecd02eb8f8dc86a609bf59a2dd03f1dfa4079436d55e24617be1a2854d008b2b2b1705e2078a7f3946318df1c24f6bf70d4b456eca286ec2b585b28262cc048a098c3e2d5f325a92bb36f691afdc14c822da1b116c9c1c07bb362eb0a04b78834c812134230ebf2044ac2e3c0e3ad00f848dc5010f3bf917ec2fc700b7bf26dacea8440620e04f90f4d97d6dd77cfde8a05c7d3930f1e5811fb8ec5c70964dcc8187ec90e32fdd6b64eec7586413b7d55bed65c4cce39a9b6c15e70e9da94e53fc904e6286f01f5b5562c94211befbc23507e01b2a3865e2f45b5d7b591f290087a5605b82495b4e393f31aa5b37211ec40241a746d903c5eebf117a4d3ddb0d00007b64cbc70e070000" +string(36%d) "%s" diff --git a/ext/zlib/tests/gzinflate-bug42663.phpt b/ext/zlib/tests/gzinflate-bug42663.phpt index cdaf53fb85d15..afd18c62b804a 100644 --- a/ext/zlib/tests/gzinflate-bug42663.phpt +++ b/ext/zlib/tests/gzinflate-bug42663.phpt @@ -19,7 +19,7 @@ var_dump(gzinflate($truncated)); ?> --EXPECTF-- int(168890) -int(66743) +int(667%d) int(65535) Warning: gzinflate(): data error in %s on line %d diff --git a/ext/zlib/tests/zlib_filter_deflate.phpt b/ext/zlib/tests/zlib_filter_deflate.phpt index 7c78d82b33215..da764cad71909 100644 --- a/ext/zlib/tests/zlib_filter_deflate.phpt +++ b/ext/zlib/tests/zlib_filter_deflate.phpt @@ -13,5 +13,5 @@ fwrite($fp, $text); fclose($fp); ?> ---EXPECT-- -HctBDoAgDETRq8zOjfEeHKOGATG0TRpC4u1Vdn/xX4IoxkVMxgP1zA4vkJVhULk9UGkM6TvSNolmxUNlNLePVQ45O3eINf0fsQxtCxwv +--EXPECTF-- +HctB%s From 6b57e2d988e965ed0cef252718f5df018c8617bd Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 2 Mar 2024 12:32:10 +0100 Subject: [PATCH 15/69] Fix GH-13569: GC buffer unnecessarily grows up to GC_MAX_BUF_SIZE when scanning WeakMaps --- Zend/tests/gh13569.phpt | 22 ++++++++++++++++++++++ Zend/zend_gc.c | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh13569.phpt diff --git a/Zend/tests/gh13569.phpt b/Zend/tests/gh13569.phpt new file mode 100644 index 0000000000000..8e5f74d666659 --- /dev/null +++ b/Zend/tests/gh13569.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-13569: GC buffer grows up to GC_MAX_BUF_SIZE when scanning WeakMaps +--FILE-- + +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 4051dd82f8a85..572e3b66fd438 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -718,7 +718,7 @@ static void ZEND_FASTCALL gc_extra_root(zend_refcounted *ref) if (EXPECTED(GC_HAS_UNUSED())) { idx = GC_FETCH_UNUSED(); - } else if (EXPECTED(GC_HAS_NEXT_UNUSED_UNDER_THRESHOLD())) { + } else if (EXPECTED(GC_HAS_NEXT_UNUSED())) { idx = GC_FETCH_NEXT_UNUSED(); } else { gc_grow_root_buffer(); From e220e84b367745188f881f96da0cf8f2d0b038ee Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 5 Mar 2024 12:19:59 +0100 Subject: [PATCH 16/69] [ci skip] --- NEWS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ee008224f9ce0..ad28347baa5ca 100644 --- a/NEWS +++ b/NEWS @@ -2,8 +2,12 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.5 +- Core: + . Fixed GH-13569 (GC buffer unnecessarily grows up to GC_MAX_BUF_SIZE when + scanning WeakMaps). (Arnaud) + - Gettext: - - Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 + . Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 with category set to LC_ALL. (David Carlier) - MySQLnd: From 33967aef11105b043ef7ad97a85fc2b706174261 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 4 Mar 2024 21:33:41 +0000 Subject: [PATCH 17/69] ext/gettext: dcgettext/dcngettext fix for stable branches. close GH-13594 --- UPGRADING | 4 ---- ext/gettext/gettext.c | 14 ++++++-------- ext/gettext/tests/dcgettext_lcall.phpt | 19 +++++-------------- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/UPGRADING b/UPGRADING index de91433d8d2b4..efa74cb42cf9d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -218,10 +218,6 @@ PHP 8.2 UPGRADE NOTES dba_fetch(string|array $key, $skip, $dba): string|false is still accepted, but it is recommended to use the new standard variant. -- Gettext: - . dcgettext/dcngettext throw now an exception if the category's argument if set to - `LC_ALL`. - - MBString . mb_check_encoding() now checks input encoding more strictly for certain text encodings, including ISO-2022-JP and UTF-7. diff --git a/ext/gettext/gettext.c b/ext/gettext/gettext.c index e7928795b279d..15af3cb9b57ff 100644 --- a/ext/gettext/gettext.c +++ b/ext/gettext/gettext.c @@ -62,12 +62,6 @@ ZEND_GET_MODULE(php_gettext) RETURN_THROWS(); \ } -#define PHP_DCGETTEXT_CATEGORY_CHECK(_arg_num, category) \ - if (category == LC_ALL) { \ - zend_argument_value_error(_arg_num, "cannot be LC_ALL"); \ - RETURN_THROWS(); \ - } - PHP_MINFO_FUNCTION(php_gettext) { php_info_print_table_start(); @@ -153,7 +147,9 @@ PHP_FUNCTION(dcgettext) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain)) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid)) - PHP_DCGETTEXT_CATEGORY_CHECK(3, category) + if (category == LC_ALL) { + RETURN_STR_COPY(msgid); + } msgstr = dcgettext(ZSTR_VAL(domain), ZSTR_VAL(msgid), category); @@ -268,7 +264,9 @@ PHP_FUNCTION(dcngettext) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, domain_len) PHP_GETTEXT_LENGTH_CHECK(2, msgid1_len) PHP_GETTEXT_LENGTH_CHECK(3, msgid2_len) - PHP_DCGETTEXT_CATEGORY_CHECK(5, category) + if (category == LC_ALL) { + RETURN_STRING(msgid1); + } msgstr = dcngettext(domain, msgid1, msgid2, count, category); diff --git a/ext/gettext/tests/dcgettext_lcall.phpt b/ext/gettext/tests/dcgettext_lcall.phpt index 004ae89409eca..f44ff29884639 100644 --- a/ext/gettext/tests/dcgettext_lcall.phpt +++ b/ext/gettext/tests/dcgettext_lcall.phpt @@ -4,18 +4,9 @@ dcgettext with LC_ALL is undefined behavior. gettext --FILE-- getMessage() . PHP_EOL; -} - -try { - dcngettext('dngettextTest', 'item', 'item2', 1, LC_ALL); -} catch (ValueError $e) { - echo $e->getMessage(); -} +var_dump(dcgettext('dngettextTest', 'item', LC_ALL)); +var_dump(dcngettext('dngettextTest', 'item', 'item2', 1, LC_ALL)); ?> ---EXPECTF-- -dcgettext(): Argument #3 ($category) cannot be LC_ALL -dcngettext(): Argument #5 ($category) cannot be LC_ALL +--EXPECT-- +string(4) "item" +string(4) "item" From e3f0d03452c78121d3b9e7ca82cce186f0b7ca29 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 6 Mar 2024 08:43:42 +0000 Subject: [PATCH 18/69] Fix GH-13603 ext/sockets: properly initialised address info data. Led to random characters visible on socket id on macOs. Close GH-13606 --- NEWS | 4 ++++ ext/sockets/sockets.c | 4 ++-- ext/sockets/tests/gh13603.phpt | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 ext/sockets/tests/gh13603.phpt diff --git a/NEWS b/NEWS index 2de10b7bc03e2..019f4a79a698e 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,10 @@ PHP NEWS . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with unknown modes). (timwolla) +- Sockets: + . Fixed bug GH-13604 (socket_getsockname returns random characters in the + end of the socket name). (David Carlier) + - SPL: . Fixed bug GH-13531 (Unable to resize SplfixedArray after being unserialized in PHP 8.2.15). (nielsdos) diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 2a15aa18945b5..73ba905f9c324 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -917,7 +917,7 @@ PHP_FUNCTION(socket_read) PHP_FUNCTION(socket_getsockname) { zval *arg1, *addr, *port = NULL; - php_sockaddr_storage sa_storage; + php_sockaddr_storage sa_storage = {0}; php_socket *php_sock; struct sockaddr *sa; struct sockaddr_in *sin; @@ -994,7 +994,7 @@ PHP_FUNCTION(socket_getsockname) PHP_FUNCTION(socket_getpeername) { zval *arg1, *arg2, *arg3 = NULL; - php_sockaddr_storage sa_storage; + php_sockaddr_storage sa_storage = {0}; php_socket *php_sock; struct sockaddr *sa; struct sockaddr_in *sin; diff --git a/ext/sockets/tests/gh13603.phpt b/ext/sockets/tests/gh13603.phpt new file mode 100644 index 0000000000000..9207a992fac3c --- /dev/null +++ b/ext/sockets/tests/gh13603.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-13603 - socket_getsockname - invalid characters +--EXTENSIONS-- +sockets +--FILE-- + Date: Thu, 7 Mar 2024 22:44:31 +0100 Subject: [PATCH 19/69] Move CODEOWNERS to .github (#13591) The CODEOWNERS file is specific to GitHub interface and can be located in .github, docs or in project root. It makes the php-src root directory a bit more browseable. --- CODEOWNERS => .github/CODEOWNERS | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CODEOWNERS => .github/CODEOWNERS (100%) diff --git a/CODEOWNERS b/.github/CODEOWNERS similarity index 100% rename from CODEOWNERS rename to .github/CODEOWNERS From 39b8d5c871a400b4789951d7afe5aeccbe253666 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:14:47 +0100 Subject: [PATCH 20/69] Fix GH-13612: Corrupted memory in destructor with weak references Inside `zend_object_std_dtor` the weakrefs are notified after the destruction of properties already took place. In this test case, the destructor of an anon class will be invoked due to the property destruction. That class has a weak reference to its parent. This means that the destructor can access parent properties that already have been destroyed, resulting in a UAF. Fix this by notifying the weakrefs at the start of the object's destruction. Closes GH-13613. --- NEWS | 4 ++++ Zend/tests/weakrefs/gh13612.phpt | 39 ++++++++++++++++++++++++++++++++ Zend/zend_objects.c | 8 +++---- 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/weakrefs/gh13612.phpt diff --git a/NEWS b/NEWS index 019f4a79a698e..780e43cf6d65b 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.18 +- Core: + . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). + (nielsdos) + - Gettext: - Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 with category set to LC_ALL. (David Carlier) diff --git a/Zend/tests/weakrefs/gh13612.phpt b/Zend/tests/weakrefs/gh13612.phpt new file mode 100644 index 0000000000000..4ca4c92508765 --- /dev/null +++ b/Zend/tests/weakrefs/gh13612.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-13612 (Corrupted memory in destructor with weak references) +--FILE-- +weakAnalysingMap = \WeakReference::create($analysingMap); + } + + public function __destruct() + { + var_dump($this->weakAnalysingMap->get()); + } + }; + + $this->destroyed[] = 1; + $this->ownerDestructorHandlers[] = $handler; + } +} + +new WeakAnalysingMapRepro(); + +echo "Done\n"; + +?> +--EXPECT-- +NULL +Done diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index b09ce3b990d5c..aeaecac539af7 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -47,6 +47,10 @@ ZEND_API void zend_object_std_dtor(zend_object *object) { zval *p, *end; + if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) { + zend_weakrefs_notify(object); + } + if (object->properties) { if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) { if (EXPECTED(GC_DELREF(object->properties) == 0) @@ -85,10 +89,6 @@ ZEND_API void zend_object_std_dtor(zend_object *object) FREE_HASHTABLE(guards); } } - - if (UNEXPECTED(GC_FLAGS(object) & IS_OBJ_WEAKLY_REFERENCED)) { - zend_weakrefs_notify(object); - } } ZEND_API void zend_objects_destroy_object(zend_object *object) From 608ef99a65aedf9991ad24471d732ab328ebbf9b Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:26:36 +0100 Subject: [PATCH 21/69] [ci skip] NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 780e43cf6d65b..21c7d6165d555 100644 --- a/NEWS +++ b/NEWS @@ -7,7 +7,7 @@ PHP NEWS (nielsdos) - Gettext: - - Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 + . Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 with category set to LC_ALL. (David Carlier) - MySQLnd: From 932982f867e773d93fcd341cad7a20e638c3d9ea Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 7 Mar 2024 17:54:12 +0100 Subject: [PATCH 22/69] [skip ci] Mark problematic openssl tests as xfail for now --- ext/openssl/tests/openssl_error_string_basic_openssl3.phpt | 1 + ext/openssl/tests/openssl_private_decrypt_basic.phpt | 1 + 2 files changed, 2 insertions(+) diff --git a/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt b/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt index d435a53e3047f..908777be3916e 100644 --- a/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt +++ b/ext/openssl/tests/openssl_error_string_basic_openssl3.phpt @@ -6,6 +6,7 @@ openssl = 3.0'); ?> +--XFAIL-- --FILE-- Date: Sat, 9 Mar 2024 01:27:54 +0100 Subject: [PATCH 23/69] [skip ci] Add CODEOWNERS in PHP-8.2 branch GitHub at the time of this writing, requires CODEOWNERS file to be present in each branch for the pull request reviews. This adds adjusted CODEOWNERS file from current master branch with updated requests and changes in PHP-8.3 branch. Closes GH-13623 --- .github/CODEOWNERS | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000000..9f631ccf19185 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,62 @@ +# The following volunteers have self-identified as subject matter experts +# or interested parties over a particular area of the php-src source code. +# While requesting a review from someone does not obligate that person to +# review a pull request, these reviewers might have valuable knowledge of +# the problem area and could aid in deciding whether a pull request is ready +# for merging. +# +# For more information, see the GitHub CODEOWNERS documentation: +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +/.github @iluuu1994 @TimWolla +/build/gen_stub.php @kocsismate +/ext/bcmath @Girgias +/ext/curl @adoy +/ext/date @derickr +/ext/dba @Girgias +/ext/dom @nielsdos +/ext/ffi @dstogov +/ext/gettext @devnexen +/ext/gmp @Girgias +/ext/imap @Girgias +/ext/intl @devnexen +/ext/json @bukka +/ext/libxml @nielsdos +/ext/mbstring @alexdowad +/ext/odbc @NattyNarwhal +/ext/opcache @dstogov @iluuu1994 +/ext/openssl @bukka +/ext/pdo_odbc @NattyNarwhal +/ext/pdo_pgsql @devnexen +/ext/pgsql @devnexen +/ext/random @TimWolla @zeriyoshi +/ext/session @Girgias +/ext/sockets @devnexen +/ext/spl @Girgias +/ext/standard @bukka +/ext/xmlreader @nielsdos +/ext/xsl @nielsdos +/main @bukka +/sapi/fpm @bukka +/Zend @iluuu1994 +/Zend/Optimizer @dstogov +/Zend/zend.* @dstogov +/Zend/zend_alloc.* @dstogov +/Zend/zend_API.* @dstogov +/Zend/zend_call_stack.* @arnaud-lb +/Zend/zend_closures.* @dstogov +/Zend/zend_execute.* @dstogov +/Zend/zend_execute_API.c @dstogov +/Zend/zend_gc.* @dstogov @arnaud-lb +/Zend/zend_hash.* @dstogov +/Zend/zend_inheritance.* @dstogov +/Zend/zend_max_execution_timer.* @arnaud-lb +/Zend/zend_object_handlers.* @dstogov +/Zend/zend_objects.* @dstogov +/Zend/zend_objects_API.* @dstogov +/Zend/zend_opcode.* @dstogov +/Zend/zend_string.* @dstogov +/Zend/zend_type*.h @dstogov +/Zend/zend_variables.* @dstogov +/Zend/zend_vm* @dstogov +*.stub.php @kocsismate From a19267d488a862bdc0a509539f7ac7acfb4b7a2d Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 8 Feb 2024 16:34:19 +0000 Subject: [PATCH 24/69] Fix GH-11086: FPM: config test runs twice in daemonised mode The previous check for STDERR did not work so this fixes it. Closes GH-13357 --- NEWS | 4 +++ sapi/fpm/fpm/fpm_stdio.c | 11 ++++-- sapi/fpm/fpm/zlog.c | 7 ++-- sapi/fpm/fpm/zlog.h | 2 +- .../gh-11086-daemonized-logs-duplicated.phpt | 34 +++++++++++++++++++ sapi/fpm/tests/tester.inc | 18 +++++++--- 6 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 sapi/fpm/tests/gh-11086-daemonized-logs-duplicated.phpt diff --git a/NEWS b/NEWS index e583ef86bc065..514f77e4ccbce 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,10 @@ PHP NEWS . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). (nielsdos) +- FPM: + . Fixed GH-11086 (FPM: config test runs twice in daemonised mode). + (Jakub Zelenka) + - Gettext: . Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 with category set to LC_ALL. (David Carlier) diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index a225d3357dd99..55139a0e02ec1 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -153,7 +153,7 @@ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ close(fpm_globals.error_log_fd); } fpm_globals.error_log_fd = -1; - zlog_set_fd(-1); + zlog_set_fd(-1, 0); return 0; } @@ -374,13 +374,14 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ php_openlog(fpm_global_config.syslog_ident, LOG_PID | LOG_CONS, fpm_global_config.syslog_facility); fpm_globals.error_log_fd = ZLOG_SYSLOG; if (fpm_use_error_log()) { - zlog_set_fd(fpm_globals.error_log_fd); + zlog_set_fd(fpm_globals.error_log_fd, 0); } return 0; } #endif fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); + if (0 > fd) { zlog(ZLOG_SYSERROR, "failed to open error_log (%s)", fpm_global_config.error_log); return -1; @@ -393,7 +394,11 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ } else { fpm_globals.error_log_fd = fd; if (fpm_use_error_log()) { - zlog_set_fd(fpm_globals.error_log_fd); + bool is_stderr = ( + strcmp(fpm_global_config.error_log, "/dev/stderr") == 0 || + strcmp(fpm_global_config.error_log, "/proc/self/fd/2") == 0 + ); + zlog_set_fd(fpm_globals.error_log_fd, is_stderr); } } if (0 > fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)) { diff --git a/sapi/fpm/fpm/zlog.c b/sapi/fpm/fpm/zlog.c index e5e49f8385d21..3903c6eb24178 100644 --- a/sapi/fpm/fpm/zlog.c +++ b/sapi/fpm/fpm/zlog.c @@ -25,6 +25,7 @@ #define EXTRA_SPACE_FOR_PREFIX 128 static int zlog_fd = -1; +static bool zlog_fd_is_stderr = false; static int zlog_level = ZLOG_NOTICE; static int zlog_limit = ZLOG_DEFAULT_LIMIT; static zlog_bool zlog_buffering = ZLOG_DEFAULT_BUFFERING; @@ -88,11 +89,13 @@ size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len) /* } /* }}} */ -int zlog_set_fd(int new_fd) /* {{{ */ +int zlog_set_fd(int new_fd, zlog_bool is_stderr) /* {{{ */ { int old_fd = zlog_fd; zlog_fd = new_fd; + zlog_fd_is_stderr = is_stderr; + return old_fd; } /* }}} */ @@ -244,7 +247,7 @@ void vzlog(const char *function, int line, int flags, const char *fmt, va_list a zend_quiet_write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len); } - if (zlog_fd != STDERR_FILENO && zlog_fd != -1 && + if (!zlog_fd_is_stderr && zlog_fd != -1 && !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) { zend_quiet_write(STDERR_FILENO, buf, len); } diff --git a/sapi/fpm/fpm/zlog.h b/sapi/fpm/fpm/zlog.h index 679996041b32e..be22acc32f3ca 100644 --- a/sapi/fpm/fpm/zlog.h +++ b/sapi/fpm/fpm/zlog.h @@ -17,7 +17,7 @@ typedef unsigned char zlog_bool; #define ZLOG_FALSE 0 void zlog_set_external_logger(void (*logger)(int, char *, size_t)); -int zlog_set_fd(int new_fd); +int zlog_set_fd(int new_fd, zlog_bool is_stderr); int zlog_set_level(int new_value); int zlog_set_limit(int new_value); int zlog_set_buffering(zlog_bool buffering); diff --git a/sapi/fpm/tests/gh-11086-daemonized-logs-duplicated.phpt b/sapi/fpm/tests/gh-11086-daemonized-logs-duplicated.phpt new file mode 100644 index 0000000000000..5c435aafc2598 --- /dev/null +++ b/sapi/fpm/tests/gh-11086-daemonized-logs-duplicated.phpt @@ -0,0 +1,34 @@ +--TEST-- +FPM: gh68591 - daemonized mode duplicated logs +--SKIPIF-- + +--FILE-- +testConfig(dumpConfig: false, printOutput: true); + +?> +Done +--EXPECTF-- +%sNOTICE: configuration file %s test is successful +Done +--CLEAN-- + diff --git a/sapi/fpm/tests/tester.inc b/sapi/fpm/tests/tester.inc index 05a33737ebb9e..d5dbdd36ff1a2 100644 --- a/sapi/fpm/tests/tester.inc +++ b/sapi/fpm/tests/tester.inc @@ -440,12 +440,22 @@ class Tester * @return null|array * @throws \Exception */ - public function testConfig($silent = false, array|string|null $expectedPattern = null): ?array - { - $configFile = $this->createConfig(); - $cmd = self::findExecutable() . ' -n -tt -y ' . $configFile . ' 2>&1'; + public function testConfig( + $silent = false, + array|string|null $expectedPattern = null, + $dumpConfig = true, + $printOutput = false + ): ?array { + $configFile = $this->createConfig(); + $configTestArg = $dumpConfig ? '-tt' : '-t'; + $cmd = self::findExecutable() . " -n $configTestArg -y $configFile 2>&1"; $this->trace('Testing config using command', $cmd, true); exec($cmd, $output, $code); + if ($printOutput) { + foreach ($output as $outputLine) { + echo $outputLine . "\n"; + } + } $found = 0; if ($expectedPattern !== null) { $expectedPatterns = is_array($expectedPattern) ? $expectedPattern : [$expectedPattern]; From 2343791aff2cfa3c49cd0f7b0841caa0455b766c Mon Sep 17 00:00:00 2001 From: divinity76 Date: Sat, 20 Jan 2024 19:38:49 +0100 Subject: [PATCH 25/69] Fix GH-13203: file_put_contents fail on strings over 4GB on Windows Closes GH-13205 --- NEWS | 2 + .../tests/file/file_put_contents_5gb.phpt | 67 +++++++++++++++++++ main/streams/plain_wrapper.c | 7 +- 3 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 ext/standard/tests/file/file_put_contents_5gb.phpt diff --git a/NEWS b/NEWS index 21c7d6165d555..f53996ae66060 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,8 @@ PHP NEWS . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) . Fixed GH-13402 (Added validation of `\n` in $additional_headers of mail()). (SakiTakamachi) + . Fixed bug GH-13203 (file_put_contents fail on strings over 4GB on Windows). + (divinity76) - XML: . Fixed bug GH-13517 (Multiple test failures when building with diff --git a/ext/standard/tests/file/file_put_contents_5gb.phpt b/ext/standard/tests/file/file_put_contents_5gb.phpt new file mode 100644 index 0000000000000..7d91ef691b586 --- /dev/null +++ b/ext/standard/tests/file/file_put_contents_5gb.phpt @@ -0,0 +1,67 @@ +--TEST-- +Test file_put_contents() function with 5GB string +--SKIPIF-- + +--INI-- +memory_limit=6G +--FILE-- + +--CLEAN-- + +--EXPECT-- +File written successfully. diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index e9a30f3334016..c77bd1e2415a8 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -40,6 +40,7 @@ # include "win32/time.h" # include "win32/ioutil.h" # include "win32/readdir.h" +# include #endif #define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC) @@ -353,11 +354,7 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun if (data->fd >= 0) { #ifdef PHP_WIN32 - ssize_t bytes_written; - if (ZEND_SIZE_T_UINT_OVFL(count)) { - count = UINT_MAX; - } - bytes_written = _write(data->fd, buf, (unsigned int)count); + ssize_t bytes_written = _write(data->fd, buf, (unsigned int)(count > INT_MAX ? INT_MAX : count)); #else ssize_t bytes_written = write(data->fd, buf, count); #endif From 00f9c5eeb4b4c5215e7a6a98b4ce5f7c0501c385 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 8 Mar 2024 19:10:28 +0100 Subject: [PATCH 26/69] Remove MAP_JIT flag This flag is supposed to go on the flags parameter, rather than prot. Moreover, this flag is no longer needed because the JIT does not set RWX without ZTS, and JIT+ZTS has been disabled on macOS with Apple Silicon. Closes GH-13638 --- ext/opcache/shared_alloc_mmap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index 33727d0da656c..6f01f1d631b74 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -180,9 +180,6 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_ #ifdef PROT_MAX flags |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC); #endif -#ifdef MAP_JIT - flags |= MAP_JIT; -#endif #if (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__)) && !defined(__SANITIZE_ADDRESS__) void *hint = find_prefered_mmap_base(requested_size); if (hint != MAP_FAILED) { From e3711af8cea04cd78dbbe6c4571d0cc66046c6db Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 9 Mar 2024 14:58:57 +0100 Subject: [PATCH 27/69] Add ZPP checks in DOMNode::{__sleep,__wakeup} Closes GH-13651. --- NEWS | 3 +++ ext/dom/node.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/NEWS b/NEWS index f53996ae66060..785fa531bd557 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,9 @@ PHP NEWS . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). (nielsdos) +- DOM: + . Add some missing ZPP checks. (nielsdos) + - Gettext: . Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 with category set to LC_ALL. (David Carlier) diff --git a/ext/dom/node.c b/ext/dom/node.c index e80939db14dd7..973505c5b01a9 100644 --- a/ext/dom/node.c +++ b/ext/dom/node.c @@ -1797,12 +1797,20 @@ PHP_METHOD(DOMNode, getLineNo) PHP_METHOD(DOMNode, __sleep) { + if (zend_parse_parameters_none() != SUCCESS) { + RETURN_THROWS(); + } + zend_throw_exception_ex(NULL, 0, "Serialization of '%s' is not allowed, unless serialization methods are implemented in a subclass", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); RETURN_THROWS(); } PHP_METHOD(DOMNode, __wakeup) { + if (zend_parse_parameters_none() != SUCCESS) { + RETURN_THROWS(); + } + zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed, unless unserialization methods are implemented in a subclass", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name)); RETURN_THROWS(); } From 65593e10ef27ea6dd43657a9bf69dcbf88678420 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 10 Mar 2024 11:27:47 +0100 Subject: [PATCH 28/69] Fix nightly failure due to type in file_put_contents_5gb.phpt --- ext/standard/tests/file/file_put_contents_5gb.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/tests/file/file_put_contents_5gb.phpt b/ext/standard/tests/file/file_put_contents_5gb.phpt index 7d91ef691b586..d552d86279d03 100644 --- a/ext/standard/tests/file/file_put_contents_5gb.phpt +++ b/ext/standard/tests/file/file_put_contents_5gb.phpt @@ -4,7 +4,7 @@ Test file_put_contents() function with 5GB string Date: Sun, 10 Mar 2024 15:15:12 +0100 Subject: [PATCH 29/69] [skip ci] Mark another openssl test as xfail --- ext/openssl/tests/openssl_error_string_basic.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/openssl/tests/openssl_error_string_basic.phpt b/ext/openssl/tests/openssl_error_string_basic.phpt index e4ea264b3bf1f..18e06b30bb447 100644 --- a/ext/openssl/tests/openssl_error_string_basic.phpt +++ b/ext/openssl/tests/openssl_error_string_basic.phpt @@ -6,6 +6,7 @@ openssl = 0x30000000) die('skip For OpenSSL < 3.0'); ?> +--XFAIL-- --FILE-- Date: Sun, 10 Mar 2024 07:41:24 -0700 Subject: [PATCH 30/69] Fix brew action (#13659) We patch brew to ensure it overwrites files while linking the dependencies --- .github/actions/brew/action.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/actions/brew/action.yml b/.github/actions/brew/action.yml index 51d37aa56d470..5868d3917b80c 100644 --- a/.github/actions/brew/action.yml +++ b/.github/actions/brew/action.yml @@ -5,6 +5,12 @@ runs: - shell: bash run: | set -x + + # Patch brew to overwrite always + formula_installer="$(brew --repo)"/Library/Homebrew/formula_installer.rb + code=" keg.link\(verbose: verbose\?" + sudo sed -Ei '' "s/$code.*/$code, overwrite: true\)/" "$formula_installer" + brew install \ pkg-config \ autoconf \ From 0ea80126ead6951def2b1dbc28fda024a226fa27 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 11 Mar 2024 15:10:12 +0100 Subject: [PATCH 31/69] Fix GH-13508: JITed QM_ASSIGN may be optimized out when op1 is null (#13610) Co-authored-by: Dmitry Stogov --- ext/opcache/jit/zend_jit_trace.c | 3 +- ext/opcache/tests/jit/qm_assign_004.phpt | 39 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/tests/jit/qm_assign_004.phpt diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index f6da28375b74d..c1ed5d80a666a 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -5070,8 +5070,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par CHECK_OP1_TRACE_TYPE(); res_info = RES_INFO(); res_use_info = zend_jit_trace_type_to_info( - STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var))) - & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE); + STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var))); res_addr = RES_REG_ADDR(); if (Z_MODE(res_addr) != IS_REG && STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) != diff --git a/ext/opcache/tests/jit/qm_assign_004.phpt b/ext/opcache/tests/jit/qm_assign_004.phpt new file mode 100644 index 0000000000000..975d46be41cec --- /dev/null +++ b/ext/opcache/tests/jit/qm_assign_004.phpt @@ -0,0 +1,39 @@ +--TEST-- +JIT QM_ASSIGN: 004 missing type store +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- + +DONE +--EXPECT-- +array(2) { + [0]=> + string(0) "" + [1]=> + string(0) "" +} +array(2) { + [0]=> + string(0) "" + [1]=> + string(0) "" +} +DONE From 809446d3d15e5b4d0ab5db60a611df8822dbfc52 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 11 Mar 2024 15:13:03 +0100 Subject: [PATCH 32/69] [ci skip] NEWS --- NEWS | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 785fa531bd557..d24a8fee0a2a0 100644 --- a/NEWS +++ b/NEWS @@ -16,16 +16,20 @@ PHP NEWS - MySQLnd: . Fix GH-13452 (Fixed handshake response [mysqlnd]). (Saki Takamachi) +- Opcache: + . Fixed GH-13508 (JITed QM_ASSIGN may be optimized out when op1 is null). + (Arnaud, Dmitry) + - PDO: . Fix various PDORow bugs. (Girgias) - Random: - . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with - unknown modes). (timwolla) + . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with unknown + modes). (timwolla) - Sockets: - . Fixed bug GH-13604 (socket_getsockname returns random characters in the - end of the socket name). (David Carlier) + . Fixed bug GH-13604 (socket_getsockname returns random characters in the end + of the socket name). (David Carlier) - SPL: . Fixed bug GH-13531 (Unable to resize SplfixedArray after being unserialized From 1b5d9f657b494966053fc9535c9043d5858362f2 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 11 Mar 2024 15:14:28 +0100 Subject: [PATCH 33/69] [ci skip] NEWS --- NEWS | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 1926343486ec5..625a148549c06 100644 --- a/NEWS +++ b/NEWS @@ -22,9 +22,13 @@ PHP NEWS - MySQLnd: . Fix GH-13452 (Fixed handshake response [mysqlnd]). (Saki Takamachi) +- Opcache: + . Fixed GH-13508 (JITed QM_ASSIGN may be optimized out when op1 is null). + (Arnaud, Dmitry) + - Random: - . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with - unknown modes). (timwolla) + . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with unknown + modes). (timwolla) - Standard: . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) From 6985aff7c31d38eed968f4c47a261b67b924621c Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:10:53 +0100 Subject: [PATCH 34/69] Fix GH-13680: Segfault with session_decode and compilation error It's illegal to return from a bailout because that doesn't restore the original bailout data. Return outside of it. Test by YuanchengJiang Closes GH-13689. --- NEWS | 4 ++++ ext/session/session.c | 5 +++-- ext/session/tests/gh13680.phpt | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 ext/session/tests/gh13680.phpt diff --git a/NEWS b/NEWS index d24a8fee0a2a0..4598f8bea7502 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ PHP NEWS . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with unknown modes). (timwolla) +- Session: + . Fixed bug GH-13680 (Segfault with session_decode and compilation error). + (nielsdos) + - Sockets: . Fixed bug GH-13604 (socket_getsockname returns random characters in the end of the socket name). (David Carlier) diff --git a/ext/session/session.c b/ext/session/session.c index 6b63999297205..74a0546b8490c 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -259,16 +259,17 @@ static zend_result php_session_decode(zend_string *data) /* {{{ */ php_error_docref(NULL, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); return FAILURE; } + zend_result result = SUCCESS; zend_try { if (PS(serializer)->decode(ZSTR_VAL(data), ZSTR_LEN(data)) == FAILURE) { php_session_cancel_decode(); - return FAILURE; + result = FAILURE; } } zend_catch { php_session_cancel_decode(); zend_bailout(); } zend_end_try(); - return SUCCESS; + return result; } /* }}} */ diff --git a/ext/session/tests/gh13680.phpt b/ext/session/tests/gh13680.phpt new file mode 100644 index 0000000000000..a95583ee34598 --- /dev/null +++ b/ext/session/tests/gh13680.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-13680 (Segfault with session_decode and compilation error) +--EXTENSIONS-- +session +--SKIPIF-- + +--INI-- +session.use_cookies=0 +session.use_strict_mode=0 +session.cache_limiter= +session.serialize_handler=php_serialize +session.save_handler=files +error_reporting=E_ALL +--FILE-- + +--EXPECTF-- +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s on line %d + +Fatal error: Could not check compatibility between Test::createFromFormat($format, $datetime, $timezone = null): Wrong and DateTime::createFromFormat(string $format, string $datetime, ?DateTimeZone $timezone = null): DateTime|false, because class Wrong is not available in %s on line %d From f34721cabd3f6f12ccc0c06fbd8534b650e10fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Wed, 13 Mar 2024 20:13:48 +0100 Subject: [PATCH 35/69] random: Initialize the `mode` field when seeding in `php_random_default_status()` (#13690) This is not just an issue due to missing initialization since moving the state struct directly into the module globals. In earlier versions changing the mode to `MT_RAND_PHP` within a single request would also affect the mode for subsequent requests. Original commit message follows: This is a follow-up fix for GH-13579. The issue was detected in the nightly MSAN build. (cherry picked from commit bf0abd1629291c193064a9cb95a2da3565decc38) --- NEWS | 2 ++ ext/random/random.c | 1 + 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 4598f8bea7502..ea7909695d14a 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,8 @@ PHP NEWS - Random: . Fixed bug GH-13544 (Pre-PHP 8.2 compatibility for mt_srand with unknown modes). (timwolla) + . Fixed bug GH-13690 (Global Mt19937 is not properly reset in-between + requests when MT_RAND_PHP is used). (timwolla) - Session: . Fixed bug GH-13680 (Segfault with session_decode and compilation error). diff --git a/ext/random/random.c b/ext/random/random.c index 9f9da28962d15..e30a04259fb2b 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -334,6 +334,7 @@ PHPAPI php_random_status *php_random_default_status(void) php_random_status *status = RANDOM_G(mt19937); if (!RANDOM_G(mt19937_seeded)) { + ((php_random_status_state_mt19937 *)status->state)->mode = MT_RAND_MT19937; php_random_mt19937_seed_default(status->state); RANDOM_G(mt19937_seeded) = true; } From 334419e1575b96c1800c666679286576659bf1ac Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 13 Mar 2024 18:50:17 +0000 Subject: [PATCH 36/69] zend test fix copy_file_range for musl. normally should no longer need off64_t with glibc anyway. --- ext/zend_test/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index ed1f3ef547466..8c32238ce36f9 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1128,9 +1128,9 @@ PHP_ZEND_TEST_API void bug_gh9090_void_int_char_var(int i, char *fmt, ...) { /** * This function allows us to simulate early return of copy_file_range by setting the limit_copy_file_range ini setting. */ -PHP_ZEND_TEST_API ssize_t copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out, size_t len, unsigned int flags) +PHP_ZEND_TEST_API ssize_t copy_file_range(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t len, unsigned int flags) { - ssize_t (*original_copy_file_range)(int, off64_t *, int, off64_t *, size_t, unsigned int) = dlsym(RTLD_NEXT, "copy_file_range"); + ssize_t (*original_copy_file_range)(int, off_t *, int, off_t *, size_t, unsigned int) = dlsym(RTLD_NEXT, "copy_file_range"); if (ZT_G(limit_copy_file_range) >= Z_L(0)) { len = ZT_G(limit_copy_file_range); } From db1f7b12868920c7d881cc3d377f25cedea232cb Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 14 Mar 2024 08:02:29 +0000 Subject: [PATCH 37/69] zend_test fix copy_file_range test for linux 32 bits close GH-13708 --- ext/zend_test/test.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 8c32238ce36f9..d27b4543fcc01 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1128,9 +1128,12 @@ PHP_ZEND_TEST_API void bug_gh9090_void_int_char_var(int i, char *fmt, ...) { /** * This function allows us to simulate early return of copy_file_range by setting the limit_copy_file_range ini setting. */ -PHP_ZEND_TEST_API ssize_t copy_file_range(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t len, unsigned int flags) +#ifdef __MUSL__ +typedef off_t off64_t; +#endif +PHP_ZEND_TEST_API ssize_t copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out, size_t len, unsigned int flags) { - ssize_t (*original_copy_file_range)(int, off_t *, int, off_t *, size_t, unsigned int) = dlsym(RTLD_NEXT, "copy_file_range"); + ssize_t (*original_copy_file_range)(int, off64_t *, int, off64_t *, size_t, unsigned int) = dlsym(RTLD_NEXT, "copy_file_range"); if (ZT_G(limit_copy_file_range) >= Z_L(0)) { len = ZT_G(limit_copy_file_range); } From 30c58aba0c481e52da16d87547a14e33cce373ee Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:08:25 +0100 Subject: [PATCH 38/69] Fix potential memory leak in XPath evaluation results --- NEWS | 1 + ext/dom/xpath.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index ea7909695d14a..60f6f0f7203df 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ PHP NEWS - DOM: . Add some missing ZPP checks. (nielsdos) + . Fix potential memory leak in XPath evaluation results. (nielsdos) - Gettext: . Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 diff --git a/ext/dom/xpath.c b/ext/dom/xpath.c index 73ceb49362781..22a7e0ecc5a91 100644 --- a/ext/dom/xpath.c +++ b/ext/dom/xpath.c @@ -125,8 +125,11 @@ static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, } } break; - default: - ZVAL_STRING(&fci.params[i], (char *)xmlXPathCastToString(obj)); + default: { + str = (char *)xmlXPathCastToString(obj); + ZVAL_STRING(&fci.params[i], str); + xmlFree(str); + } } xmlXPathFreeObject(obj); } From 23eb6a00e2b3ce8f5af7b2ad9ec89d26bdefc21f Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Sat, 16 Mar 2024 00:14:18 +0900 Subject: [PATCH 39/69] Changed the test expected value of `mysqli::info` to `%s` (#13723) Closes #13723 Fixes #13628 --- ext/mysqli/tests/bug34810.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysqli/tests/bug34810.phpt b/ext/mysqli/tests/bug34810.phpt index 502a67dbd21e8..02c6680d9ac57 100644 --- a/ext/mysqli/tests/bug34810.phpt +++ b/ext/mysqli/tests/bug34810.phpt @@ -84,7 +84,7 @@ object(mysqli)#%d (%d) { ["host_info"]=> string(%d) "%s" ["info"]=> - NULL + %s ["insert_id"]=> int(0) ["server_info"]=> From afdabb124737a0dfd3be3929ece611239d463c81 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:16:23 +0100 Subject: [PATCH 40/69] Add missing DOM dependency in config.m4 for ext/xsl Closes GH-13715. --- ext/xsl/config.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/xsl/config.m4 b/ext/xsl/config.m4 index 14af536fa7352..8d45e8eacb9a3 100644 --- a/ext/xsl/config.m4 +++ b/ext/xsl/config.m4 @@ -29,4 +29,5 @@ if test "$PHP_XSL" != "no"; then PHP_NEW_EXTENSION(xsl, php_xsl.c xsltprocessor.c, $ext_shared) PHP_SUBST(XSL_SHARED_LIBADD) PHP_ADD_EXTENSION_DEP(xsl, libxml) + PHP_ADD_EXTENSION_DEP(xsl, dom) fi From 6c4e3c0f52510eef93edc03a329f9d5c22033ab3 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Sun, 17 Mar 2024 03:09:08 +0100 Subject: [PATCH 41/69] Use ZEND_API in zend_hrtime (#13288) This allows actually calling zend_hrtime() from extensions on Windows. Signed-off-by: Bob Weinand --- Zend/zend_hrtime.c | 4 ++-- Zend/zend_hrtime.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Zend/zend_hrtime.c b/Zend/zend_hrtime.c index a28ba3f470508..bcf11964f1cea 100644 --- a/Zend/zend_hrtime.c +++ b/Zend/zend_hrtime.c @@ -31,13 +31,13 @@ # define WIN32_LEAN_AND_MEAN -double zend_hrtime_timer_scale = .0; +ZEND_API double zend_hrtime_timer_scale = .0; #elif ZEND_HRTIME_PLATFORM_APPLE # include # include -mach_timebase_info_data_t zend_hrtime_timerlib_info = { +ZEND_API mach_timebase_info_data_t zend_hrtime_timerlib_info = { .numer = 0, .denom = 1, }; diff --git a/Zend/zend_hrtime.h b/Zend/zend_hrtime.h index 6bba076738a91..1449c4e443cf2 100644 --- a/Zend/zend_hrtime.h +++ b/Zend/zend_hrtime.h @@ -60,13 +60,13 @@ BEGIN_EXTERN_C() #if ZEND_HRTIME_PLATFORM_WINDOWS -extern double zend_hrtime_timer_scale; +ZEND_API extern double zend_hrtime_timer_scale; #elif ZEND_HRTIME_PLATFORM_APPLE # include # include -extern mach_timebase_info_data_t zend_hrtime_timerlib_info; +ZEND_API extern mach_timebase_info_data_t zend_hrtime_timerlib_info; #endif From aa34e0acb4a03df652ad083bf01370f7a7a52788 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:38:15 +0100 Subject: [PATCH 42/69] Fix GH-13685: Unexpected null pointer in zend_string.h Regressed in 6fbf81c. There is a missing error check on spl_filesystem_file_read_line(), which means that if the line could not be read (e.g. because we're at the end of the file), it will not set intern->u.file.current_line, which will cause a NULL pointer deref later on. Fix it by adding a check, and reintroducing the silent flag partially to be able to throw an exception like it did in the past. Closes GH-13692. --- NEWS | 1 + ext/spl/spl_directory.c | 46 ++++++++++++++++++++------------- ext/spl/tests/gh13685.phpt | 52 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 ext/spl/tests/gh13685.phpt diff --git a/NEWS b/NEWS index 60f6f0f7203df..927a536d89519 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,7 @@ PHP NEWS - SPL: . Fixed bug GH-13531 (Unable to resize SplfixedArray after being unserialized in PHP 8.2.15). (nielsdos) + . Fixed bug GH-13685 (Unexpected null pointer in zend_string.h). (nielsdos) - Standard: . Fixed bug GH-11808 (Live filesystem modified by tests). (nielsdos) diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 581183d38f49e..03b959daa3bbf 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1866,6 +1866,11 @@ zend_object_iterator *spl_filesystem_tree_get_iterator(zend_class_entry *ce, zva } /* }}} */ +static ZEND_COLD void spl_filesystem_file_cannot_read(spl_filesystem_object *intern) +{ + zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", ZSTR_VAL(intern->file_name)); +} + static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bool silent, zend_long line_add, bool csv) { char *buf; @@ -1875,7 +1880,7 @@ static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bo if (php_stream_eof(intern->u.file.stream)) { if (!silent) { - zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", ZSTR_VAL(intern->file_name)); + spl_filesystem_file_cannot_read(intern); } return FAILURE; } @@ -1930,10 +1935,10 @@ static bool is_line_empty(spl_filesystem_object *intern) || (current_line_len == 2 && current_line[0] == '\r' && current_line[1] == '\n')))); } -static zend_result spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value) /* {{{ */ +static zend_result spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value, bool silent) /* {{{ */ { do { - zend_result ret = spl_filesystem_file_read(intern, /* silent */ true, /* csv */ true); + zend_result ret = spl_filesystem_file_read(intern, silent, /* csv */ true); if (ret != SUCCESS) { return ret; } @@ -1959,19 +1964,21 @@ static zend_result spl_filesystem_file_read_csv(spl_filesystem_object *intern, c } /* }}} */ -/* Call to this function reads a line in a "silent" fashion and does not throw an exception */ -static zend_result spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern) /* {{{ */ +static zend_result spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_object *intern, bool silent) /* {{{ */ { zval retval; /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV)) { - return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL); + return spl_filesystem_file_read_csv(intern, intern->u.file.delimiter, intern->u.file.enclosure, intern->u.file.escape, NULL, silent); } if (intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) { spl_filesystem_file_free_line(intern); if (php_stream_eof(intern->u.file.stream)) { + if (!silent) { + spl_filesystem_file_cannot_read(intern); + } return FAILURE; } zend_call_method_with_0_params(Z_OBJ_P(this_ptr), Z_OBJCE_P(this_ptr), &intern->u.file.func_getCurr, "getCurrentLine", &retval); @@ -1995,18 +2002,17 @@ static zend_result spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesys zval_ptr_dtor(&retval); return SUCCESS; } else { - return spl_filesystem_file_read(intern, /* silent */ true, /* csv */ false); + return spl_filesystem_file_read(intern, silent, /* csv */ false); } } /* }}} */ -/* Call to this function reads a line in a "silent" fashion and does not throw an exception */ -static zend_result spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern) /* {{{ */ +static zend_result spl_filesystem_file_read_line(zval * this_ptr, spl_filesystem_object *intern, bool silent) /* {{{ */ { - zend_result ret = spl_filesystem_file_read_line_ex(this_ptr, intern); + zend_result ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent); while (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_SKIP_EMPTY) && ret == SUCCESS && is_line_empty(intern)) { spl_filesystem_file_free_line(intern); - ret = spl_filesystem_file_read_line_ex(this_ptr, intern); + ret = spl_filesystem_file_read_line_ex(this_ptr, intern, silent); } return ret; @@ -2028,7 +2034,7 @@ static void spl_filesystem_file_rewind(zval * this_ptr, spl_filesystem_object *i intern->u.file.current_line_num = 0; if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { - spl_filesystem_file_read_line(this_ptr, intern); + spl_filesystem_file_read_line(this_ptr, intern, true); } } /* }}} */ @@ -2182,7 +2188,7 @@ PHP_METHOD(SplFileObject, current) CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) { - spl_filesystem_file_read_line(ZEND_THIS, intern); + spl_filesystem_file_read_line(ZEND_THIS, intern, true); } if (intern->u.file.current_line && (!SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || Z_ISUNDEF(intern->u.file.current_zval))) { RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len); @@ -2221,7 +2227,7 @@ PHP_METHOD(SplFileObject, next) spl_filesystem_file_free_line(intern); if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { - spl_filesystem_file_read_line(ZEND_THIS, intern); + spl_filesystem_file_read_line(ZEND_THIS, intern, true); } intern->u.file.current_line_num++; } /* }}} */ @@ -2339,7 +2345,7 @@ PHP_METHOD(SplFileObject, fgetcsv) } } - if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value) == FAILURE) { + if (spl_filesystem_file_read_csv(intern, delimiter, enclosure, escape, return_value, true) == FAILURE) { RETURN_FALSE; } } @@ -2720,7 +2726,7 @@ PHP_METHOD(SplFileObject, seek) spl_filesystem_file_rewind(ZEND_THIS, intern); for (i = 0; i < line_pos; i++) { - if (spl_filesystem_file_read_line(ZEND_THIS, intern) == FAILURE) { + if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == FAILURE) { return; } } @@ -2740,8 +2746,12 @@ PHP_METHOD(SplFileObject, __toString) CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); - if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval)) { - spl_filesystem_file_read_line(ZEND_THIS, intern); + if (!intern->u.file.current_line) { + ZEND_ASSERT(Z_ISUNDEF(intern->u.file.current_zval)); + zend_result result = spl_filesystem_file_read_line(ZEND_THIS, intern, false); + if (UNEXPECTED(result != SUCCESS)) { + RETURN_THROWS(); + } } RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len); diff --git a/ext/spl/tests/gh13685.phpt b/ext/spl/tests/gh13685.phpt new file mode 100644 index 0000000000000..0f679d0e93fc9 --- /dev/null +++ b/ext/spl/tests/gh13685.phpt @@ -0,0 +1,52 @@ +--TEST-- +GH-13685 (Unexpected null pointer in zend_string.h) +--FILE-- +fwrite($contents); +$file->rewind(); +while (($data = $file->fgetcsv(',', '"', ''))) { + var_dump((string) $file); +} +try { + var_dump((string) $file); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +echo "--- Use csv control ---\n"; + +$file = new SplTempFileObject; +$file->fwrite($contents); +$file->rewind(); +$file->setFlags(SplFileObject::READ_CSV); +$file->setCsvControl(',', '"', ''); +foreach ($file as $row) { + var_dump((string) $file); +} +try { + var_dump((string) $file); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +--- Directly call fgetcsv --- +string(14) ""A", "B", "C" +" +string(13) ""D", "E", "F"" +Cannot read from file php://temp +--- Use csv control --- +string(14) ""A", "B", "C" +" +string(13) ""D", "E", "F"" +Cannot read from file php://temp From 868257a3de8236c4aa0508d23ac0a068a4e76139 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 16 Mar 2024 17:00:15 +0000 Subject: [PATCH 43/69] Fix GH-13727: macro generating invalid call test prototypes fixes. autoconf/libtool generating code to test features missed `void` for C calls prototypes w/o arguments. Note that specific changes related to libtool have to be upstreamed. Co-authored-by: Peter Kokot close GH-13732 --- NEWS | 2 ++ TSRM/threads.m4 | 2 +- Zend/Zend.m4 | 2 +- build/libtool.m4 | 10 +++++----- build/ltmain.sh | 2 +- build/php.m4 | 34 +++++++++++++++++----------------- configure.ac | 4 ++-- ext/gd/config.m4 | 2 +- ext/iconv/config.m4 | 6 +++--- ext/opcache/config.m4 | 6 +++--- ext/standard/config.m4 | 12 ++++++------ sapi/fpm/config.m4 | 10 +++++----- 12 files changed, 47 insertions(+), 45 deletions(-) diff --git a/NEWS b/NEWS index 927a536d89519..dd3e7703cd3ed 100644 --- a/NEWS +++ b/NEWS @@ -151,6 +151,8 @@ PHP NEWS loading composer classmaps with more than 11k elements). (nielsdos) . Fixed bug GH-12966 (missing cross-compiling 3rd argument so Autoconf doesn't emit warnings). (Peter Kokot) + . Fixed bug GH-13727 (missing void keyword for C generate code for feature test). + (Peter Kokot/David Carlier) - Cli: . Fix incorrect timeout in built-in web server when using router script and diff --git a/TSRM/threads.m4 b/TSRM/threads.m4 index dc5719bbec056..c42b328dd6651 100644 --- a/TSRM/threads.m4 +++ b/TSRM/threads.m4 @@ -73,7 +73,7 @@ void *thread_routine(void *data) { return data; } -int main() { +int main(void) { pthread_t thd; pthread_mutexattr_t mattr; int data = 1; diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 06b19c85c712b..e7a6603ddbf07 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -220,7 +220,7 @@ typedef union _mm_align_test { #define ZEND_MM_ALIGNMENT (sizeof(mm_align_test)) #endif -int main() +int main(void) { size_t i = ZEND_MM_ALIGNMENT; int zeros = 0; diff --git a/build/libtool.m4 b/build/libtool.m4 index 8ee7b453010f1..5b518d50e4ef5 100644 --- a/build/libtool.m4 +++ b/build/libtool.m4 @@ -277,7 +277,7 @@ dnl This sometimes fails to find confdefs.h, for some reason. dnl [#]line __oline__ "[$]0" [#]line __oline__ "configure" #include "confdefs.h" -int main() { +int main(void) { ; return 0; } EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then @@ -978,8 +978,8 @@ else # endif #endif -void fnord() { int i=42;} -int main () +void fnord(void) { int i=42;} +int main (void) { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; @@ -2750,7 +2750,7 @@ _LT_AC_TAGVAR(objext, $1)=$objext lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' +lt_simple_link_test_code='int main(void){return(0);}' _LT_AC_SYS_COMPILER @@ -4640,7 +4640,7 @@ void nm_test_func(){} #ifdef __cplusplus } #endif -int main(){nm_test_var='a';nm_test_func();return(0);} +int main(void){nm_test_var='a';nm_test_func();return(0);} EOF if AC_TRY_EVAL(ac_compile); then diff --git a/build/ltmain.sh b/build/ltmain.sh index 2f1c8c9dc80f0..ff1685c8a89f9 100755 --- a/build/ltmain.sh +++ b/build/ltmain.sh @@ -3598,7 +3598,7 @@ EOF # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c < -int main() { +int main(void) { char buf[27]; struct tm t; time_t old = 0; @@ -1118,7 +1118,7 @@ return (1); ],[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -int main() { +int main(void) { struct tm t, *s; time_t old = 0; char buf[27], *p; @@ -1159,7 +1159,7 @@ AC_DEFUN([PHP_DOES_PWRITE_WORK],[ #include #include $1 - int main() { + int main(void) { int fd = open("conftest_in", O_WRONLY|O_CREAT, 0600); if (fd < 0) return 1; @@ -1193,7 +1193,7 @@ AC_DEFUN([PHP_DOES_PREAD_WORK],[ #include #include $1 - int main() { + int main(void) { char buf[3]; int fd = open("conftest_in", O_RDONLY); if (fd < 0) return 1; @@ -1261,27 +1261,27 @@ dnl PHP_MISSING_TIME_R_DECL dnl AC_DEFUN([PHP_MISSING_TIME_R_DECL],[ AC_MSG_CHECKING([for missing declarations of reentrant functions]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm *(*func)() = localtime_r]])],[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm *(*func)(void) = localtime_r]])],[ : ],[ AC_DEFINE(MISSING_LOCALTIME_R_DECL,1,[Whether localtime_r is declared]) ]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm *(*func)() = gmtime_r]])],[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm *(*func)(void) = gmtime_r]])],[ : ],[ AC_DEFINE(MISSING_GMTIME_R_DECL,1,[Whether gmtime_r is declared]) ]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *(*func)() = asctime_r]])],[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *(*func)(void) = asctime_r]])],[ : ],[ AC_DEFINE(MISSING_ASCTIME_R_DECL,1,[Whether asctime_r is declared]) ]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *(*func)() = ctime_r]])],[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *(*func)(void) = ctime_r]])],[ : ],[ AC_DEFINE(MISSING_CTIME_R_DECL,1,[Whether ctime_r is declared]) ]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *(*func)() = strtok_r]])],[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[char *(*func)(void) = strtok_r]])],[ : ],[ AC_DEFINE(MISSING_STRTOK_R_DECL,1,[Whether strtok_r is declared]) @@ -1315,7 +1315,7 @@ dnl See if we have broken header files like SunOS has. dnl AC_DEFUN([PHP_MISSING_FCLOSE_DECL],[ AC_MSG_CHECKING([for fclose declaration]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int (*func)() = fclose]])],[ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int (*func)(void) = fclose]])],[ AC_DEFINE(MISSING_FCLOSE_DECL,0,[ ]) AC_MSG_RESULT([ok]) ],[ @@ -1405,7 +1405,7 @@ struct s int i; char c[1]; }; -int main() +int main(void) { struct s *s = malloc(sizeof(struct s) + 3); s->i = 3; @@ -1463,7 +1463,7 @@ int seeker(void *cookie, off64_t *position, int whence) cookie_io_functions_t funcs = {reader, writer, seeker, closer}; -int main() { +int main(void) { struct cookiedata g = { 0 }; FILE *fp = fopencookie(&g, "r", funcs); @@ -1590,7 +1590,7 @@ AC_DEFUN([PHP_CHECK_FUNC_LIB],[ if test "$found" = "yes"; then ac_libs=$LIBS LIBS="$LIBS -l$2" - AC_RUN_IFELSE([AC_LANG_SOURCE([[int main() { return (0); }]])],[found=yes],[found=no],[ + AC_RUN_IFELSE([AC_LANG_PROGRAM()],[found=yes],[found=no],[ dnl Cross compilation. found=yes ]) @@ -1643,8 +1643,8 @@ AC_DEFUN([PHP_TEST_BUILD], [ LIBS="$4 $LIBS" AC_LINK_IFELSE([AC_LANG_SOURCE([[ $5 - char $1(); - int main() { + char $1(void); + int main(void) { $1(); return 0; } @@ -2296,7 +2296,7 @@ AC_DEFUN([PHP_TEST_WRITE_STDOUT],[ #define TEXT "This is the test message -- " -int main() +int main(void) { int n; diff --git a/configure.ac b/configure.ac index 701e6d5b966a2..de0eac8498ec8 100644 --- a/configure.ac +++ b/configure.ac @@ -1120,7 +1120,7 @@ case $host_alias in save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-zcommon-page-size=2097152 -Wl,-zmax-page-size=2097152" AC_RUN_IFELSE( - [AC_LANG_SOURCE([[int main() {return 0;}]])], + [AC_LANG_PROGRAM()], [ac_cv_common_page_size=yes], [ac_cv_common_page_size=no], [ac_cv_common_page_size=no]) @@ -1134,7 +1134,7 @@ case $host_alias in save_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-zmax-page-size=2097152" AC_RUN_IFELSE( - [AC_LANG_SOURCE([[int main() {return 0;}]])], + [AC_LANG_PROGRAM()], [ac_cv_max_page_size=yes], [ac_cv_max_page_size=no], [ac_cv_max_page_size=no]) diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index 9bdd6bb11c04d..a8b1c76d2d131 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -239,7 +239,7 @@ dnl Various checks for GD features PHP_TEST_BUILD(foobar, [], [ AC_MSG_ERROR([GD build test failed. Please check the config.log for details.]) - ], [ $GD_SHARED_LIBADD ], [char foobar () {}]) + ], [ $GD_SHARED_LIBADD ], [char foobar (void) {}]) else extra_sources="gd_compat.c" diff --git a/ext/iconv/config.m4 b/ext/iconv/config.m4 index ac57c81e7d472..5d408de8331d9 100644 --- a/ext/iconv/config.m4 +++ b/ext/iconv/config.m4 @@ -30,7 +30,7 @@ if test "$PHP_ICONV" != "no"; then AC_MSG_CHECKING([if using GNU libiconv]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -int main() { +int main(void) { printf("%d", _libiconv_version); return 0; } @@ -90,7 +90,7 @@ int main() { #include #include -int main() { +int main(void) { iconv_t cd; cd = iconv_open( "*blahblah*", "*blahblahblah*" ); if (cd == (iconv_t)(-1)) { @@ -117,7 +117,7 @@ int main() { #include #include -int main() { +int main(void) { iconv_t cd = iconv_open( "UTF-8//IGNORE", "UTF-8" ); if(cd == (iconv_t)-1) { return 1; diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index d35efbc689ed9..6bf07ad35e2e0 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -121,7 +121,7 @@ if test "$PHP_OPCACHE" != "no"; then #include #include -int main() { +int main(void) { pid_t pid; int status; int ipc_id; @@ -200,7 +200,7 @@ int main() { # define MAP_FAILED ((void*)-1) #endif -int main() { +int main(void) { pid_t pid; int status; char *shm; @@ -262,7 +262,7 @@ int main() { # define MAP_FAILED ((void*)-1) #endif -int main() { +int main(void) { pid_t pid; int status; int fd; diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 8e77e75134c9e..1f25edb9ee058 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -81,7 +81,7 @@ if test "$PHP_EXTERNAL_LIBCRYPT" != "no"; then #include #include -int main() { +int main(void) { #if HAVE_CRYPT char *encrypted = crypt("rasmuslerdorf","rl"); return !encrypted || strcmp(encrypted,"rl.3StKT.4T8M"); @@ -111,7 +111,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char *encrypted = crypt("rasmuslerdorf","_J9..rasm"); return !encrypted || strcmp(encrypted,"_J9..rasmBYk8r9AiWNc"); @@ -141,7 +141,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[15], answer[40]; char *encrypted; @@ -181,7 +181,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[30], answer[70]; char *encrypted; @@ -218,7 +218,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[21], answer[21+86]; char *encrypted; @@ -254,7 +254,7 @@ int main() { #include #include -int main() { +int main(void) { #if HAVE_CRYPT char salt[21], answer[21+43]; char *encrypted; diff --git a/sapi/fpm/config.m4 b/sapi/fpm/config.m4 index aa2a85d2ca632..e3d52084c8204 100644 --- a/sapi/fpm/config.m4 +++ b/sapi/fpm/config.m4 @@ -90,7 +90,7 @@ AC_DEFUN([AC_FPM_CLOCK], #include #include - int main() + int main(void) { kern_return_t ret; clock_serv_t aClock; mach_timespec_t aTime; ret = host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &aClock); @@ -158,7 +158,7 @@ AC_DEFUN([AC_FPM_TRACE], #define PTRACE_PEEKDATA PT_READ_D #endif - int main() + int main(void) { long v1 = (unsigned int) -1; /* copy will fail if sizeof(long) == 8 and we've got "int ptrace()" */ long v2; @@ -263,7 +263,7 @@ AC_DEFUN([AC_FPM_TRACE], #include #include #include - int main() + int main(void) { long v1 = (unsigned int) -1, v2 = 0; char buf[128]; @@ -604,7 +604,7 @@ if test "$PHP_FPM" != "no"; then AC_CHECK_HEADERS([sys/acl.h]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include - int main() + int main(void) { acl_t acl; acl_entry_t user, group; @@ -623,7 +623,7 @@ if test "$PHP_FPM" != "no"; then AC_MSG_RESULT([yes]) ],[ AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - int main() + int main(void) { acl_t acl; acl_entry_t user, group; From 00799320ec0684a493a114a10e7e122bc4aba459 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 15 Mar 2024 12:52:29 -0400 Subject: [PATCH 44/69] Fix GH-12019: ext/gd/config.m4: don't forget GDLIB_CFLAGS in feature tests In commit 85e5635a, a feature test for the various libgd image formats was added. That test however erroneously omits the GDLIB_CFLAGS (from pkg-config) during compilation. This can lead to build failures and therefore false negatives from the test. Here, we add $GDLIB_CFLAGS to $CFLAGS for the duration of the test. Closes GH-12019 --- NEWS | 3 +++ ext/gd/config.m4 | 3 +++ 2 files changed, 6 insertions(+) diff --git a/NEWS b/NEWS index dd3e7703cd3ed..7c1ccee1c9862 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,9 @@ PHP NEWS . Add some missing ZPP checks. (nielsdos) . Fix potential memory leak in XPath evaluation results. (nielsdos) +- GD: + . Fixed bug GH-12019 (add GDLIB_CFLAGS in feature tests). (Michael Orlitzky) + - Gettext: . Fixed sigabrt raised with dcgettext/dcngettext calls with gettext 0.22.5 with category set to LC_ALL. (David Carlier) diff --git a/ext/gd/config.m4 b/ext/gd/config.m4 index a8b1c76d2d131..42bb64578ce0a 100644 --- a/ext/gd/config.m4 +++ b/ext/gd/config.m4 @@ -150,6 +150,8 @@ dnl or run test insufficient. AC_DEFUN([PHP_GD_CHECK_FORMAT],[ old_LIBS="${LIBS}" LIBS="${LIBS} ${GD_SHARED_LIBADD}" + old_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} ${GDLIB_CFLAGS}" AC_MSG_CHECKING([for working gdImageCreateFrom$1 in libgd]) AC_LANG_PUSH([C]) AC_RUN_IFELSE([AC_LANG_SOURCE([ @@ -180,6 +182,7 @@ int main(int argc, char** argv) { AC_MSG_RESULT([no]) ]) AC_LANG_POP([C]) + CFLAGS="${old_CFLAGS}" LIBS="${old_LIBS}" ]) From 6fb8b9d721d0e0e001780cc0d1f11842aedcff83 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 18 Mar 2024 17:18:33 +0100 Subject: [PATCH 45/69] Fix possible segfault with 0x0 shared opcache base Moving the minimum base of the shared opcache memory to the second huge page to avoid a possible 0x0 base, which may cause all sorts of segfaults. This is not a problem on most systems which have a mmap_min_addr which is non-zero, but e.g. WSL1 doesn't have a minimum mapping address. --- ext/opcache/shared_alloc_mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index 6f01f1d631b74..1840b214705fa 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -49,7 +49,7 @@ static void *find_prefered_mmap_base(size_t requested_size) { size_t huge_page_size = 2 * 1024 * 1024; - uintptr_t last_free_addr = 0; + uintptr_t last_free_addr = huge_page_size; uintptr_t last_candidate = (uintptr_t)MAP_FAILED; uintptr_t start, end, text_start = 0; #if defined(__linux__) From 10d912d6e3cbd20458308776712389724382259c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 18 Mar 2024 19:02:42 +0100 Subject: [PATCH 46/69] Fix GH-13712: Segmentation fault for enabled observers when calling trait method of internal trait when opcache is loaded (#13735) Inherited methods regardless of source must share the original runtime cache. Traits were missed. This adds ZEND_ACC_TRAIT_CLONE to internal functions as well to allow easy distinction of these. --- NEWS | 2 ++ Zend/zend_inheritance.c | 2 +- ext/opcache/tests/gh13712.phpt | 23 +++++++++++++++++++++++ ext/opcache/zend_persist.c | 2 +- 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/tests/gh13712.phpt diff --git a/NEWS b/NEWS index 7c1ccee1c9862..8afb4a4c82506 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ PHP NEWS - Opcache: . Fixed GH-13508 (JITed QM_ASSIGN may be optimized out when op1 is null). (Arnaud, Dmitry) + . Fixed GH-13712 (Segmentation fault for enabled observers when calling trait + method of internal trait when opcache is loaded). (Bob) - PDO: . Fix various PDORow bugs. (Girgias) diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index b34823569fc1c..cec0ffdb1853b 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1917,9 +1917,9 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ } else { new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); memcpy(new_fn, fn, sizeof(zend_op_array)); - new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE; new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE; } + new_fn->common.fn_flags |= ZEND_ACC_TRAIT_CLONE; /* Reassign method name, in case it is an alias. */ new_fn->common.function_name = name; diff --git a/ext/opcache/tests/gh13712.phpt b/ext/opcache/tests/gh13712.phpt new file mode 100644 index 0000000000000..e770375e33e46 --- /dev/null +++ b/ext/opcache/tests/gh13712.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-13712 (Segmentation fault for enabled observers when calling trait method of internal trait when opcache is loaded) +--EXTENSIONS-- +opcache +zend_test +--INI-- +zend_test.observer.enabled=1 +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- +testMethod()); +?> +--EXPECTF-- + + + +bool(true) diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 149bcb730bee1..87f1aee1480bc 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -726,7 +726,7 @@ static void zend_persist_class_method(zval *zv, zend_class_entry *ce) } // Real dynamically created internal functions like enum methods must have their own run_time_cache pointer. They're always on the same scope as their defining class. // However, copies - as caused by inheritance of internal methods - must retain the original run_time_cache pointer, shared with the source function. - if (!op_array->scope || op_array->scope == ce) { + if (!op_array->scope || (op_array->scope == ce && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE))) { ZEND_MAP_PTR_NEW(op_array->run_time_cache); } } From 059bf33e6054d8aab3f42204a85c76da3e5f86de Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 18 Mar 2024 20:24:23 +0100 Subject: [PATCH 47/69] Properly forward the signal to the original handler if TSRM is shutdown. (#10219) This ensures proper handling of SIGQUIT in ZTS fpm builds outside of active requests. --- Zend/zend_signal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Zend/zend_signal.c b/Zend/zend_signal.c index 0990999e0116a..e32ffeff9c6b6 100644 --- a/Zend/zend_signal.c +++ b/Zend/zend_signal.c @@ -183,8 +183,7 @@ static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context) zend_signal_entry_t p_sig; #ifdef ZTS if (tsrm_is_shutdown() || !tsrm_get_ls_cache()) { - p_sig.flags = 0; - p_sig.handler = SIG_DFL; + p_sig = global_orig_handlers[signo-1]; } else #endif p_sig = SIGG(handlers)[signo-1]; From 697d1a1c637ff11844f409fc1f3c450def883f7b Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 18 Mar 2024 20:10:26 +0100 Subject: [PATCH 48/69] Fix ASan build See https://github.com/actions/runner-images/issues/9491#issuecomment-1989718917 The mentioned workaround doesn't work for us because we run ASan inside Docker. Instead, we switch to ubuntu-20.04 as the host. The docker setup itself remains the same. Closes GH-13757 --- .github/workflows/push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index eb8c4929a1305..58e32a2a847a3 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -72,7 +72,7 @@ jobs: zts: true asan: true name: "LINUX_X64_${{ matrix.debug && 'DEBUG' || 'RELEASE' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}${{ matrix.asan && '_ASAN' || '' }}" - runs-on: ubuntu-22.04 + runs-on: ubuntu-${{ !matrix.asan && '22' || '20' }}.04 container: image: ${{ matrix.asan && 'ubuntu:23.04' || null }} steps: From db063cb771cae469d7816e4d3887903a7ceb8344 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 7 Mar 2024 21:01:27 +0000 Subject: [PATCH 49/69] CI: update freebsd 13 image. 13.2 is going to be EOL. close GH-13622 --- .cirrus.yml | 4 ++-- ext/curl/tests/curl_setopt_ssl.phpt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 02440c2a3e3d6..a5209930b6e44 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,7 +4,7 @@ env: freebsd_task: name: FREEBSD_DEBUG_NTS freebsd_instance: - image_family: freebsd-13-2 + image_family: freebsd-13-3 env: ARCH: amd64 install_script: @@ -14,7 +14,7 @@ freebsd_task: - pkg install -y autoconf bison gmake re2c icu libiconv png freetype2 enchant2 bzip2 krb5 t1lib gmp tidyp libsodium libzip libxml2 libxslt openssl oniguruma pkgconf webp libavif script: - ./buildconf -f - - ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-dl-test=shared --enable-intl --with-mhash --with-sodium --enable-werror --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d + - ./configure --prefix=/usr/local --enable-debug --enable-option-checking=fatal --enable-fpm --with-pdo-sqlite --without-pear --with-bz2 --with-avif --with-jpeg --with-webp --with-freetype --enable-gd --enable-exif --with-zip --with-zlib --enable-soap --enable-xmlreader --with-xsl --with-libxml --enable-shmop --enable-pcntl --enable-mbstring --with-curl --enable-sockets --with-openssl --with-iconv=/usr/local --enable-bcmath --enable-calendar --enable-ftp --with-kerberos --with-ffi --enable-zend-test --enable-dl-test=shared --enable-intl --with-mhash --with-sodium --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d - gmake -j2 - mkdir /etc/php.d - gmake install diff --git a/ext/curl/tests/curl_setopt_ssl.phpt b/ext/curl/tests/curl_setopt_ssl.phpt index 2e28466a84057..11d8fff702a88 100644 --- a/ext/curl/tests/curl_setopt_ssl.phpt +++ b/ext/curl/tests/curl_setopt_ssl.phpt @@ -9,6 +9,7 @@ exec('openssl version', $out, $code); if ($code > 0) die("skip couldn't locate openssl binary"); if (PHP_OS_FAMILY === 'Windows') die('skip not for Windows'); if (PHP_OS_FAMILY === 'Darwin') die('skip Fails intermittently on macOS'); +if (PHP_OS === 'FreeBSD') die('skip proc_open seems to be stuck on FreeBSD'); $curl_version = curl_version(); if ($curl_version['version_number'] < 0x074700) { die("skip: blob options not supported for curl < 7.71.0"); @@ -237,4 +238,4 @@ bool(true) bool(true) bool(true) client cert subject not in response -CURL ERROR: 83 \ No newline at end of file +CURL ERROR: 83 From 3301d9602a2307007858c299c41795d3d95e3843 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 12 Mar 2024 16:32:25 +0100 Subject: [PATCH 50/69] Restore error handler after running it Symfony relies on finding the exception handler in the handler stack. There's currently no clean API to find it, so they pop all the handlers, and push them again once the stack is empty. This PR attempts to minimize the BC break by pushing the current handler onto the stack and clearing the current handler, and restoring it once it has finished. This is essentially equivalent to set_exception_handler(null) and restore_exception_handler(). restore_exception_handler() however is only called if the exception handler is still unset. If the handler has pushed a new handler in the meantime, we assume it knows what it's doing. Fixes GH-13446 Closes GH-13686 --- NEWS | 1 + Zend/tests/gh13446_1.phpt | 19 +++++++++++++++++++ Zend/tests/gh13446_2.phpt | 16 ++++++++++++++++ Zend/tests/gh13446_3.phpt | 25 +++++++++++++++++++++++++ Zend/tests/gh13446_4.phpt | 21 +++++++++++++++++++++ Zend/zend.c | 10 +++++++++- 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh13446_1.phpt create mode 100644 Zend/tests/gh13446_2.phpt create mode 100644 Zend/tests/gh13446_3.phpt create mode 100644 Zend/tests/gh13446_4.phpt diff --git a/NEWS b/NEWS index 14d9aa5ef6fae..bc19e3916030c 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ PHP NEWS scanning WeakMaps). (Arnaud) . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). (nielsdos) + . Fixed bug GH-13446 (Restore exception handler after it finishes). (ilutov) - DOM: . Add some missing ZPP checks. (nielsdos) diff --git a/Zend/tests/gh13446_1.phpt b/Zend/tests/gh13446_1.phpt new file mode 100644 index 0000000000000..cb51d041c969f --- /dev/null +++ b/Zend/tests/gh13446_1.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-13446: Exception handler is restored after is has finished +--FILE-- +getMessage(), "\n"; +} +set_exception_handler('exception_handler'); + +register_shutdown_function(function () { + echo set_exception_handler(null), "\n"; + restore_exception_handler(); +}); + +throw new Exception('Test'); +?> +--EXPECT-- +Exception caught: Test +exception_handler diff --git a/Zend/tests/gh13446_2.phpt b/Zend/tests/gh13446_2.phpt new file mode 100644 index 0000000000000..c1bab44ce80bf --- /dev/null +++ b/Zend/tests/gh13446_2.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-13446: Exception handler attempting to free itself +--FILE-- + +--EXPECT-- +object(stdClass)#1 (0) { +} diff --git a/Zend/tests/gh13446_3.phpt b/Zend/tests/gh13446_3.phpt new file mode 100644 index 0000000000000..eb56eb1b32d89 --- /dev/null +++ b/Zend/tests/gh13446_3.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-13446: Exception handler isn't restored if it is previously modified +--FILE-- + +--EXPECT-- +Handler 1 +exception_handler_2 diff --git a/Zend/tests/gh13446_4.phpt b/Zend/tests/gh13446_4.phpt new file mode 100644 index 0000000000000..634d16f38a0a3 --- /dev/null +++ b/Zend/tests/gh13446_4.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-13446: Exception handler isn't restored if stack is empty +--FILE-- + +--EXPECT-- +Handler +NULL diff --git a/Zend/zend.c b/Zend/zend.c index d154c67382a72..28922647bba1d 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1839,7 +1839,9 @@ ZEND_API ZEND_COLD void zend_user_exception_handler(void) /* {{{ */ old_exception = EG(exception); EG(exception) = NULL; ZVAL_OBJ(¶ms[0], old_exception); + ZVAL_COPY_VALUE(&orig_user_exception_handler, &EG(user_exception_handler)); + zend_stack_push(&EG(user_exception_handlers), &orig_user_exception_handler); ZVAL_UNDEF(&EG(user_exception_handler)); if (call_user_function(CG(function_table), NULL, &orig_user_exception_handler, &retval2, 1, params) == SUCCESS) { @@ -1853,7 +1855,13 @@ ZEND_API ZEND_COLD void zend_user_exception_handler(void) /* {{{ */ EG(exception) = old_exception; } - zval_ptr_dtor(&orig_user_exception_handler); + if (Z_TYPE(EG(user_exception_handler)) == IS_UNDEF) { + zval *tmp = zend_stack_top(&EG(user_exception_handlers)); + if (tmp) { + ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp); + zend_stack_del_top(&EG(user_exception_handlers)); + } + } } /* }}} */ ZEND_API zend_result zend_execute_scripts(int type, zval *retval, int file_count, ...) /* {{{ */ From 741570c30fffc77b67954ff8938d410cc0ff8329 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Tue, 19 Mar 2024 21:20:38 +0100 Subject: [PATCH 51/69] Fix phpdoc for DOMDocument load methods Closes GH-13763. --- NEWS | 1 + ext/dom/php_dom.stub.php | 16 ++++++++-------- ext/dom/php_dom_arginfo.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 8afb4a4c82506..72d6f9a3971c6 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ PHP NEWS - DOM: . Add some missing ZPP checks. (nielsdos) . Fix potential memory leak in XPath evaluation results. (nielsdos) + . Fix phpdoc for DOMDocument load methods. (VincentLanglet) - GD: . Fixed bug GH-12019 (add GDLIB_CFLAGS in feature tests). (Michael Orlitzky) diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 9806a863a293b..0ed7b4544a501 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -743,11 +743,11 @@ public function getElementsByTagNameNS(?string $namespace, string $localName): D /** @return DOMNode|false */ public function importNode(DOMNode $node, bool $deep = false) {} - /** @return DOMDocument|bool */ - public function load(string $filename, int $options = 0) {} // TODO return type shouldn't depend on the call scope + /** @return bool */ + public function load(string $filename, int $options = 0) {} - /** @return DOMDocument|bool */ - public function loadXML(string $source, int $options = 0) {} // TODO return type shouldn't depend on the call scope + /** @return bool */ + public function loadXML(string $source, int $options = 0) {} /** @tentative-return-type */ public function normalizeDocument(): void {} @@ -759,11 +759,11 @@ public function registerNodeClass(string $baseClass, ?string $extendedClass): bo public function save(string $filename, int $options = 0): int|false {} #ifdef LIBXML_HTML_ENABLED - /** @return DOMDocument|bool */ - public function loadHTML(string $source, int $options = 0) {} // TODO return type shouldn't depend on the call scope + /** @return bool */ + public function loadHTML(string $source, int $options = 0) {} - /** @return DOMDocument|bool */ - public function loadHTMLFile(string $filename, int $options = 0) {} // TODO return type shouldn't depend on the call scope + /** @return bool */ + public function loadHTMLFile(string $filename, int $options = 0) {} /** @tentative-return-type */ public function saveHTML(?DOMNode $node = null): string|false {} diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index 6618238991dcc..6aa7f2eb8a388 100644 --- a/ext/dom/php_dom_arginfo.h +++ b/ext/dom/php_dom_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 3f579ee4c3aef3bde54e9a50d23432f1bd782929 */ + * Stub hash: 7d4dc9e1a3736f2ac9082c32bf5260dfa58b1aa0 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_dom_import_simplexml, 0, 1, DOMElement, 0) ZEND_ARG_TYPE_INFO(0, node, IS_OBJECT, 0) From 09a36812c1c4f6f775308ba31743f257ced24440 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Fri, 22 Mar 2024 10:30:00 +0100 Subject: [PATCH 52/69] Fix AX_GCC_FUNC_ATTRIBUTE failure --- build/ax_gcc_func_attribute.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ax_gcc_func_attribute.m4 b/build/ax_gcc_func_attribute.m4 index 79478f56b8bfd..79f3eef82bc06 100644 --- a/build/ax_gcc_func_attribute.m4 +++ b/build/ax_gcc_func_attribute.m4 @@ -216,7 +216,7 @@ AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ static int bar( void ) __attribute__(($1("foo"))); ], [target], [ - static int bar( void ) __attribute__(($1("sse2"))); + int bar( void ) __attribute__(($1("sse2"))); ], [ m4_warn([syntax], [Unsupported attribute $1, the test may fail]) From 8ffac997aa8d59a750ac9a62c7af0ec315fdd799 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 22 Mar 2024 00:36:22 +0100 Subject: [PATCH 53/69] Fix incorrect charset length in check_mb_eucjpms() Closes GH-13781. --- NEWS | 1 + ext/mysqlnd/mysqlnd_charset.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 72d6f9a3971c6..add6fdb57ba1d 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,7 @@ PHP NEWS - MySQLnd: . Fix GH-13452 (Fixed handshake response [mysqlnd]). (Saki Takamachi) + . Fix incorrect charset length in check_mb_eucjpms(). (nielsdos) - Opcache: . Fixed GH-13508 (JITed QM_ASSIGN may be optimized out when op1 is null). diff --git a/ext/mysqlnd/mysqlnd_charset.c b/ext/mysqlnd/mysqlnd_charset.c index 802822128be2e..2d826002686b4 100644 --- a/ext/mysqlnd/mysqlnd_charset.c +++ b/ext/mysqlnd/mysqlnd_charset.c @@ -270,7 +270,7 @@ static unsigned int check_mb_eucjpms(const char * const start, const char * cons } if (valid_eucjpms_ss3(start[0]) && (end - start) > 2 && valid_eucjpms(start[1]) && valid_eucjpms(start[2])) { - return 2; + return 3; } return 0; } From 6f11cc46e0a7d79a0a83b36d882cad9494120212 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Fri, 22 Mar 2024 11:39:17 +0100 Subject: [PATCH 54/69] [ci skip] NEWS --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index add6fdb57ba1d..4854d790c59ab 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - Core: . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). (nielsdos) + . Fixed bug GH-13784 (AX_GCC_FUNC_ATTRIBUTE failure). (Remi) - DOM: . Add some missing ZPP checks. (nielsdos) From c007dca32d0044e30aaae49154f2b0b0869af475 Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Fri, 22 Mar 2024 11:39:46 +0100 Subject: [PATCH 55/69] [ci skip] NEWS --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 9173be795ce91..8e1e9c6dbba50 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ PHP NEWS . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). (nielsdos) . Fixed bug GH-13446 (Restore exception handler after it finishes). (ilutov) + . Fixed bug GH-13784 (AX_GCC_FUNC_ATTRIBUTE failure). (Remi) - DOM: . Add some missing ZPP checks. (nielsdos) From dd3aa18545797bb36a2f5995a1240ed22b03e177 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 24 Mar 2024 13:57:08 +0100 Subject: [PATCH 56/69] Fix incorrect check in fpm_shm_free() (#13797) `if (fpm_shm_size - size > 0)` will be rewritten by the compiler as this: `if (fpm_shm_size != size)`, which is undesirable. The reason this happens is that both variables are size_t, so subtracting them cannot be negative. The only way it can be not > 0, is if they're equal because the result will then be 0. This means that the else branch won't work properly. E.g. if `fpm_shm_size == 50` and `size == 51`, then `fpm_shm_size` will wraparound instead of becoming zero. To showcase that the compiler actually does this, take a look at this isolated case: https://godbolt.org/z/azobdWcrY. Here we can see the usage of the compare instruction + cmove, so the "then" branch is only done if the variables are equal. --- sapi/fpm/fpm/fpm_shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sapi/fpm/fpm/fpm_shm.c b/sapi/fpm/fpm/fpm_shm.c index 386fef8c49fa2..7b27978084367 100644 --- a/sapi/fpm/fpm/fpm_shm.c +++ b/sapi/fpm/fpm/fpm_shm.c @@ -50,7 +50,7 @@ int fpm_shm_free(void *mem, size_t size) /* {{{ */ return 0; } - if (fpm_shm_size - size > 0) { + if (fpm_shm_size > size) { fpm_shm_size -= size; } else { fpm_shm_size = 0; From e3fbfddbd2d93fa78ea274b87cc416a1ab4ac85a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 24 Mar 2024 13:58:09 +0100 Subject: [PATCH 57/69] [ci skip] NEWS --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 4854d790c59ab..d83614b3660be 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,9 @@ PHP NEWS . Fix potential memory leak in XPath evaluation results. (nielsdos) . Fix phpdoc for DOMDocument load methods. (VincentLanglet) +- FPM + . Fix incorrect check in fpm_shm_free(). (nielsdos) + - GD: . Fixed bug GH-12019 (add GDLIB_CFLAGS in feature tests). (Michael Orlitzky) From c13794cdcb1ddcd9ddcd5a14da99a904b8c91aac Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 25 Mar 2024 16:17:54 +0100 Subject: [PATCH 58/69] Adjust GC threshold if num_roots is higher than gc_threshold after collection (#13758) This fixes an edge case causing the GC to be triggered repeatedly. Destructors might add potential garbage to the buffer, so it may happen that num_root it higher than gc_threshold after collection, thus triggering a GC run almost immediately. This can happen by touching enough objects in a destructor, e.g. by iterating over an array. If this happens again in the new run, and the threshold is not updated, the GC may be triggered again. The edge case requires specific conditions to be triggered and it must happen rarely in practice: * At least GC_THRESHOLD_TRIGGER (100) objects must be collected during each run for the threshold to not be updated * At least GC_G(gc_threshold) (initially 10k) objects must be touched (decref'ed to n>0) by any destructor during each run to fill the buffer The fix is to increase the threshold if GC_G(num_roots) >= GC_G(gc_threshold) after GC. The threshold eventually reaches a point at which the second condition is not met anymore. The included tests trigger more than 200 GC runs before the fix, and 2 after the fix (dtors always trigger a second run). A related issue is that zend_gc_check_root_tmpvars() may add potential garbage before the threshold is adjusted, which may trigger GC and exhaust the stack. This is fixed by setting GC_G(active)=1 around zend_gc_check_root_tmpvars(). --- Zend/tests/gh13670_001.phpt | 43 +++++++++++++++++++++++ Zend/tests/gh13670_002.phpt | 66 +++++++++++++++++++++++++++++++++++ Zend/tests/gh13670_003.phpt | 68 +++++++++++++++++++++++++++++++++++++ Zend/zend_gc.c | 8 ++++- 4 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh13670_001.phpt create mode 100644 Zend/tests/gh13670_002.phpt create mode 100644 Zend/tests/gh13670_003.phpt diff --git a/Zend/tests/gh13670_001.phpt b/Zend/tests/gh13670_001.phpt new file mode 100644 index 0000000000000..def8fa3f5f25e --- /dev/null +++ b/Zend/tests/gh13670_001.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-13670 001 +--FILE-- +self = $this; + } + public function __destruct() { + global $shutdown; + if (!$shutdown) { + new Cycle(); + } + } +} + +$defaultThreshold = gc_status()['threshold']; +for ($i = 0; $i < $defaultThreshold+1; $i++) { + new Cycle(); +} + +$objs = []; +for ($i = 0; $i < 100; $i++) { + $obj = new stdClass; + $objs[] = $obj; +} + +$st = gc_status(); + +if ($st['runs'] > 10) { + var_dump($st); +} +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/gh13670_002.phpt b/Zend/tests/gh13670_002.phpt new file mode 100644 index 0000000000000..c822585e3632f --- /dev/null +++ b/Zend/tests/gh13670_002.phpt @@ -0,0 +1,66 @@ +--TEST-- +GH-13670 002 +--FILE-- +self = $this; + } +} + +class Canary { + public $self; + public function __construct() { + $this->self = $this; + } + public function __destruct() { + global $shutdown; + if (!$shutdown) { + work(); + } + } +} + +function work() { + global $objs, $defaultThreshold; + new Canary(); + // Create some collectable garbage so the next run will not adjust + // threshold + for ($i = 0; $i < 100; $i++) { + new Cycle(); + } + // Add potential garbage to buffer + foreach (array_slice($objs, 0, $defaultThreshold) as $obj) { + $o = $obj; + } +} + +$defaultThreshold = gc_status()['threshold']; +$objs = []; +for ($i = 0; $i < $defaultThreshold*2; $i++) { + $obj = new stdClass; + $objs[] = $obj; +} + +work(); + +foreach ($objs as $obj) { + $o = $obj; +} + +$st = gc_status(); + +if ($st['runs'] > 10) { + var_dump($st); +} +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/gh13670_003.phpt b/Zend/tests/gh13670_003.phpt new file mode 100644 index 0000000000000..defd3da438678 --- /dev/null +++ b/Zend/tests/gh13670_003.phpt @@ -0,0 +1,68 @@ +--TEST-- +GH-13670 003 +--FILE-- +self = $this; + } +} + +class Canary { + public $self; + public function __construct() { + $this->self = $this; + } + public function __destruct() { + global $shutdown; + if (!$shutdown) { + work(); + } + } +} + +function work() { + global $objs, $defaultThreshold; + new Canary(); + // Create some collectable garbage so the next run will not adjust + // threshold + for ($i = 0; $i < 100; $i++) { + new Cycle(); + } + // Add potential garbage to buffer + foreach (array_slice($objs, 0, $defaultThreshold) as $obj) { + $o = $obj; + } +} + +$defaultThreshold = gc_status()['threshold']; +$objs = []; +for ($i = 0; $i < $defaultThreshold*2; $i++) { + $obj = new stdClass; + $objs[] = $obj; +} + +work(); + +// Result of array_slice() is a tmpvar that will be checked by +// zend_gc_check_root_tmpvars() +foreach (array_slice($objs, -10) as $obj) { + $o = $obj; +} + +$st = gc_status(); + +if ($st['runs'] > 10) { + var_dump($st); +} +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index e7d9c8ef29257..4417f674cbb91 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -557,7 +557,7 @@ static void gc_adjust_threshold(int count) /* TODO Very simple heuristic for dynamic GC buffer resizing: * If there are "too few" collections, increase the collection threshold * by a fixed step */ - if (count < GC_THRESHOLD_TRIGGER) { + if (count < GC_THRESHOLD_TRIGGER || GC_G(num_roots) >= GC_G(gc_threshold)) { /* increase */ if (GC_G(gc_threshold) < GC_THRESHOLD_MAX) { new_threshold = GC_G(gc_threshold) + GC_THRESHOLD_STEP; @@ -1674,7 +1674,13 @@ ZEND_API int zend_gc_collect_cycles(void) finish: zend_get_gc_buffer_release(); + + /* Prevent GC from running during zend_gc_check_root_tmpvars, before + * gc_threshold is adjusted, as this may result in unbounded recursion */ + GC_G(gc_active) = 1; zend_gc_check_root_tmpvars(); + GC_G(gc_active) = 0; + return total_count; } From f968a6316291024fe90d97de3fa26044f0b03e05 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 25 Mar 2024 16:19:32 +0100 Subject: [PATCH 59/69] [ci skip] --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index d83614b3660be..d73bb484d204f 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). (nielsdos) . Fixed bug GH-13784 (AX_GCC_FUNC_ATTRIBUTE failure). (Remi) + . Fixed bug GH-13670 (GC does not scale well with a lot of objects created in + destructor). (Arnaud) - DOM: . Add some missing ZPP checks. (nielsdos) From ff2359b62e999c38598db16e60c3cc6818477224 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Mon, 25 Mar 2024 16:23:44 +0100 Subject: [PATCH 60/69] [ci skip] --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 1643de8813dbb..22155e47db975 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,8 @@ PHP NEWS (nielsdos) . Fixed bug GH-13446 (Restore exception handler after it finishes). (ilutov) . Fixed bug GH-13784 (AX_GCC_FUNC_ATTRIBUTE failure). (Remi) + . Fixed bug GH-13670 (GC does not scale well with a lot of objects created in + destructor). (Arnaud) - DOM: . Add some missing ZPP checks. (nielsdos) From bb6b659aa80338e1d91c1a84a70b281a8d0383a6 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 26 Mar 2024 12:33:44 +0100 Subject: [PATCH 61/69] Tests are not repeatable gc_threshold is inherited accross requests, so the tests fail when repeating --- Zend/tests/gh13670_001.phpt | 5 +++++ Zend/tests/gh13670_002.phpt | 5 +++++ Zend/tests/gh13670_003.phpt | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/Zend/tests/gh13670_001.phpt b/Zend/tests/gh13670_001.phpt index def8fa3f5f25e..f1cd32ea8bc0e 100644 --- a/Zend/tests/gh13670_001.phpt +++ b/Zend/tests/gh13670_001.phpt @@ -1,5 +1,10 @@ --TEST-- GH-13670 001 +--SKIPIF-- + --FILE-- --FILE-- --FILE-- Date: Tue, 26 Mar 2024 08:49:44 -0400 Subject: [PATCH 62/69] PHP-8.2 is now for PHP 8.2.19-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index d73bb484d204f..bdc2cd8efa244 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.18 +?? ??? ????, PHP 8.2.19 + + +11 Apr 2024, PHP 8.2.18 - Core: . Fixed bug GH-13612 (Corrupted memory in destructor with weak references). diff --git a/Zend/zend.h b/Zend/zend.h index 12a467ee8a44e..ad8fde7a8ad1c 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.18-dev" +#define ZEND_VERSION "4.2.19-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index de0eac8498ec8..683029f476a94 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.18-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.19-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 c5491beea546d..a17d49197da51 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 18 +#define PHP_RELEASE_VERSION 19 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.18-dev" -#define PHP_VERSION_ID 80218 +#define PHP_VERSION "8.2.19-dev" +#define PHP_VERSION_ID 80219 From 0d89b54759f9816f6dd126bb5458fe93479d3f3f Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 15 Feb 2024 23:53:49 +0000 Subject: [PATCH 63/69] Add proc_open escaping for cmd file execution --- ext/standard/proc_open.c | 86 +++++++++++++++++-- .../ghsa-pc52-254m-w9w7_1.phpt | 29 +++++++ .../ghsa-pc52-254m-w9w7_2.phpt | 29 +++++++ .../ghsa-pc52-254m-w9w7_3.phpt | 29 +++++++ 4 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt create mode 100644 ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt create mode 100644 ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 78d2db999eab6..3feac72122276 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -538,11 +538,32 @@ static void append_backslashes(smart_str *str, size_t num_bs) } } -/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments */ -static void append_win_escaped_arg(smart_str *str, zend_string *arg) +const char *special_chars = "()!^\"<>&|%"; + +static bool is_special_character_present(const zend_string *arg) +{ + for (size_t i = 0; i < ZSTR_LEN(arg); ++i) { + if (strchr(special_chars, ZSTR_VAL(arg)[i]) != NULL) { + return true; + } + } + return false; +} + +/* See https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments and + * https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way */ +static void append_win_escaped_arg(smart_str *str, zend_string *arg, bool is_cmd_argument) { size_t num_bs = 0; + bool has_special_character = false; + if (is_cmd_argument) { + has_special_character = is_special_character_present(arg); + if (has_special_character) { + /* Escape double quote with ^ if executed by cmd.exe. */ + smart_str_appendc(str, '^'); + } + } smart_str_appendc(str, '"'); for (size_t i = 0; i < ZSTR_LEN(arg); ++i) { char c = ZSTR_VAL(arg)[i]; @@ -556,18 +577,71 @@ static void append_win_escaped_arg(smart_str *str, zend_string *arg) num_bs = num_bs * 2 + 1; } append_backslashes(str, num_bs); + if (has_special_character && strchr(special_chars, c) != NULL) { + /* Escape special chars with ^ if executed by cmd.exe. */ + smart_str_appendc(str, '^'); + } smart_str_appendc(str, c); num_bs = 0; } append_backslashes(str, num_bs * 2); + if (has_special_character) { + /* Escape double quote with ^ if executed by cmd.exe. */ + smart_str_appendc(str, '^'); + } smart_str_appendc(str, '"'); } +static inline int stricmp_end(const char* suffix, const char* str) { + size_t suffix_len = strlen(suffix); + size_t str_len = strlen(str); + + if (suffix_len > str_len) { + return -1; /* Suffix is longer than string, cannot match. */ + } + + /* Compare the end of the string with the suffix, ignoring case. */ + return _stricmp(str + (str_len - suffix_len), suffix); +} + +static bool is_executed_by_cmd(const char *prog_name) +{ + /* If program name is cmd.exe, then return true. */ + if (_stricmp("cmd.exe", prog_name) == 0 || _stricmp("cmd", prog_name) == 0 + || stricmp_end("\\cmd.exe", prog_name) == 0 || stricmp_end("\\cmd", prog_name) == 0) { + return true; + } + + /* Find the last occurrence of the directory separator (backslash or forward slash). */ + char *last_separator = strrchr(prog_name, '\\'); + char *last_separator_fwd = strrchr(prog_name, '/'); + if (last_separator_fwd && (!last_separator || last_separator < last_separator_fwd)) { + last_separator = last_separator_fwd; + } + + /* Find the last dot in the filename after the last directory separator. */ + char *extension = NULL; + if (last_separator != NULL) { + extension = strrchr(last_separator, '.'); + } else { + extension = strrchr(prog_name, '.'); + } + + if (extension == NULL || extension == prog_name) { + /* No file extension found, it is not batch file. */ + return false; + } + + /* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */ + return _stricmp(extension, ".bat") == 0 || _stricmp(extension, ".cmd") == 0; +} + static zend_string *create_win_command_from_args(HashTable *args) { smart_str str = {0}; zval *arg_zv; - bool is_prog_name = 1; + bool is_prog_name = true; + bool is_cmd_execution = false; int elem_num = 0; ZEND_HASH_FOREACH_VAL(args, arg_zv) { @@ -577,11 +651,13 @@ static zend_string *create_win_command_from_args(HashTable *args) return NULL; } - if (!is_prog_name) { + if (is_prog_name) { + is_cmd_execution = is_executed_by_cmd(ZSTR_VAL(arg_str)); + } else { smart_str_appendc(&str, ' '); } - append_win_escaped_arg(&str, arg_str); + append_win_escaped_arg(&str, arg_str, !is_prog_name && is_cmd_execution); is_prog_name = 0; zend_string_release(arg_str); diff --git a/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt new file mode 100644 index 0000000000000..8d0939cdf1bc7 --- /dev/null +++ b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_1.phpt @@ -0,0 +1,29 @@ +--TEST-- +GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for bat files +--SKIPIF-- + +--FILE-- + +--EXPECT-- +"¬epad.exe +--CLEAN-- + diff --git a/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt new file mode 100644 index 0000000000000..a1e39d7ef9ba0 --- /dev/null +++ b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_2.phpt @@ -0,0 +1,29 @@ +--TEST-- +GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd files +--SKIPIF-- + +--FILE-- +^()!.exe"], $descriptorspec, $pipes); +proc_close($proc); + +?> +--EXPECT-- +"¬epad<>^()!.exe +--CLEAN-- + diff --git a/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt new file mode 100644 index 0000000000000..69f12d7b358d2 --- /dev/null +++ b/ext/standard/tests/general_functions/ghsa-pc52-254m-w9w7_3.phpt @@ -0,0 +1,29 @@ +--TEST-- +GHSA-54hq-v5wp-fqgv - proc_open does not correctly escape args for cmd executing batch files +--SKIPIF-- + +--FILE-- + +--EXPECT-- +"¬epad.exe +--CLEAN-- + From f77e5794c450be34bf24d1117131a191b3100b85 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 17 Mar 2024 21:04:47 +0100 Subject: [PATCH 64/69] Fix GHSA-wpj3-hf5j-x4v4: __Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix The check happened too early as later code paths may perform more mangling rules. Move the check downwards right before adding the actual variable. --- ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt | 63 +++++++++++++++++++++ main/php_variables.c | 41 +++++++++----- 2 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt diff --git a/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt new file mode 100644 index 0000000000000..77fcb68089488 --- /dev/null +++ b/ext/standard/tests/ghsa-wpj3-hf5j-x4v4.phpt @@ -0,0 +1,63 @@ +--TEST-- +ghsa-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to partial CVE-2022-31629 fix) +--COOKIE-- +..Host-test=ignore_1; +._Host-test=ignore_2; +.[Host-test=ignore_3; +_.Host-test=ignore_4; +__Host-test=ignore_5; +_[Host-test=ignore_6; +[.Host-test=ignore_7; +[_Host-test=ignore_8; +[[Host-test=ignore_9; +..Host-test[]=ignore_10; +._Host-test[]=ignore_11; +.[Host-test[]=ignore_12; +_.Host-test[]=ignore_13; +__Host-test[]=legitimate_14; +_[Host-test[]=legitimate_15; +[.Host-test[]=ignore_16; +[_Host-test[]=ignore_17; +[[Host-test[]=ignore_18; +..Secure-test=ignore_1; +._Secure-test=ignore_2; +.[Secure-test=ignore_3; +_.Secure-test=ignore_4; +__Secure-test=ignore_5; +_[Secure-test=ignore_6; +[.Secure-test=ignore_7; +[_Secure-test=ignore_8; +[[Secure-test=ignore_9; +..Secure-test[]=ignore_10; +._Secure-test[]=ignore_11; +.[Secure-test[]=ignore_12; +_.Secure-test[]=ignore_13; +__Secure-test[]=legitimate_14; +_[Secure-test[]=legitimate_15; +[.Secure-test[]=ignore_16; +[_Secure-test[]=ignore_17; +[[Secure-test[]=ignore_18; +--FILE-- + +--EXPECT-- +array(3) { + ["__Host-test"]=> + array(1) { + [0]=> + string(13) "legitimate_14" + } + ["_"]=> + array(2) { + ["Host-test["]=> + string(13) "legitimate_15" + ["Secure-test["]=> + string(13) "legitimate_15" + } + ["__Secure-test"]=> + array(1) { + [0]=> + string(13) "legitimate_14" + } +} diff --git a/main/php_variables.c b/main/php_variables.c index 22d8ff73fe3a8..dc413a461b2f1 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -89,6 +89,21 @@ PHPAPI void php_register_known_variable(const char *var_name, size_t var_name_le php_register_variable_quick(var_name, var_name_len, value, symbol_table); } +/* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- + * Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */ +static bool php_is_forbidden_variable_name(const char *mangled_name, size_t mangled_name_len, const char *pre_mangled_name) +{ + if (mangled_name_len >= sizeof("__Host-")-1 && strncmp(mangled_name, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(pre_mangled_name, "__Host-", sizeof("__Host-")-1) != 0) { + return true; + } + + if (mangled_name_len >= sizeof("__Secure-")-1 && strncmp(mangled_name, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(pre_mangled_name, "__Secure-", sizeof("__Secure-")-1) != 0) { + return true; + } + + return false; +} + PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *track_vars_array) { char *p = NULL; @@ -139,20 +154,6 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac } var_len = p - var; - /* Discard variable if mangling made it start with __Host-, where pre-mangling it did not start with __Host- */ - if (strncmp(var, "__Host-", sizeof("__Host-")-1) == 0 && strncmp(var_name, "__Host-", sizeof("__Host-")-1) != 0) { - zval_ptr_dtor_nogc(val); - free_alloca(var_orig, use_heap); - return; - } - - /* Discard variable if mangling made it start with __Secure-, where pre-mangling it did not start with __Secure- */ - if (strncmp(var, "__Secure-", sizeof("__Secure-")-1) == 0 && strncmp(var_name, "__Secure-", sizeof("__Secure-")-1) != 0) { - zval_ptr_dtor_nogc(val); - free_alloca(var_orig, use_heap); - return; - } - if (var_len==0) { /* empty variable name, or variable name with a space in it */ zval_ptr_dtor_nogc(val); free_alloca(var_orig, use_heap); @@ -256,6 +257,12 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac return; } } else { + if (php_is_forbidden_variable_name(index, index_len, var_name)) { + zval_ptr_dtor_nogc(val); + free_alloca(var_orig, use_heap); + return; + } + gpc_element_p = zend_symtable_str_find(symtable1, index, index_len); if (!gpc_element_p) { zval tmp; @@ -293,6 +300,12 @@ PHPAPI void php_register_variable_ex(const char *var_name, zval *val, zval *trac zval_ptr_dtor_nogc(val); } } else { + if (php_is_forbidden_variable_name(index, index_len, var_name)) { + zval_ptr_dtor_nogc(val); + free_alloca(var_orig, use_heap); + return; + } + zend_ulong idx; /* From 6a5c04d01d1fa9cdbfde40344c854133011107d1 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 29 Mar 2024 15:27:59 +0000 Subject: [PATCH 65/69] Fix bug GHSA-q6x7-frmf-grcw: password_verify can erroneously return true Disallow null character in bcrypt password --- ext/standard/password.c | 5 +++++ ext/standard/tests/password/password_bcrypt_errors.phpt | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/ext/standard/password.c b/ext/standard/password.c index c3f7f73821839..6eedd8abcc152 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -180,6 +180,11 @@ static zend_string* php_password_bcrypt_hash(const zend_string *password, zend_a zval *zcost; zend_long cost = PHP_PASSWORD_BCRYPT_COST; + if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) { + zend_value_error("Bcrypt password must not contain null character"); + return NULL; + } + if (options && (zcost = zend_hash_str_find(options, "cost", sizeof("cost")-1)) != NULL) { cost = zval_get_long(zcost); } diff --git a/ext/standard/tests/password/password_bcrypt_errors.phpt b/ext/standard/tests/password/password_bcrypt_errors.phpt index 10c3483f5a80d..5d823cba0217d 100644 --- a/ext/standard/tests/password/password_bcrypt_errors.phpt +++ b/ext/standard/tests/password/password_bcrypt_errors.phpt @@ -14,7 +14,14 @@ try { } catch (ValueError $exception) { echo $exception->getMessage() . "\n"; } + +try { + var_dump(password_hash("null\0password", PASSWORD_BCRYPT)); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} ?> --EXPECT-- Invalid bcrypt cost parameter specified: 3 Invalid bcrypt cost parameter specified: 32 +Bcrypt password must not contain null character From f7e73704ad324fa273ad9c4eaa26d6aad0dfe838 Mon Sep 17 00:00:00 2001 From: Alex Dowad Date: Mon, 18 Mar 2024 23:23:28 +0200 Subject: [PATCH 66/69] Fix infinite loop in mb_encode_mimeheader --- ext/mbstring/mbstring.c | 55 +++++++++++-------- .../tests/mb_encode_mimeheader_basic4.phpt | 33 ++++++++++- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index cf4c1c32c5915..618fff55362e1 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -5858,6 +5858,9 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin unsigned char *in = (unsigned char*)ZSTR_VAL(input); size_t in_len = ZSTR_LEN(input); + ZEND_ASSERT(outcode->mime_name != NULL); + ZEND_ASSERT(outcode->mime_name[0] != '\0'); + if (!in_len) { return zend_empty_string; } @@ -5880,7 +5883,8 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin unsigned int state = 0; /* wchar_buf should be big enough that when it is full, we definitely have enough * wchars to fill an entire line of output */ - uint32_t wchar_buf[80]; + const size_t wchar_buf_len = 90; + uint32_t wchar_buf[wchar_buf_len]; uint32_t *p, *e; /* What part of wchar_buf is filled with still-unprocessed data which should not * be overwritten? */ @@ -5891,7 +5895,7 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin * spaces), just pass it through unchanged */ bool checking_leading_spaces = true; while (in_len) { - size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, 80, &state); + size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf, wchar_buf_len, &state); p = wchar_buf; e = wchar_buf + out_len; @@ -5925,9 +5929,9 @@ no_passthrough: ; * do so all the way to the end of the string */ while (in_len) { /* Decode part of the input string, refill wchar_buf */ - ZEND_ASSERT(offset < 80); - size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state); - ZEND_ASSERT(out_len <= 80 - offset); + ZEND_ASSERT(offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len); + size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, wchar_buf_len - offset, &state); + ZEND_ASSERT(out_len <= wchar_buf_len - offset); p = wchar_buf; e = wchar_buf + offset + out_len; /* ASCII output is broken into space-delimited 'words' @@ -5948,6 +5952,7 @@ no_passthrough: ; * If we are already too far along on a line to include Base64/QPrint encoded data * on the same line (without overrunning max line length), then add a line feed * right now */ +feed_and_mime_encode: if (mb_convert_buf_len(&buf) - line_start + indent + strlen(outcode->mime_name) > 55) { MB_CONVERT_BUF_ENSURE(&buf, buf.out, buf.limit, (e - word_start) + linefeed_len + 1); buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); @@ -5985,7 +5990,13 @@ no_passthrough: ; if (in_len) { /* Copy chars which are part of an incomplete 'word' to the beginning - * of wchar_buf and reprocess them on the next iteration */ + * of wchar_buf and reprocess them on the next iteration. + * But first make sure that the incomplete 'word' isn't so big that + * there will be no space to add any more decoded wchars in the buffer + * (which could lead to an infinite loop) */ + if ((word_start - wchar_buf) < MBSTRING_MIN_WCHAR_BUFSIZE) { + goto feed_and_mime_encode; + } offset = e - word_start; if (offset) { memmove(wchar_buf, word_start, offset * sizeof(uint32_t)); @@ -6027,17 +6038,17 @@ mime_encoding_needed: ; /* Do we need to refill wchar_buf to make sure we don't run out of wchars * in the middle of a line? */ - if (p == wchar_buf) { + offset = e - p; + if (wchar_buf_len - offset < MBSTRING_MIN_WCHAR_BUFSIZE) { goto start_new_line; } - offset = e - p; memmove(wchar_buf, p, offset * sizeof(uint32_t)); while(true) { refill_wchar_buf: ; - ZEND_ASSERT(offset < 80); - size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, 80 - offset, &state); - ZEND_ASSERT(out_len <= 80 - offset); + ZEND_ASSERT(offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len); + size_t out_len = incode->to_wchar(&in, &in_len, wchar_buf + offset, wchar_buf_len - offset, &state); + ZEND_ASSERT(out_len <= wchar_buf_len - offset); p = wchar_buf; e = wchar_buf + offset + out_len; @@ -6112,22 +6123,18 @@ start_new_line: ; indent = 0; /* Indent argument must only affect the first line */ - if (in_len) { - /* We still have more of input string remaining to decode */ + if (in_len || p < e) { + /* We still have more input to process */ buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); buf.out = mb_convert_buf_add(buf.out, ' '); line_start = mb_convert_buf_len(&buf); - /* Copy remaining wchars to beginning of buffer so they will be - * processed on the next iteration of outer 'do' loop */ offset = e - p; - memmove(wchar_buf, p, offset * sizeof(uint32_t)); - goto refill_wchar_buf; - } else if (p < e) { - /* Input string is finished, but we still have trailing wchars - * remaining to be processed in wchar_buf */ - buf.out = mb_convert_buf_appendn(buf.out, linefeed, linefeed_len); - buf.out = mb_convert_buf_add(buf.out, ' '); - line_start = mb_convert_buf_len(&buf); + if (in_len && (wchar_buf_len - offset >= MBSTRING_MIN_WCHAR_BUFSIZE)) { + /* Copy any remaining wchars to beginning of buffer and refill + * the rest of the buffer */ + memmove(wchar_buf, p, offset * sizeof(uint32_t)); + goto refill_wchar_buf; + } goto start_new_line; } else { /* We are done! */ @@ -6165,7 +6172,7 @@ PHP_FUNCTION(mb_encode_mimeheader) charset = php_mb_get_encoding(charset_name, 2); if (!charset) { RETURN_THROWS(); - } else if (charset->mime_name == NULL || charset->mime_name[0] == '\0') { + } else if (charset->mime_name == NULL || charset->mime_name[0] == '\0' || charset == &mbfl_encoding_qprint) { zend_argument_value_error(2, "\"%s\" cannot be used for MIME header encoding", ZSTR_VAL(charset_name)); RETURN_THROWS(); } diff --git a/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt b/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt index 7bf05b43ae36b..d9a3407bf3f9f 100644 --- a/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt +++ b/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt @@ -115,11 +115,29 @@ var_dump(mb_encode_mimeheader("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ // In the general case, matching the old implementation's decision to transfer-encode or not // perfectly would require allocating potentially unbounded scratch memory (up to the size of // the input string), but we aim to only use a constant amount of temporarily allocated memory -var_dump(mb_encode_mimeheader("2\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3", "GB18030", "Q", "")); +var_dump(mb_encode_mimeheader("2\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20!3", "GB18030", "Q", "")); + +// Regression test for infinite loop which was unintentionally caused when refactoring +var_dump(mb_encode_mimeheader(",9868949,9868978,9869015,9689100,9869121,9869615,9870690,9867116,98558119861183. ", "utf-8", "B")); +var_dump(mb_encode_mimeheader('xx ' . str_repeat("A", 81) . " ", "utf-8", "B")); + +// Regression test for problem where MIME encoding loop would not leave enough space in wchar +// buffer for the next iteration, causing an assertion failure +mb_internal_encoding('MacJapanese'); +var_dump(mb_encode_mimeheader("ne\xf6\xff\xff\xffs\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff1\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff1", 'CP50220', 'B', "A", 44)); + +// Regression test for failing assertion caused by the fact that QPrint deliberately generates no +// wchars for CR (0x0D) bytes +try { + mb_internal_encoding('Quoted-Printable'); + var_dump(mb_encode_mimeheader("=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=00=00=00=00=00=00=00=01=00=00=00=00=00=00=00850r=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=0D=00=00=00=0050r=08=0DCP850r850r0r", "Quoted-Printable", "B", "", 184)); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} echo "Done"; ?> ---EXPECT-- +--EXPECTF-- string(0) "" string(21) "=?UTF-8?Q?abc=00abc?=" string(16) "=?UTF-8?B?Pw==?=" @@ -156,5 +174,14 @@ string(75) " 111111111111111111111111111111111111111111111111111111111111111111 string(33) "=?HZ-GB-2312?Q?=7E=7Bs=5B=7E=7D?=" string(77) "2 !3" string(282) "=?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20!=33=20?=" -string(296) "2 =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20!=33?=" +string(344) "2 =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?GB18030?Q?=20=20=20=20=20=20=20=20=20!=33?=" +string(135) "=?UTF-8?B?LDk4Njg5NDksOTg2ODk3OCw5ODY5MDE1LDk2ODkxMDAsOTg2OTEyMSw5ODY5?= + =?UTF-8?B?NjE1LDk4NzA2OTAsOTg2NzExNiw5ODU1ODExOTg2MTE4My4g?=" +string(142) "xx =?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= + =?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBIA==?=" +string(690) "=?ISO-2022-JP?B?bmU/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/cxskQiFEGyhCPw==?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/MRskQiFEGyhCPxskQiFEGyhCPw==?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/MQ==?=" + + +Deprecated: mb_encode_mimeheader(): Handling QPrint via mbstring is deprecated; use quoted_printable_encode/quoted_printable_decode instead in %s on line %d +mb_encode_mimeheader(): Argument #2 ($charset) "Quoted-Printable" cannot be used for MIME header encoding Done From 88953d1361fd545ebe7ba3489f7830fe0db017fd Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 6 Apr 2024 23:32:35 +0200 Subject: [PATCH 67/69] Adapt regression test --- ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt b/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt index d9a3407bf3f9f..02206efab3586 100644 --- a/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt +++ b/ext/mbstring/tests/mb_encode_mimeheader_basic4.phpt @@ -2,6 +2,8 @@ Test mb_encode_mimeheader() function : test cases found by fuzzer --EXTENSIONS-- mbstring +--INI-- +error_reporting=E_ALL^E_DEPRECATED --FILE-- ---EXPECTF-- +--EXPECT-- string(0) "" string(21) "=?UTF-8?Q?abc=00abc?=" string(16) "=?UTF-8?B?Pw==?=" @@ -180,8 +182,5 @@ string(135) "=?UTF-8?B?LDk4Njg5NDksOTg2ODk3OCw5ODY5MDE1LDk2ODkxMDAsOTg2OTEyMSw5O string(142) "xx =?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB?= =?UTF-8?B?QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBIA==?=" string(690) "=?ISO-2022-JP?B?bmU/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/cxskQiFEGyhCPw==?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/MRskQiFEGyhCPxskQiFEGyhCPw==?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/GyRCIUQbKEI/?=A =?ISO-2022-JP?B?GyRCIUQbKEI/GyRCIUQbKEI/MQ==?=" - - -Deprecated: mb_encode_mimeheader(): Handling QPrint via mbstring is deprecated; use quoted_printable_encode/quoted_printable_decode instead in %s on line %d mb_encode_mimeheader(): Argument #2 ($charset) "Quoted-Printable" cannot be used for MIME header encoding Done From 9df068821b7c5a3a5b0ea2d78a84a7807776601c Mon Sep 17 00:00:00 2001 From: Eric Mann Date: Tue, 9 Apr 2024 13:49:09 -0700 Subject: [PATCH 68/69] Update NEWS file --- NEWS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NEWS b/NEWS index 22155e47db975..fe0b3f261d717 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,14 @@ PHP NEWS (SakiTakamachi) . Fixed bug GH-13203 (file_put_contents fail on strings over 4GB on Windows). (divinity76) + . Fixed bug GHSA-pc52-254m-w9w7 (Command injection via array-ish $command + parameter of proc_open). (CVE-2024-1874) (Jakub Zelenka) + . Fixed bug GHSA-wpj3-hf5j-x4v4 (__Host-/__Secure- cookie bypass due to + partial CVE-2022-31629 fix). (CVE-2024-2756) (nielsdos) + . Fixed bug GHSA-h746-cjrr-wfmr (password_verify can erroneously return true, + opening ATO risk). (CVE-2024-3096) (Jakub Zelenka) + Fixed bug GHSA-fjp9-9hwx-59fq (mb_encode_mimeheader runs endlessly for some + inputs). (CVE-2024-2757) (Alex Dowad) 14 Mar 2024, PHP 8.3.4 From 9a9c7197c4774c80f622222b3dfa874e6dc44f67 Mon Sep 17 00:00:00 2001 From: Eric Mann Date: Tue, 9 Apr 2024 14:04:01 -0700 Subject: [PATCH 69/69] Update versions for PHP 8.3.5 --- 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 fe0b3f261d717..c5d4f776956b1 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.5 +11 Apr 2024, PHP 8.3.5 - Core: . Fixed GH-13569 (GC buffer unnecessarily grows up to GC_MAX_BUF_SIZE when diff --git a/Zend/zend.h b/Zend/zend.h index 074e1f1680317..3afafa2ca6161 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.5-dev" +#define ZEND_VERSION "4.3.5" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 906c46c2e1d47..ac90dd9c10c88 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.3.5-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.5],[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 e10e9f0a96d1d..53858862da367 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 #define PHP_RELEASE_VERSION 5 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.5-dev" +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.3.5" #define PHP_VERSION_ID 80305