From e07813ad461ea1066c5a46a020b8241197dc7757 Mon Sep 17 00:00:00 2001 From: Pierrick Charron Date: Tue, 16 Jul 2024 12:20:55 -0400 Subject: [PATCH 01/51] PHP-8.2 is now for PHP 8.2.23-dev --- NEWS | 4 +++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 2276e3ff22b69..5b8f429449127 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.22 +?? ??? ????, PHP 8.2.23 + +01 Aug 2024, PHP 8.2.22 - Core: . Fixed bug GH-13922 (Fixed support for systems with diff --git a/Zend/zend.h b/Zend/zend.h index 675dcdd338fa6..c9018454dfc60 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.22-dev" +#define ZEND_VERSION "4.2.23-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index d694a0a7a14ba..8e8682095520a 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.22-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.23-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 8fcd1fa0c4703..5d1d455b26508 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 22 +#define PHP_RELEASE_VERSION 23 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.22-dev" -#define PHP_VERSION_ID 80222 +#define PHP_VERSION "8.2.23-dev" +#define PHP_VERSION_ID 80223 From b368db204ff96bdced897068a6caaeec8ef55c93 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 16 Jul 2024 17:50:16 +0200 Subject: [PATCH 02/51] Fix comments between -> and keyword Comments should not fall out of ST_LOOKING_FOR_PROPERTY. Fixes GH-14961 Closes GH-14976 --- NEWS | 2 ++ Zend/tests/gh14961.phpt | 26 ++++++++++++++++++++++++++ Zend/zend_language_scanner.l | 16 ++++++++-------- 3 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 Zend/tests/gh14961.phpt diff --git a/NEWS b/NEWS index 5b8f429449127..2767e5fa1b867 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ PHP NEWS . Fixed bug GH-14741 (Segmentation fault in Zend/zend_types.h). (nielsdos) . Fixed bug GH-14969 (Use-after-free in property coercion with __toString()). (ilutov) + . Fixed bug GH-14961 (Comment between -> and keyword results in parse error). + (ilutov) - Dom: . Fixed bug GH-14702 (DOMDocument::xinclude() crash). (nielsdos) diff --git a/Zend/tests/gh14961.phpt b/Zend/tests/gh14961.phpt new file mode 100644 index 0000000000000..f066943c4ec44 --- /dev/null +++ b/Zend/tests/gh14961.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-14961: Comment between -> and keyword +--FILE-- +/* comment */class = 42; +var_dump($c->/** doc comment */class); +var_dump($c-> + // line comment + class); +var_dump($c-> + # hash comment + class); +var_dump($c?->/* comment */class); + +?> +--EXPECT-- +int(42) +int(42) +int(42) +int(42) diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index c73a50948d6bc..c3b27cbfc321c 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1587,12 +1587,6 @@ NEWLINE ("\r"|"\n"|"\r\n") RETURN_TOKEN_WITH_STR(T_STRING, 0); } -{ANY_CHAR} { - yyless(0); - yy_pop_state(); - goto restart; -} - "::" { RETURN_TOKEN(T_PAAMAYIM_NEKUDOTAYIM); } @@ -2375,7 +2369,7 @@ inline_char_handler: } -"#"|"//" { +"#"|"//" { while (YYCURSOR < YYLIMIT) { switch (*YYCURSOR++) { case '\r': @@ -2399,7 +2393,7 @@ inline_char_handler: RETURN_OR_SKIP_TOKEN(T_COMMENT); } -"/*"|"/**"{WHITESPACE} { +"/*"|"/**"{WHITESPACE} { int doc_com; if (yyleng > 2) { @@ -2435,6 +2429,12 @@ inline_char_handler: RETURN_OR_SKIP_TOKEN(T_COMMENT); } +{ANY_CHAR} { + yyless(0); + yy_pop_state(); + goto restart; +} + "?>"{NEWLINE}? { BEGIN(INITIAL); if (yytext[yyleng-1] != '>') { From 911dc5b46c6778ad9a71aa11923a3db879da1828 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 26 May 2024 00:00:23 +0200 Subject: [PATCH 03/51] Fix bug #55639: Digest autentication dont work RFC 2617 and 7616 describe that for the "Authorization" header we should not put the qop nor nc value inside quotes. This differs from the WWW-Authenticate header, which may have been the source of the confusion in the implementation. While the version with quotes seems to work fine in some cases, clearly not all servers accept the non-standard form. To fix the issue, simply removing the quotes of those two header fields of the client request to be in line with the RFC suffices. I refer further to example 3.5 in RFC 2617 and example 3.9.1 in RFC 7616. RFC 2617: https://datatracker.ietf.org/doc/html/rfc2617 RFC 7616: https://datatracker.ietf.org/doc/html/rfc7616 Closes GH-14328. --- NEWS | 3 ++ ext/soap/php_http.c | 10 ++--- ext/soap/tests/bugs/bug55639.phpt | 65 +++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 ext/soap/tests/bugs/bug55639.phpt diff --git a/NEWS b/NEWS index 2767e5fa1b867..01073cf61ed71 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.23 +- Soap: + . Fixed bug #55639 (Digest autentication dont work). (nielsdos) + 01 Aug 2024, PHP 8.2.22 - Core: diff --git a/ext/soap/php_http.c b/ext/soap/php_http.c index 1aa0d9f6f6df4..2aefdba0fb840 100644 --- a/ext/soap/php_http.c +++ b/ext/soap/php_http.c @@ -745,7 +745,7 @@ int make_http_soap_request(zval *this_ptr, PHP_MD5Update(&md5ctx, (unsigned char*)":", 1); PHP_MD5Update(&md5ctx, (unsigned char*)cnonce, 8); PHP_MD5Update(&md5ctx, (unsigned char*)":", 1); - /* TODO: Support for qop="auth-int" */ + /* TODO: Support for qop=auth-int */ PHP_MD5Update(&md5ctx, (unsigned char*)"auth", sizeof("auth")-1); PHP_MD5Update(&md5ctx, (unsigned char*)":", 1); } @@ -781,11 +781,11 @@ int make_http_soap_request(zval *this_ptr, } if ((tmp = zend_hash_str_find(Z_ARRVAL_P(digest), "qop", sizeof("qop")-1)) != NULL && Z_TYPE_P(tmp) == IS_STRING) { - /* TODO: Support for qop="auth-int" */ - smart_str_append_const(&soap_headers, "\", qop=\"auth"); - smart_str_append_const(&soap_headers, "\", nc=\""); + /* TODO: Support for qop=auth-int */ + smart_str_append_const(&soap_headers, "\", qop=auth"); + smart_str_append_const(&soap_headers, ", nc="); smart_str_appendl(&soap_headers, nc, 8); - smart_str_append_const(&soap_headers, "\", cnonce=\""); + smart_str_append_const(&soap_headers, ", cnonce=\""); smart_str_appendl(&soap_headers, cnonce, 8); } smart_str_append_const(&soap_headers, "\", response=\""); diff --git a/ext/soap/tests/bugs/bug55639.phpt b/ext/soap/tests/bugs/bug55639.phpt new file mode 100644 index 0000000000000..40a2cf3f11d26 --- /dev/null +++ b/ext/soap/tests/bugs/bug55639.phpt @@ -0,0 +1,65 @@ +--TEST-- +Bug #55639 (Digest authentication dont work) +--INI-- +soap.wsdl_cache_enabled=0 +--EXTENSIONS-- +soap +--SKIPIF-- + +--FILE-- + 'http://' . PHP_CLI_SERVER_ADDRESS, + 'uri' => 'misc-uri', + 'authentication' => SOAP_AUTHENTICATION_DIGEST, + 'realm' => 'myrealm', + 'login' => 'user', + 'password' => 'pass', + 'trace' => true, +]); + +try { + $client->__soapCall("foo", []); +} catch (Throwable $e) { + echo $e->getMessage(), "\n"; +} + +$headers = $client->__getLastRequestHeaders(); +var_dump($headers); + +?> +--EXPECTF-- +Unauthorized +string(424) "POST / HTTP/1.1 +Host: %s +Connection: Keep-Alive +User-Agent: %s +Content-Type: text/xml; charset=utf-8 +SOAPAction: "misc-uri#foo" +Content-Length: %d +Authorization: Digest username="user", realm="realm", nonce="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", uri="/", qop=auth, nc=00000001, cnonce="%s", response="%s", opaque="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + +" From efd00b8ff05cb78ecb0351b96cce7780bcb72a2a Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 16 Jul 2024 19:55:04 +0100 Subject: [PATCH 04/51] ext/curl: curl_error using curl_easy_strerror if CURLOPT_ERRORBUFFER did not fill the error buffer. close GH-14984 --- NEWS | 4 ++++ ext/curl/interface.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 01073cf61ed71..e82ffc50426db 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.23 +- Curl: + . Fixed case when curl_error returns an empty string. + (David Carlier) + - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 707f4e0a6fc4e..4884ddc8228a1 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -2764,7 +2764,11 @@ PHP_FUNCTION(curl_error) if (ch->err.no) { ch->err.str[CURL_ERROR_SIZE] = 0; - RETURN_STRING(ch->err.str); + if (strlen(ch->err.str) > 0) { + RETURN_STRING(ch->err.str); + } else { + RETURN_STRING(curl_easy_strerror(ch->err.no)); + } } else { RETURN_EMPTY_STRING(); } From 355baf982eaec1aea54ba9886f54decad6fcc467 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 18 Jul 2024 12:42:01 +0200 Subject: [PATCH 05/51] Revert "Skip bug45161.phpt on Windows" This reverts commit 4b22c3e3ad5fa7088469315cc96353da747c91f6. As quick measure for GH-10753, that test was skipped on Windows. However, it seems that there are no longer performance issues with newer cURL versions, so we run that test again on Windows. Fixes GH-10753. Closes GH-14998. --- ext/curl/tests/bug45161.phpt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ext/curl/tests/bug45161.phpt b/ext/curl/tests/bug45161.phpt index 7e67b6d741ed5..9ba8f5f90249c 100644 --- a/ext/curl/tests/bug45161.phpt +++ b/ext/curl/tests/bug45161.phpt @@ -2,10 +2,6 @@ Bug #45161 (Reusing a curl handle leaks memory) --EXTENSIONS-- curl ---SKIPIF-- - --FILE-- Date: Wed, 17 Jul 2024 13:59:47 +0200 Subject: [PATCH 06/51] Update the php-sdk-binary-tools to php-sdk-2.3.0 The Windows CI of the `PHP-8.2` to `PHP-8.3` branches still use the `php-sdk-2.2.0` which is almost five years old, and does not fetch the updated dependencies from https://downloads.php.net/~windows. The `master` branch CI uses `php_downloads_server_migration_v1`, which has been superseded a few months ago[1]. So switching to the `php-sdk-2.3.0` makes sense there, too. [1] Closes GH-14991. --- .github/workflows/nightly.yml | 2 +- .github/workflows/push.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 61545aeac59da..4822721f2c675 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -657,7 +657,7 @@ jobs: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache PHP_BUILD_OBJ_DIR: C:\obj PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk - PHP_BUILD_SDK_BRANCH: php-sdk-2.2.0 + PHP_BUILD_SDK_BRANCH: php-sdk-2.3.0 PHP_BUILD_CRT: vs16 PLATFORM: ${{ matrix.x64 && 'x64' || 'x86' }} THREAD_SAFE: "${{ matrix.zts && '1' || '0' }}" diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 662e4a4b5342c..34a592c3b0468 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -182,7 +182,7 @@ jobs: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache PHP_BUILD_OBJ_DIR: C:\obj PHP_BUILD_CACHE_SDK_DIR: C:\build-cache\sdk - PHP_BUILD_SDK_BRANCH: php-sdk-2.2.0 + PHP_BUILD_SDK_BRANCH: php-sdk-2.3.0 PHP_BUILD_CRT: vs16 PLATFORM: x64 THREAD_SAFE: "1" From 03d73182d9afc0ddbd4134e69750daf080585a37 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:13:51 +0200 Subject: [PATCH 07/51] Fix GH-15020: Memory leak in Zend/Optimizer/escape_analysis.c Closes GH-15022. --- NEWS | 4 ++++ Zend/Optimizer/escape_analysis.c | 1 + 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index e82ffc50426db..ec7c542a11f9a 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.23 +- Core: + . Fixed bug GH-15020 (Memory leak in Zend/Optimizer/escape_analysis.c). + (nielsdos) + - Curl: . Fixed case when curl_error returns an empty string. (David Carlier) diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c index b7c0a5ec4466a..4bb2b58af776d 100644 --- a/Zend/Optimizer/escape_analysis.c +++ b/Zend/Optimizer/escape_analysis.c @@ -400,6 +400,7 @@ zend_result zend_ssa_escape_analysis(const zend_script *script, zend_op_array *o } if (zend_build_equi_escape_sets(ees, op_array, ssa) == FAILURE) { + free_alloca(ees, use_heap); return FAILURE; } From 8c19efdc974eb7af9dba0510baacda54dfda0700 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:34:17 +0200 Subject: [PATCH 08/51] Fix GH-15023: Memory leak in Zend/zend_ini.c Closes GH-15024. --- NEWS | 1 + Zend/zend_ini.c | 1 + 2 files changed, 2 insertions(+) diff --git a/NEWS b/NEWS index ec7c542a11f9a..14aad73564aff 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - Core: . Fixed bug GH-15020 (Memory leak in Zend/Optimizer/escape_analysis.c). (nielsdos) + . Fixed bug GH-15023 (Memory leak in Zend/zend_ini.c). (nielsdos) - Curl: . Fixed case when curl_error returns an empty string. diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 8ba3d7ee48f0d..cfa394d43e978 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -243,6 +243,7 @@ ZEND_API zend_result zend_register_ini_entries_ex(const zend_ini_entry_def *ini_ if (p->name) { zend_string_release_ex(p->name, 1); } + pefree(p, true); zend_unregister_ini_entries_ex(module_number, module_type); return FAILURE; } From 5996227f88240fcf2fe83ef32eda0816e3fc7e3a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 19 Jul 2024 14:12:34 +0200 Subject: [PATCH 09/51] Fix GH-15028: Memory leak in ext/phar/stream.c Closes GH-15029. --- NEWS | 3 +++ ext/phar/stream.c | 1 + 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 14aad73564aff..109f0b2d91e8e 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,9 @@ PHP NEWS - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) +- Streams: + . Fixed bug GH-15028 (Memory leak in ext/phar/stream.c). (nielsdos) + 01 Aug 2024, PHP 8.2.22 - Core: diff --git a/ext/phar/stream.c b/ext/phar/stream.c index ceedbdae35389..0e5c9dd1f2ae7 100644 --- a/ext/phar/stream.c +++ b/ext/phar/stream.c @@ -782,6 +782,7 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from } if (PHAR_G(readonly) && (!pto || !pto->is_data)) { php_url_free(resource_from); + php_url_free(resource_to); php_error_docref(NULL, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly"); return 0; } From 8de7ccb29b1806ba7943bb8440b21a02edff9653 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 21 Jul 2024 00:38:56 +0200 Subject: [PATCH 10/51] Fix memory leaks in ext/tidy basedir restriction code TIDY_APPLY_CONFIG can early return because it's a macro, but then the cleanup paths are not executed. Transform this to a real function and handle the cleanups correctly at the callsites. Closes GH-15046. --- NEWS | 3 + ext/tidy/tests/open_basedir/test.html | 1 + .../tests/open_basedir_failure_config.phpt | 48 +++++++++++++++ ext/tidy/tidy.c | 58 +++++++++---------- 4 files changed, 81 insertions(+), 29 deletions(-) create mode 100644 ext/tidy/tests/open_basedir/test.html create mode 100644 ext/tidy/tests/open_basedir_failure_config.phpt diff --git a/NEWS b/NEWS index 109f0b2d91e8e..ed4fb6b761c1e 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,9 @@ PHP NEWS - Streams: . Fixed bug GH-15028 (Memory leak in ext/phar/stream.c). (nielsdos) +- Tidy: + . Fix memory leaks in ext/tidy basedir restriction code. (nielsdos) + 01 Aug 2024, PHP 8.2.22 - Core: diff --git a/ext/tidy/tests/open_basedir/test.html b/ext/tidy/tests/open_basedir/test.html new file mode 100644 index 0000000000000..5b9b4b71f8f0e --- /dev/null +++ b/ext/tidy/tests/open_basedir/test.html @@ -0,0 +1 @@ +

my epic string

diff --git a/ext/tidy/tests/open_basedir_failure_config.phpt b/ext/tidy/tests/open_basedir_failure_config.phpt new file mode 100644 index 0000000000000..b14393b7b801c --- /dev/null +++ b/ext/tidy/tests/open_basedir_failure_config.phpt @@ -0,0 +1,48 @@ +--TEST-- +Tidy with basedir restriction failure on configuration file +--EXTENSIONS-- +tidy +--INI-- +open_basedir={PWD}/open_basedir +--FILE-- +repairString('my epic string', 'my_config_file.ini'); + +echo "=== tidy_parse_string ===\n"; +tidy_parse_string('my epic string', 'my_config_file.ini'); + +echo "=== tidy_parse_file ===\n"; +tidy_parse_file(__DIR__.'/open_basedir/test.html', 'my_config_file.ini'); + +echo "=== __construct ===\n"; +$tidy = new tidy(__DIR__.'/open_basedir/test.html', 'my_config_file.ini'); + +echo "=== parseFile ===\n"; +$tidy = new tidy; +$tidy->parseFile(__DIR__.'/open_basedir/test.html', 'my_config_file.ini'); + +echo "=== parseString ===\n"; +$tidy = new tidy; +$tidy->parseString('my epic string', 'my_config_file.ini'); +?> +--EXPECTF-- +=== repairString === + +Warning: tidy::repairString(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d +=== tidy_parse_string === + +Warning: tidy_parse_string(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d +=== tidy_parse_file === + +Warning: tidy_parse_file(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d +=== __construct === + +Warning: tidy::__construct(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d +=== parseFile === + +Warning: tidy::parseFile(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d +=== parseString === + +Warning: tidy::parseString(): open_basedir restriction in effect. File(my_config_file.ini) is not within the allowed path(s): (%sopen_basedir) in %s on line %d diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c index 38e97a71a2a15..831fcb3815399 100644 --- a/ext/tidy/tidy.c +++ b/ext/tidy/tidy.c @@ -74,19 +74,6 @@ } \ obj = Z_TIDY_P(object); \ -#define TIDY_APPLY_CONFIG(_doc, _val_str, _val_ht) \ - if (_val_ht) { \ - _php_tidy_apply_config_array(_doc, _val_ht); \ - } else if (_val_str) { \ - TIDY_OPEN_BASE_DIR_CHECK(ZSTR_VAL(_val_str)); \ - php_tidy_load_config(_doc, ZSTR_VAL(_val_str)); \ - } - -#define TIDY_OPEN_BASE_DIR_CHECK(filename) \ -if (php_check_open_basedir(filename)) { \ - RETURN_FALSE; \ -} \ - #define TIDY_SET_DEFAULT_CONFIG(_doc) \ if (TG(default_config) && TG(default_config)[0]) { \ php_tidy_load_config(_doc, TG(default_config)); \ @@ -221,6 +208,19 @@ static void php_tidy_load_config(TidyDoc doc, const char *path) } } +static zend_result php_tidy_apply_config(TidyDoc doc, zend_string *str_string, HashTable *ht_options) +{ + if (ht_options) { + return _php_tidy_apply_config_array(doc, ht_options); + } else if (str_string) { + if (php_check_open_basedir(ZSTR_VAL(str_string))) { + return FAILURE; + } + php_tidy_load_config(doc, ZSTR_VAL(str_string)); + } + return SUCCESS; +} + static int _php_tidy_set_tidy_opt(TidyDoc doc, char *optname, zval *value) { TidyOption opt = tidyGetOptionByName(doc, optname); @@ -329,9 +329,9 @@ static void php_tidy_quick_repair(INTERNAL_FUNCTION_PARAMETERS, bool is_file) TIDY_SET_DEFAULT_CONFIG(doc); - TIDY_APPLY_CONFIG(doc, config_str, config_ht); - - if(enc_len) { + if (php_tidy_apply_config(doc, config_str, config_ht) != SUCCESS) { + RETVAL_FALSE; + } else if (enc_len) { if (tidySetCharEncoding(doc, enc) < 0) { php_error_docref(NULL, E_WARNING, "Could not set encoding \"%s\"", enc); RETVAL_FALSE; @@ -1024,9 +1024,8 @@ PHP_FUNCTION(tidy_parse_string) tidy_instantiate(tidy_ce_doc, return_value); obj = Z_TIDY_P(return_value); - TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); - - if (php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == FAILURE) { + if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS + || php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == FAILURE) { zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1093,9 +1092,8 @@ PHP_FUNCTION(tidy_parse_file) tidy_instantiate(tidy_ce_doc, return_value); obj = Z_TIDY_P(return_value); - TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); - - if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { + if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS + || php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { zval_ptr_dtor(return_value); RETVAL_FALSE; } @@ -1388,7 +1386,11 @@ PHP_METHOD(tidy, __construct) RETURN_THROWS(); } - TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); + if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS) { + /* TODO: this is the constructor, we should throw probably... */ + zend_string_release_ex(contents, 0); + RETURN_FALSE; + } php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc); @@ -1427,9 +1429,8 @@ PHP_METHOD(tidy, parseFile) RETURN_THROWS(); } - TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); - - if (php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { + if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) != SUCCESS + || php_tidy_parse_string(obj, ZSTR_VAL(contents), (uint32_t)ZSTR_LEN(contents), enc) == FAILURE) { RETVAL_FALSE; } else { RETVAL_TRUE; @@ -1461,9 +1462,8 @@ PHP_METHOD(tidy, parseString) TIDY_SET_CONTEXT; obj = Z_TIDY_P(object); - TIDY_APPLY_CONFIG(obj->ptdoc->doc, options_str, options_ht); - - if(php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == SUCCESS) { + if (php_tidy_apply_config(obj->ptdoc->doc, options_str, options_ht) == SUCCESS + && php_tidy_parse_string(obj, ZSTR_VAL(input), (uint32_t)ZSTR_LEN(input), enc) == SUCCESS) { RETURN_TRUE; } From cfcc2a3fda3baaca83e9d5d605e578f445893f07 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:52:03 +0200 Subject: [PATCH 11/51] Fix GH-15034: Integer overflow on stream_notification_callback byte_max parameter with files bigger than 2GB We were using atoi, which is only for integers. When the size does not fit in an integer this breaks. Use ZEND_STRTOUL instead. Also make sure invalid data isn't accidentally parsed into a file size. Closes GH-15035. --- NEWS | 2 ++ ext/standard/http_fopen_wrapper.c | 15 ++++++++-- ext/standard/tests/http/gh15034.phpt | 44 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/http/gh15034.phpt diff --git a/NEWS b/NEWS index ed4fb6b761c1e..f6599dc5fc44d 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,8 @@ PHP NEWS - Streams: . Fixed bug GH-15028 (Memory leak in ext/phar/stream.c). (nielsdos) + . Fixed bug GH-15034 (Integer overflow on stream_notification_callback + byte_max parameter with files bigger than 2GB). (nielsdos) - Tidy: . Fix memory leaks in ext/tidy basedir restriction code. (nielsdos) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index a9950fa6d48d2..dca176ad3f526 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -791,8 +791,19 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, } else if (!strncasecmp(http_header_line, "Content-Type:", sizeof("Content-Type:")-1)) { php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_value, 0); } else if (!strncasecmp(http_header_line, "Content-Length:", sizeof("Content-Length:")-1)) { - file_size = atoi(http_header_value); - php_stream_notify_file_size(context, file_size, http_header_line, 0); + /* https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length */ + const char *ptr = http_header_value; + /* must contain only digits, no + or - symbols */ + if (*ptr >= '0' && *ptr <= '9') { + char *endptr = NULL; + size_t parsed = ZEND_STRTOUL(ptr, &endptr, 10); + /* check whether there was no garbage in the header value and the conversion was successful */ + if (endptr && !*endptr) { + /* truncate for 32-bit such that no negative file sizes occur */ + file_size = MIN(parsed, ZEND_LONG_MAX); + php_stream_notify_file_size(context, file_size, http_header_line, 0); + } + } } else if ( !strncasecmp(http_header_line, "Transfer-Encoding:", sizeof("Transfer-Encoding:")-1) && !strncasecmp(http_header_value, "Chunked", sizeof("Chunked")-1) diff --git a/ext/standard/tests/http/gh15034.phpt b/ext/standard/tests/http/gh15034.phpt new file mode 100644 index 0000000000000..c0841ef954437 --- /dev/null +++ b/ext/standard/tests/http/gh15034.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-15034 (Integer overflow on stream_notification_callback byte_max parameter with files bigger than 2GB) +--SKIPIF-- + +--INI-- +allow_url_fopen=1 +--FILE-- + $pid, 'uri' => $uri] = http_server($responses); + +$params = ['notification' => function( + int $notification_code, + int $severity, + ?string $message, + int $message_code, + int $bytes_transferred, + int $bytes_max +) { + global $max; + $max = $bytes_max; +}]; +$contextResource = stream_context_create([], $params); + +$resource = fopen($uri, 'r', false, $contextResource); +fclose($resource); + +http_server_kill($pid); + +var_dump($max); +?> +--EXPECT-- +int(3000000000) From d20d11375fa602236e1fb828f6a2236b19b43cdc Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 22 Jul 2024 06:57:04 +0200 Subject: [PATCH 12/51] Append -Wno-implicit-fallthrough flag conditionally (#13331) Older GCC versions (< 7.0) don't support the -Wno-implicit-fallthrough compiler flag. This adds the flag conditionally in case some other compiler will run into same issue. Fixes GH-13330 --- NEWS | 2 ++ ext/date/config0.m4 | 6 +++++- ext/hash/config.m4 | 7 ++++++- ext/opcache/config.m4 | 6 +++++- ext/pcre/config0.m4 | 7 ++++++- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index f6599dc5fc44d..11ff5add75a2a 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS . Fixed bug GH-15020 (Memory leak in Zend/Optimizer/escape_analysis.c). (nielsdos) . Fixed bug GH-15023 (Memory leak in Zend/zend_ini.c). (nielsdos) + . Fixed bug GH-13330 (Append -Wno-implicit-fallthrough flag conditionally). + (Peter Kokot) - Curl: . Fixed case when curl_error returns an empty string. diff --git a/ext/date/config0.m4 b/ext/date/config0.m4 index 6b803bf33e55b..d7ec92687e10f 100644 --- a/ext/date/config0.m4 +++ b/ext/date/config0.m4 @@ -4,7 +4,11 @@ AC_CHECK_HEADERS([io.h]) dnl Check for strtoll, atoll AC_CHECK_FUNCS(strtoll atoll) -PHP_DATE_CFLAGS="-Wno-implicit-fallthrough -I@ext_builddir@/lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DHAVE_TIMELIB_CONFIG_H=1" +AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough], + [PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -Wno-implicit-fallthrough"],, + [-Werror]) + +PHP_DATE_CFLAGS="$PHP_DATE_CFLAGS -I@ext_builddir@/lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DHAVE_TIMELIB_CONFIG_H=1" timelib_sources="lib/astro.c lib/dow.c lib/parse_date.c lib/parse_tz.c lib/parse_posix.c lib/timelib.c lib/tm2unixtime.c lib/unixtime2tm.c lib/parse_iso_intervals.c lib/interval.c" diff --git a/ext/hash/config.m4 b/ext/hash/config.m4 index a893879f9cf01..f31206fc17464 100644 --- a/ext/hash/config.m4 +++ b/ext/hash/config.m4 @@ -28,8 +28,13 @@ else SHA3_OPT_SRC="$SHA3_DIR/KeccakP-1600-opt64.c" ]) EXT_HASH_SHA3_SOURCES="$SHA3_OPT_SRC $SHA3_DIR/KeccakHash.c $SHA3_DIR/KeccakSponge.c hash_sha3.c" + dnl Add -Wno-implicit-fallthrough flag as it happens on 32 bit builds - PHP_HASH_CFLAGS="-Wno-implicit-fallthrough -I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" + AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough], + [PHP_HASH_CFLAGS="$PHP_HASH_CFLAGS -Wno-implicit-fallthrough"],, + [-Werror]) + + PHP_HASH_CFLAGS="$PHP_HASH_CFLAGS -I@ext_srcdir@/$SHA3_DIR -DKeccakP200_excluded -DKeccakP400_excluded -DKeccakP800_excluded -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" PHP_ADD_BUILD_DIR(ext/hash/$SHA3_DIR, 1) fi diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 6bf07ad35e2e0..b3929382e1173 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -317,6 +317,10 @@ int main(void) { fi AC_MSG_RESULT([$have_shm_mmap_posix]) + AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough], + [PHP_OPCACHE_CFLAGS="$PHP_OPCACHE_CFLAGS -Wno-implicit-fallthrough"],, + [-Werror]) + PHP_NEW_EXTENSION(opcache, ZendAccelerator.c \ zend_accelerator_blacklist.c \ @@ -332,7 +336,7 @@ int main(void) { shared_alloc_mmap.c \ shared_alloc_posix.c \ $ZEND_JIT_SRC, - shared,,"-Wno-implicit-fallthrough -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1",,yes) + shared,,"$PHP_OPCACHE_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1",,yes) PHP_ADD_EXTENSION_DEP(opcache, pcre) diff --git a/ext/pcre/config0.m4 b/ext/pcre/config0.m4 index 5f74b5df6b5b8..cd2f60c78430d 100644 --- a/ext/pcre/config0.m4 +++ b/ext/pcre/config0.m4 @@ -66,7 +66,12 @@ else pcre2lib/pcre2_string_utils.c pcre2lib/pcre2_study.c pcre2lib/pcre2_substitute.c pcre2lib/pcre2_substring.c \ pcre2lib/pcre2_tables.c pcre2lib/pcre2_ucd.c pcre2lib/pcre2_valid_utf.c pcre2lib/pcre2_xclass.c \ pcre2lib/pcre2_find_bracket.c pcre2lib/pcre2_convert.c pcre2lib/pcre2_extuni.c pcre2lib/pcre2_script_run.c" - PHP_PCRE_CFLAGS="-Wno-implicit-fallthrough -DHAVE_CONFIG_H -I@ext_srcdir@/pcre2lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" + + AX_CHECK_COMPILE_FLAG([-Wno-implicit-fallthrough], + [PHP_PCRE_CFLAGS="$PHP_PCRE_CFLAGS -Wno-implicit-fallthrough"],, + [-Werror]) + + PHP_PCRE_CFLAGS="$PHP_PCRE_CFLAGS -DHAVE_CONFIG_H -I@ext_srcdir@/pcre2lib -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" AC_DEFINE(HAVE_BUNDLED_PCRE, 1, [ ]) AC_DEFINE(PCRE2_CODE_UNIT_WIDTH, 8, [ ]) From 13e9b40517909c65a7f901c0b9166c04c92940d4 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 22 Jul 2024 16:01:26 +0300 Subject: [PATCH 13/51] Regenerate FFI parser using HEAD version of LLK --- ext/ffi/ffi.g | 5 ++++ ext/ffi/ffi_parser.c | 67 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/ext/ffi/ffi.g b/ext/ffi/ffi.g index b70e3f1299629..e30d86b21c72a 100644 --- a/ext/ffi/ffi.g +++ b/ext/ffi/ffi.g @@ -64,6 +64,7 @@ php llk.php ffi.g /* forward declarations */ static void yy_error(const char *msg); static void yy_error_sym(const char *msg, int sym); +static void yy_error_str(const char *msg, const char *str); %} @@ -918,3 +919,7 @@ static void yy_error(const char *msg) { static void yy_error_sym(const char *msg, int sym) { zend_ffi_parser_error("%s '%s' at line %d", msg, sym_name[sym], yy_line); } + +static void yy_error_str(const char *msg, const char *str) { + zend_ffi_parser_error("%s '%s' at line %d\n", msg, str, yy_line); +} diff --git a/ext/ffi/ffi_parser.c b/ext/ffi/ffi_parser.c index b956f885ee001..cdd05361b97ff 100644 --- a/ext/ffi/ffi_parser.c +++ b/ext/ffi/ffi_parser.c @@ -34,6 +34,7 @@ /* forward declarations */ static void yy_error(const char *msg); static void yy_error_sym(const char *msg, int sym); +static void yy_error_str(const char *msg, const char *str); #define YYPOS cpos #define YYEND cend @@ -246,6 +247,63 @@ static const char * sym_name[] = { #define YY_IN_SET(sym, set, bitset) \ (bitset[sym>>3] & (1 << (sym & 0x7))) +size_t yy_escape(char *buf, unsigned char ch) +{ + switch (ch) { + case '\\': buf[0] = '\\'; buf[1] = '\\'; return 2; + case '\'': buf[0] = '\\'; buf[1] = '\''; return 2; + case '\"': buf[0] = '\\'; buf[1] = '\"'; return 2; + case '\a': buf[0] = '\\'; buf[1] = '\a'; return 2; + case '\b': buf[0] = '\\'; buf[1] = '\b'; return 2; + case 27: buf[0] = '\\'; buf[1] = '\e'; return 2; + case '\f': buf[0] = '\\'; buf[1] = '\f'; return 2; + case '\n': buf[0] = '\\'; buf[1] = '\n'; return 2; + case '\r': buf[0] = '\\'; buf[1] = '\r'; return 2; + case '\t': buf[0] = '\\'; buf[1] = '\t'; return 2; + case '\v': buf[0] = '\\'; buf[1] = '\v'; return 2; + case '\?': buf[0] = '\\'; buf[1] = 0x3f; return 2; + default: break; + } + if (ch < 32 || ch >= 127) { + buf[0] = '\\'; + buf[1] = '0' + ((ch >> 6) % 8); + buf[2] = '0' + ((ch >> 3) % 8); + buf[3] = '0' + (ch % 8); + return 4; + } else { + buf[0] = ch; + return 1; + } +} + +const char *yy_escape_char(char *buf, unsigned char ch) +{ + size_t len = yy_escape(buf, ch); + buf[len] = 0; + return buf; +} + +const char *yy_escape_string(char *buf, size_t size, const unsigned char *str, size_t n) +{ + size_t i = 0; + size_t pos = 0; + size_t len; + + while (i < n) { + if (pos + 8 > size) { + buf[pos++] = '.'; + buf[pos++] = '.'; + buf[pos++] = '.'; + break; + } + len = yy_escape(buf + pos, str[i]); + i++; + pos += len; + } + buf[pos] = 0; + return buf; +} + static int skip_EOL(int sym); static int skip_WS(int sym); static int skip_ONE_LINE_COMMENT(int sym); @@ -310,6 +368,7 @@ static int synpred_5(int sym); static int synpred_6(int sym); static int get_skip_sym(void) { + char buf[64]; int ch; int ret; int accept = -1; @@ -1667,9 +1726,9 @@ static int get_skip_sym(void) { if (YYPOS >= YYEND) { yy_error("unexpected "); } else if (YYPOS == yy_text) { - yy_error("unexpected character 'escape_char(ch)'"); + yy_error_str("unexpected character", yy_escape_char(buf, ch)); } else { - yy_error("unexpected sequence 'escape_string(yy_text, 1 + YYPOS - yy_text))'"); + yy_error_str("unexpected sequence", yy_escape_string(buf, sizeof(buf), yy_text, 1 + YYPOS - yy_text)); } YYPOS++; goto _yy_state_start; @@ -3592,3 +3651,7 @@ static void yy_error(const char *msg) { static void yy_error_sym(const char *msg, int sym) { zend_ffi_parser_error("%s '%s' at line %d", msg, sym_name[sym], yy_line); } + +static void yy_error_str(const char *msg, const char *str) { + zend_ffi_parser_error("%s '%s' at line %d\n", msg, str, yy_line); +} From d6efff72548584dc91bc941eda26e2fbb2efd861 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 22 Jul 2024 16:41:16 +0300 Subject: [PATCH 14/51] Fix Windows build --- ext/ffi/ffi_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ffi/ffi_parser.c b/ext/ffi/ffi_parser.c index cdd05361b97ff..8d06f1d875879 100644 --- a/ext/ffi/ffi_parser.c +++ b/ext/ffi/ffi_parser.c @@ -255,7 +255,7 @@ size_t yy_escape(char *buf, unsigned char ch) case '\"': buf[0] = '\\'; buf[1] = '\"'; return 2; case '\a': buf[0] = '\\'; buf[1] = '\a'; return 2; case '\b': buf[0] = '\\'; buf[1] = '\b'; return 2; - case 27: buf[0] = '\\'; buf[1] = '\e'; return 2; + case 27: buf[0] = '\\'; buf[1] = 27; return 2; case '\f': buf[0] = '\\'; buf[1] = '\f'; return 2; case '\n': buf[0] = '\\'; buf[1] = '\n'; return 2; case '\r': buf[0] = '\\'; buf[1] = '\r'; return 2; From c0de7214aa9a2d9f03ce3fe4c6c02667fa3c8672 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 6 Jul 2024 01:10:04 +0200 Subject: [PATCH 15/51] Fix GH-14286 (ffi enum type (when enum has no name) make memory leak) For top-level anonymous type definition we never store the declaration anywhere else nor the type anywhere else. The declaration keeps owning the type and it goes out of scope. For anonymous fields this gets handled by the add_anonymous_field code that removes the type from the declaration. This patch does something similar in the parsing code when it is detected we're dealing with an anonymous enum in a top-level declaration. Closes GH-14839. --- NEWS | 4 ++++ ext/ffi/ffi.c | 2 +- ext/ffi/ffi.g | 5 +++- ext/ffi/ffi_parser.c | 4 ++++ ext/ffi/php_ffi.h | 1 + ext/ffi/tests/gh14286_1.phpt | 46 ++++++++++++++++++++++++++++++++++++ ext/ffi/tests/gh14286_2.phpt | 25 ++++++++++++++++++++ 7 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 ext/ffi/tests/gh14286_1.phpt create mode 100644 ext/ffi/tests/gh14286_2.phpt diff --git a/NEWS b/NEWS index 11ff5add75a2a..828a8fdff317d 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,10 @@ PHP NEWS . Fixed case when curl_error returns an empty string. (David Carlier) +- FFI: + . Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory + leak). (nielsdos, dstogov) + - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 560338e71f335..8b0b58105d320 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -3544,7 +3544,7 @@ ZEND_METHOD(FFI, scope) /* {{{ */ } /* }}} */ -static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */ +void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */ { if (dcl) { zend_ffi_type_dtor(dcl->type); diff --git a/ext/ffi/ffi.g b/ext/ffi/ffi.g index e30d86b21c72a..d70075267e54f 100644 --- a/ext/ffi/ffi.g +++ b/ext/ffi/ffi.g @@ -97,7 +97,10 @@ declarations: initializer? {zend_ffi_declare(name, name_len, &dcl);} )* - )? + | + /* empty */ + {if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl);} + ) ";" )* ; diff --git a/ext/ffi/ffi_parser.c b/ext/ffi/ffi_parser.c index 8d06f1d875879..2589ae81e0259 100644 --- a/ext/ffi/ffi_parser.c +++ b/ext/ffi/ffi_parser.c @@ -2115,6 +2115,10 @@ static int parse_declarations(int sym) { } zend_ffi_declare(name, name_len, &dcl); } + } else if (sym == YY__SEMICOLON) { + if (common_dcl.flags & (ZEND_FFI_DCL_ENUM | ZEND_FFI_DCL_STRUCT | ZEND_FFI_DCL_UNION)) zend_ffi_cleanup_dcl(&common_dcl); + } else { + yy_error_sym("unexpected", sym); } if (sym != YY__SEMICOLON) { yy_error_sym("';' expected, got", sym); diff --git a/ext/ffi/php_ffi.h b/ext/ffi/php_ffi.h index 02a241c6bb691..430b8a2e568f8 100644 --- a/ext/ffi/php_ffi.h +++ b/ext/ffi/php_ffi.h @@ -208,6 +208,7 @@ typedef struct _zend_ffi_val { zend_result zend_ffi_parse_decl(const char *str, size_t len); zend_result zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl); +void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl); /* parser callbacks */ void ZEND_NORETURN zend_ffi_parser_error(const char *msg, ...); diff --git a/ext/ffi/tests/gh14286_1.phpt b/ext/ffi/tests/gh14286_1.phpt new file mode 100644 index 0000000000000..19701f634a631 --- /dev/null +++ b/ext/ffi/tests/gh14286_1.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-14286 (ffi enum type (when enum has no name) make memory leak) +--EXTENSIONS-- +ffi +--INI-- +ffi.enable=1 +--FILE-- +TEST_ONE); +var_dump($ffi->TEST_TWO); +var_dump($ffi->TEST_THREE); +var_dump($ffi->TEST_FOUR); +var_dump($ffi->TEST_FIVE); +var_dump($ffi->TEST_SIX); +?> +--EXPECT-- +int(1) +int(2) +int(3) +int(4) +int(5) +int(6) diff --git a/ext/ffi/tests/gh14286_2.phpt b/ext/ffi/tests/gh14286_2.phpt new file mode 100644 index 0000000000000..683929780c053 --- /dev/null +++ b/ext/ffi/tests/gh14286_2.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-14286 (ffi enum type (when enum has no name) make memory leak) +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +getMessage(), "\n"; +} +?> +--EXPECT-- +Failed resolving C variable 'x' From fdcfd62b9b27c59ec6da607f3d61cdb1715e3195 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:08:55 +0200 Subject: [PATCH 16/51] Fix passing non-finite timeout values in stream functions Closes GH-15061. --- NEWS | 3 ++ ext/standard/streamsfuncs.c | 6 ++++ .../tests/streams/non_finite_values.phpt | 31 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 ext/standard/tests/streams/non_finite_values.phpt diff --git a/NEWS b/NEWS index 828a8fdff317d..ecd04bac449cd 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,9 @@ PHP NEWS - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) +- Standard: + . Fix passing non-finite timeout values in stream functions. (nielsdos) + - Streams: . Fixed bug GH-15028 (Memory leak in ext/phar/stream.c). (nielsdos) . Fixed bug GH-15034 (Integer overflow on stream_notification_callback diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 53fa8d33dad6b..18e80ddda32ab 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -127,6 +127,9 @@ PHP_FUNCTION(stream_socket_client) if (timeout_is_null) { timeout = (double)FG(default_socket_timeout); + } else if (!zend_finite(timeout)) { + zend_argument_value_error(4, "must be a finite value"); + RETURN_THROWS(); } context = php_stream_context_from_zval(zcontext, flags & PHP_FILE_NO_DEFAULT_CONTEXT); @@ -279,6 +282,9 @@ PHP_FUNCTION(stream_socket_accept) if (timeout_is_null) { timeout = (double)FG(default_socket_timeout); + } else if (!zend_finite(timeout)) { + zend_argument_value_error(2, "must be a finite value"); + RETURN_THROWS(); } php_stream_from_zval(stream, zstream); diff --git a/ext/standard/tests/streams/non_finite_values.phpt b/ext/standard/tests/streams/non_finite_values.phpt new file mode 100644 index 0000000000000..5dba0d3b48266 --- /dev/null +++ b/ext/standard/tests/streams/non_finite_values.phpt @@ -0,0 +1,31 @@ +--TEST-- +Non-finite timeout values in stream functions +--FILE-- +getMessage(), "\n"; + } +} +fclose($socket); + +foreach ([NAN, -NAN, INF, -INF] as $value) { + try { + stream_socket_client("tcp://0.0.0.0:14781", timeout: $value); + } catch (ValueError $e) { + echo $e->getMessage(), "\n"; + } +} +?> +--EXPECT-- +stream_socket_accept(): Argument #2 ($timeout) must be a finite value +stream_socket_accept(): Argument #2 ($timeout) must be a finite value +stream_socket_accept(): Argument #2 ($timeout) must be a finite value +stream_socket_accept(): Argument #2 ($timeout) must be a finite value +stream_socket_client(): Argument #4 ($timeout) must be a finite value +stream_socket_client(): Argument #4 ($timeout) must be a finite value +stream_socket_client(): Argument #4 ($timeout) must be a finite value +stream_socket_client(): Argument #4 ($timeout) must be a finite value From a18df90a8be27ecbf9c763484017c65fa16f76d8 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 22 Jul 2024 18:28:03 +0200 Subject: [PATCH 17/51] Fix GH-13817: Segmentation fault for enabled observers after pass 4 Instead of fixing up temporaries count in between observer steps, just apply the additional temporary in the two affected observer steps. Closes GH-14018. --- NEWS | 4 +++ Zend/Optimizer/compact_vars.c | 3 +- Zend/Optimizer/optimize_temp_vars_5.c | 3 +- Zend/Optimizer/zend_optimizer.c | 13 ------- ext/opcache/tests/gh13817.phpt | 51 +++++++++++++++++++++++++++ 5 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 ext/opcache/tests/gh13817.phpt diff --git a/NEWS b/NEWS index ecd04bac449cd..a1086fd499149 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,10 @@ PHP NEWS . Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory leak). (nielsdos, dstogov) +- Opcache: + . Fixed bug GH-13817 (Segmentation fault for enabled observers after pass 4). + (Bob) + - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/Zend/Optimizer/compact_vars.c b/Zend/Optimizer/compact_vars.c index a8ef8846deca2..9898714a17c5e 100644 --- a/Zend/Optimizer/compact_vars.c +++ b/Zend/Optimizer/compact_vars.c @@ -18,6 +18,7 @@ #include "Optimizer/zend_optimizer_internal.h" #include "zend_bitset.h" +#include "zend_observer.h" /* This pass removes all CVs and temporaries that are completely unused. It does *not* merge any CVs or TMPs. * This pass does not operate on SSA form anymore. */ @@ -117,7 +118,7 @@ void zend_optimizer_compact_vars(zend_op_array *op_array) { op_array->last_var = num_cvs; } - op_array->T = num_tmps; + op_array->T = num_tmps + ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled free_alloca(vars_map, use_heap2); } diff --git a/Zend/Optimizer/optimize_temp_vars_5.c b/Zend/Optimizer/optimize_temp_vars_5.c index 33d418ffbd99c..de0b189d5dca1 100644 --- a/Zend/Optimizer/optimize_temp_vars_5.c +++ b/Zend/Optimizer/optimize_temp_vars_5.c @@ -26,6 +26,7 @@ #include "zend_execute.h" #include "zend_vm.h" #include "zend_bitset.h" +#include "zend_observer.h" #define INVALID_VAR ((uint32_t)-1) #define GET_AVAILABLE_T() \ @@ -173,5 +174,5 @@ void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_c } zend_arena_release(&ctx->arena, checkpoint); - op_array->T = max + 1; + op_array->T = max + 1 + ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled } diff --git a/Zend/Optimizer/zend_optimizer.c b/Zend/Optimizer/zend_optimizer.c index f274edb039c17..8a029c8007b85 100644 --- a/Zend/Optimizer/zend_optimizer.c +++ b/Zend/Optimizer/zend_optimizer.c @@ -31,7 +31,6 @@ #include "zend_inference.h" #include "zend_dump.h" #include "php.h" -#include "zend_observer.h" #ifndef ZEND_OPTIMIZER_MAX_REGISTERED_PASSES # define ZEND_OPTIMIZER_MAX_REGISTERED_PASSES 32 @@ -1097,8 +1096,6 @@ static void zend_revert_pass_two(zend_op_array *op_array) } #endif - op_array->T -= ZEND_OBSERVER_ENABLED; - op_array->fn_flags &= ~ZEND_ACC_DONE_PASS_TWO; } @@ -1128,8 +1125,6 @@ static void zend_redo_pass_two(zend_op_array *op_array) } #endif - op_array->T += ZEND_OBSERVER_ENABLED; // reserve last temporary for observers if enabled - opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { @@ -1557,12 +1552,6 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l } } - if (ZEND_OBSERVER_ENABLED) { - for (i = 0; i < call_graph.op_arrays_count; i++) { - ++call_graph.op_arrays[i]->T; // ensure accurate temporary count for stack size precalculation - } - } - if (ZEND_OPTIMIZER_PASS_12 & optimization_level) { for (i = 0; i < call_graph.op_arrays_count; i++) { zend_adjust_fcall_stack_size_graph(call_graph.op_arrays[i]); @@ -1578,8 +1567,6 @@ ZEND_API void zend_optimize_script(zend_script *script, zend_long optimization_l zend_recalc_live_ranges(op_array, needs_live_range); } } else { - op_array->T -= ZEND_OBSERVER_ENABLED; // redo_pass_two will re-increment it - zend_redo_pass_two(op_array); if (op_array->live_range) { zend_recalc_live_ranges(op_array, NULL); diff --git a/ext/opcache/tests/gh13817.phpt b/ext/opcache/tests/gh13817.phpt new file mode 100644 index 0000000000000..0e5eb560d46f3 --- /dev/null +++ b/ext/opcache/tests/gh13817.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-13712 (Segmentation fault for enabled observers after pass 4) +--EXTENSIONS-- +opcache +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.show_output=1 +zend_test.observer.observe_all=1 +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=0x4069 +--FILE-- + +--EXPECTF-- + + + + + + + + +Ok + + + + + From b8e9c5ba6a8018de0bfa180e0b1576ecf6689a2f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:32:16 +0200 Subject: [PATCH 18/51] Fix bogus fallthrough path in firebird_handle_get_attribute() If getting the version fails, we should return -1 according to php_pdo_driver.h:259, not fall through to another attribute. Closes GH-15066. --- NEWS | 3 +++ ext/pdo_firebird/firebird_driver.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index a1086fd499149..d497db6690df9 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,9 @@ PHP NEWS . Fixed bug GH-13817 (Segmentation fault for enabled observers after pass 4). (Bob) +- PDO_Firebird: + . Fix bogus fallthrough path in firebird_handle_get_attribute(). (nielsdos) + - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c index 7dc40f510d459..03c9f1b7741c5 100644 --- a/ext/pdo_firebird/firebird_driver.c +++ b/ext/pdo_firebird/firebird_driver.c @@ -977,8 +977,7 @@ static int firebird_handle_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *v ZVAL_STRING(val, tmp); return 1; } - /* TODO Check this is correct? */ - ZEND_FALLTHROUGH; + return -1; case PDO_ATTR_FETCH_TABLE_NAMES: ZVAL_BOOL(val, H->fetch_table_names); From a924e1c71b81a4ce925688707c8ff772b5204345 Mon Sep 17 00:00:00 2001 From: LoongT4o <109949122+LoongT4o@users.noreply.github.com> Date: Tue, 23 May 2023 19:49:19 +0800 Subject: [PATCH 19/51] Fix the JIT buffer relocation failure at the corner case (#11266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid missing possible candidates due to the large address range of the free segment. Eg,  48000000-49400000 r-xs 08000000 00:0f 39322841               segment1 7ffff2ec8000-7ffff2f49000 rw-p 00000000 00:00 0              segment2 7ffff6fae000-7ffff735c000 r-xp 00200000 08:02 11538515       /usr/local/sbin/php-fpm original code will miss the opportunity between [7ffff2ec** - 7ffff2ec8000]. Fix issue #11265. Signed-off-by: Long, Tao Signed-off-by: Dmitry Stogov --- ext/opcache/shared_alloc_mmap.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index 1840b214705fa..d3a5916be89b3 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -76,8 +76,13 @@ static void *find_prefered_mmap_base(size_t requested_size) } if ((uintptr_t)execute_ex >= start) { /* the current segment lays before PHP .text segment or PHP .text segment itself */ + /*Search for candidates at the end of the free segment near the .text segment + to prevent candidates from being missed due to large hole*/ if (last_free_addr + requested_size <= start) { - last_candidate = last_free_addr; + last_candidate = ZEND_MM_ALIGNED_SIZE_EX(start - requested_size, huge_page_size); + if (last_candidate + requested_size > start) { + last_candidate -= huge_page_size; + } } if ((uintptr_t)execute_ex < end) { /* the current segment is PHP .text segment itself */ @@ -128,7 +133,10 @@ static void *find_prefered_mmap_base(size_t requested_size) if ((uintptr_t)execute_ex >= e_start) { /* the current segment lays before PHP .text segment or PHP .text segment itself */ if (last_free_addr + requested_size <= e_start) { - last_candidate = last_free_addr; + last_candidate = ZEND_MM_ALIGNED_SIZE_EX(e_start - requested_size, huge_page_size); + if (last_candidate + requested_size > e_start) { + last_candidate -= huge_page_size; + } } if ((uintptr_t)execute_ex < e_end) { /* the current segment is PHP .text segment itself */ From 929536b6979c43dec0229857a03527a0136fafa1 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Wed, 3 Jul 2024 18:27:58 +0200 Subject: [PATCH 20/51] Hint the opcache shm mapping location only when JIT is enabled Closes GH-14793 Fixes GH-13775 --- NEWS | 2 ++ ext/opcache/shared_alloc_mmap.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index d497db6690df9..52cd632c1d325 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,8 @@ PHP NEWS - Opcache: . Fixed bug GH-13817 (Segmentation fault for enabled observers after pass 4). (Bob) + . Fixed bug GH-13775 (Memory leak possibly related to opcache SHM placement). + (Arnaud) - PDO_Firebird: . Fix bogus fallthrough path in firebird_handle_get_attribute(). (nielsdos) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index d3a5916be89b3..8da25db0bdb16 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -20,6 +20,7 @@ */ #include "zend_shared_alloc.h" +#include "jit/zend_jit.h" #ifdef USE_MMAP @@ -45,7 +46,7 @@ # define MAP_HUGETLB MAP_ALIGNED_SUPER #endif -#if (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__)) && !defined(__SANITIZE_ADDRESS__) +#if defined(HAVE_JIT) && (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__)) && !defined(__SANITIZE_ADDRESS__) static void *find_prefered_mmap_base(size_t requested_size) { size_t huge_page_size = 2 * 1024 * 1024; @@ -188,8 +189,17 @@ 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 -#if (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__)) && !defined(__SANITIZE_ADDRESS__) - void *hint = find_prefered_mmap_base(requested_size); +#if defined(HAVE_JIT) && (defined(__linux__) || defined(__FreeBSD__)) && (defined(__x86_64__) || defined (__aarch64__)) && !defined(__SANITIZE_ADDRESS__) + void *hint; + if (JIT_G(enabled) && JIT_G(buffer_size) + && zend_jit_check_support() == SUCCESS) { + hint = find_prefered_mmap_base(requested_size); + } else { + /* Do not use a hint if JIT is not enabled, as this profits only JIT and + * this is potentially unsafe when the only suitable candidate is just + * after the heap (e.g. in non-PIE builds) (GH-13775). */ + hint = MAP_FAILED; + } if (hint != MAP_FAILED) { # ifdef MAP_HUGETLB size_t huge_page_size = 2 * 1024 * 1024; From 40551dd74bcfeae961c616230f9eccff2df97177 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:29:48 +0200 Subject: [PATCH 21/51] Fix uninitialized memory in network.c See https://github.com/php/php-src/issues/14806#issuecomment-2208150509 and https://github.com/php/php-src/issues/14806#issuecomment-2208690481 Closes GH-15068. --- NEWS | 1 + main/network.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 52cd632c1d325..15e260714bdcc 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ PHP NEWS . Fixed bug GH-15023 (Memory leak in Zend/zend_ini.c). (nielsdos) . Fixed bug GH-13330 (Append -Wno-implicit-fallthrough flag conditionally). (Peter Kokot) + . Fix uninitialized memory in network.c. (nielsdos) - Curl: . Fixed case when curl_error returns an empty string. diff --git a/main/network.c b/main/network.c index a1165f6a29d6b..1133bbb3e86cb 100644 --- a/main/network.c +++ b/main/network.c @@ -861,7 +861,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short #if HAVE_IPV6 && HAVE_INET_PTON struct sockaddr_in6 in6; #endif - } local_address; + } local_address = {0}; int local_address_len = 0; if (sa->sa_family == AF_INET) { @@ -873,7 +873,6 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short local_address_len = sizeof(struct sockaddr_in); local_address.in4.sin_family = sa->sa_family; local_address.in4.sin_port = htons(bindport); - memset(&(local_address.in4.sin_zero), 0, sizeof(local_address.in4.sin_zero)); } } #if HAVE_IPV6 && HAVE_INET_PTON From ba909d7c43f03c907f94ad685139dce839b1da8c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 22 Jul 2024 12:53:54 +0100 Subject: [PATCH 22/51] Fix GH-14780: p(f)sockopen overflow on timeout argument. close GH-14785 --- NEWS | 1 + ext/standard/file.h | 6 ++++ ext/standard/fsock.c | 23 +++++++++++---- ext/standard/streamsfuncs.c | 2 -- ext/standard/tests/streams/gh14780.phpt | 38 +++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 ext/standard/tests/streams/gh14780.phpt diff --git a/NEWS b/NEWS index 15e260714bdcc..592ad5daa63fc 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,7 @@ PHP NEWS - Standard: . Fix passing non-finite timeout values in stream functions. (nielsdos) + . Fixed GH-14780 p(f)sockopen timeout overflow. (David Carlier) - Streams: . Fixed bug GH-15028 (Memory leak in ext/phar/stream.c). (nielsdos) diff --git a/ext/standard/file.h b/ext/standard/file.h index 2b2307cab7278..0f3ccd7c27ab3 100644 --- a/ext/standard/file.h +++ b/ext/standard/file.h @@ -60,6 +60,12 @@ PHPAPI ssize_t php_fputcsv(php_stream *stream, zval *fields, char delimiter, cha #define PHP_FILE_APPEND (1 << 3) #define PHP_FILE_NO_DEFAULT_CONTEXT (1 << 4) +#ifndef _WIN32 +#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX +#else +#define PHP_TIMEOUT_ULL_MAX UINT64_MAX +#endif + typedef enum _php_meta_tags_token { TOK_EOF = 0, TOK_OPENTAG, diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index 9e1a53c0ec2a0..0ad0735906ebc 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -73,14 +73,27 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) } /* prepare the timeout value for use */ + if (timeout != -1.0 && !(timeout >= 0.0 && timeout <= (double) PHP_TIMEOUT_ULL_MAX / 1000000.0)) { + if (port > 0) { + efree(hostname); + } + + if (hashkey) { + efree(hashkey); + } + + zend_argument_value_error(6, "must be -1 or between 0 and " ZEND_ULONG_FMT, (PHP_TIMEOUT_ULL_MAX / 1000000.0)); + RETURN_THROWS(); + } else { #ifndef PHP_WIN32 - conv = (time_t) (timeout * 1000000.0); - tv.tv_sec = conv / 1000000; + conv = (time_t) (timeout * 1000000.0); + tv.tv_sec = conv / 1000000; #else - conv = (long) (timeout * 1000000.0); - tv.tv_sec = conv / 1000000; + conv = (long) (timeout * 1000000.0); + tv.tv_sec = conv / 1000000; #endif - tv.tv_usec = conv % 1000000; + tv.tv_usec = conv % 1000000; + } stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err); diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 18e80ddda32ab..2a5487bf51f8d 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -33,13 +33,11 @@ #ifndef PHP_WIN32 #define php_select(m, r, w, e, t) select(m, r, w, e, t) typedef unsigned long long php_timeout_ull; -#define PHP_TIMEOUT_ULL_MAX ULLONG_MAX #else #include "win32/select.h" #include "win32/sockets.h" #include "win32/console.h" typedef unsigned __int64 php_timeout_ull; -#define PHP_TIMEOUT_ULL_MAX UINT64_MAX #endif #define GET_CTX_OPT(stream, wrapper, name, val) (PHP_STREAM_CONTEXT(stream) && NULL != (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), wrapper, name))) diff --git a/ext/standard/tests/streams/gh14780.phpt b/ext/standard/tests/streams/gh14780.phpt new file mode 100644 index 0000000000000..064e496b17538 --- /dev/null +++ b/ext/standard/tests/streams/gh14780.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-14780: p(f)sockopen overflow on timeout. +--SKIPIF-- + +--FILE-- +getMessage() . PHP_EOL; +} +try { + pfsockopen('udp://127.0.0.1', '63844', $code, $err, (PHP_INT_MIN/100000)-1); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +var_dump(pfsockopen('udp://127.0.0.1', '63844', $code, $err, -1)); +try { + pfsockopen('udp://127.0.0.1', '63844', $code, $err, NAN); +} catch (\ValueError $e) { + echo $e->getMessage() . PHP_EOL; +} +try { + pfsockopen('udp://127.0.0.1', '63844', $code, $err, INF); +} catch (\ValueError $e) { + echo $e->getMessage(); +} +?> +--EXPECTF-- +pfsockopen(): Argument #6 must be -1 or between 0 and %s +pfsockopen(): Argument #6 must be -1 or between 0 and %s +resource(%d) of type (persistent stream) +pfsockopen(): Argument #6 must be -1 or between 0 and %s +pfsockopen(): Argument #6 must be -1 or between 0 and %s From 350c10d98530e86af50652b6e594861d9bb838e9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 22 Jul 2024 23:16:38 +0100 Subject: [PATCH 23/51] fix GH-14785 pedantic error close GH-15071 --- ext/standard/fsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index 0ad0735906ebc..cb7a471e935a6 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -82,7 +82,7 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) efree(hashkey); } - zend_argument_value_error(6, "must be -1 or between 0 and " ZEND_ULONG_FMT, (PHP_TIMEOUT_ULL_MAX / 1000000.0)); + zend_argument_value_error(6, "must be -1 or between 0 and " ZEND_ULONG_FMT, ((double) PHP_TIMEOUT_ULL_MAX / 1000000.0)); RETURN_THROWS(); } else { #ifndef PHP_WIN32 From acf758d2eae705df171d381ad881c0c820ae375a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 23 Jul 2024 13:42:47 +0200 Subject: [PATCH 24/51] Fix build on platforms without JIT support (#15069) --- ext/opcache/shared_alloc_mmap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index 8da25db0bdb16..bfa0e9161ac75 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -20,7 +20,9 @@ */ #include "zend_shared_alloc.h" -#include "jit/zend_jit.h" +#ifdef HAVE_JIT +# include "jit/zend_jit.h" +#endif #ifdef USE_MMAP From 0956267c08b8ea8cc8e8e2b31fe0ce12f060e47e Mon Sep 17 00:00:00 2001 From: Levi Morrison Date: Tue, 23 Jul 2024 16:15:07 -0600 Subject: [PATCH 25/51] Fix warnings in session/spl This fixes -Winline errors where the functions are not ever inlined. Also fixes some signature mismatches which were fixed previously but for whatever reason were not ported to all maintained branches: /usr/local/src/php/ext/session/session.c:1299:20: warning:conflicting types for 'php_session_send_cookie' due to enum/integer mismatch; have 'zend_result(void)' {aka 'ZEND_RESULT_CODE(void)'} [-Wenum-int-mismatch] 1299 | static zend_result php_session_send_cookie(void) /* {{{ */ | ^~~~~~~~~~~~~~~~~~~~~~~ /usr/local/src/php/ext/session/session.c:100:12: note: previous declaration of 'php_session_send_cookie' with type 'int(void)' 100 | static int php_session_send_cookie(void); | ^~~~~~~~~~~~~~~~~~~~~~~ --- ext/session/session.c | 10 +++++----- ext/spl/spl_directory.c | 2 +- ext/spl/spl_heap.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/session/session.c b/ext/session/session.c index 74a0546b8490c..ea7f2b6403efa 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -56,8 +56,8 @@ PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps) -static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); -static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); +static zend_result php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); +static zend_result (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); static void php_session_track_init(void); /* SessionHandler class */ @@ -97,8 +97,8 @@ zend_class_entry *php_session_update_timestamp_iface_entry; #define APPLY_TRANS_SID (PS(use_trans_sid) && !PS(use_only_cookies)) -static int php_session_send_cookie(void); -static int php_session_abort(void); +static zend_result php_session_send_cookie(void); +static zend_result php_session_abort(void); /* Initialized in MINIT, readonly otherwise. */ static int my_module_number = 0; @@ -122,7 +122,7 @@ static inline void php_rinit_session_globals(void) /* {{{ */ /* }}} */ /* Dispatched by RSHUTDOWN and by php_session_destroy */ -static inline void php_rshutdown_session_globals(void) /* {{{ */ +static void php_rshutdown_session_globals(void) /* {{{ */ { /* Do NOT destroy PS(mod_user_names) here! */ if (!Z_ISUNDEF(PS(http_session_vars))) { diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 03b959daa3bbf..0440ff59c8ba9 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -240,7 +240,7 @@ PHPAPI zend_string *spl_filesystem_object_get_path(spl_filesystem_object *intern return zend_string_copy(intern->path); } /* }}} */ -static inline zend_result spl_filesystem_object_get_file_name(spl_filesystem_object *intern) /* {{{ */ +static zend_result spl_filesystem_object_get_file_name(spl_filesystem_object *intern) /* {{{ */ { if (intern->file_name) { /* already known */ diff --git a/ext/spl/spl_heap.c b/ext/spl/spl_heap.c index db35511f08d2d..736f151da5846 100644 --- a/ext/spl/spl_heap.c +++ b/ext/spl/spl_heap.c @@ -501,7 +501,7 @@ static zend_result spl_heap_object_count_elements(zend_object *object, zend_long } /* }}} */ -static inline HashTable* spl_heap_object_get_debug_info(zend_class_entry *ce, zend_object *obj) { /* {{{ */ +static HashTable* spl_heap_object_get_debug_info(zend_class_entry *ce, zend_object *obj) { /* {{{ */ spl_heap_object *intern = spl_heap_from_obj(obj); zval tmp, heap_array; zend_string *pnstr; From d41e97ae66f6f3799dc349e4178b5de776859f9e Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 24 Jul 2024 08:21:16 +0300 Subject: [PATCH 26/51] Workaraound against false positive GCC array bounds error (#15078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents compilation error when compiling PHP by GCC with "-O2 -g -Wall -Werror" zend_API.c:2754:34: error: array subscript ‘zend_function {aka const union _zend_function}[0]’ is partly outside array bounds of ‘unsigned char[160]’ [-Werror=array-bounds=] 2754 | if (ZSTR_VAL(fptr->common.function_name)[0] != '_' --- Zend/zend_API.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 4c447845e5474..eb6e349f7ec21 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2559,8 +2559,8 @@ static void zend_check_magic_method_no_return_type( ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, zend_string *lcname, int error_type) /* {{{ */ { - if (ZSTR_VAL(fptr->common.function_name)[0] != '_' - || ZSTR_VAL(fptr->common.function_name)[1] != '_') { + if (ZSTR_VAL(lcname)[0] != '_' + || ZSTR_VAL(lcname)[1] != '_') { return; } From 5fbda7309930d03494b4ad41dbed657cb2aae8be Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 24 Jul 2024 16:45:20 +0200 Subject: [PATCH 27/51] Fix GH-15087 IntlChar::foldCase()'s $option is not optional Since that parameter is supposed to be optional (and has been prior to PHP 8.0.0), we fix the implementation instead of the stub. Closes GH-15091. --- NEWS | 3 +++ ext/intl/uchar/tests/gh15087.phpt | 10 ++++++++++ ext/intl/uchar/uchar.c | 3 ++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 ext/intl/uchar/tests/gh15087.phpt diff --git a/NEWS b/NEWS index 592ad5daa63fc..59ae1e052b3cb 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,9 @@ PHP NEWS . Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory leak). (nielsdos, dstogov) +- Intl: + . Fixed bug GH-15087 (IntlChar::foldCase()'s $option is not optional). (cmb) + - Opcache: . Fixed bug GH-13817 (Segmentation fault for enabled observers after pass 4). (Bob) diff --git a/ext/intl/uchar/tests/gh15087.phpt b/ext/intl/uchar/tests/gh15087.phpt new file mode 100644 index 0000000000000..62009857ab1d6 --- /dev/null +++ b/ext/intl/uchar/tests/gh15087.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-15087 (IntlChar::foldCase()'s $option is not optional) +--EXTENSIONS-- +intl +--FILE-- + +--EXPECT-- +string(1) "i" diff --git a/ext/intl/uchar/uchar.c b/ext/intl/uchar/uchar.c index 771805925827f..7cb6a553af824 100644 --- a/ext/intl/uchar/uchar.c +++ b/ext/intl/uchar/uchar.c @@ -392,8 +392,9 @@ IC_METHOD(foldCase) { zend_string *string_codepoint; zend_long int_codepoint; - ZEND_PARSE_PARAMETERS_START(2, 2) + ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STR_OR_LONG(string_codepoint, int_codepoint) + Z_PARAM_OPTIONAL Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); From af789afbe88e36d2870875918adfdb8659f0ccce Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 26 Jul 2024 14:57:16 +0200 Subject: [PATCH 28/51] Fix type incompatibility in assignment. This partially reverts 0956267c08b8ea8cc8e8e2b31fe0ce12f060e47e, which introduced a type incompatibility where an `int` function is assigned to a `zend_result` function. That yields a level 1 C4133 warning on MSVC, and usually (e.g. in CI) level 1 warnings are elevated to errors, so the build fails.[1] The PHP-8.3 branch and up are uneffected by this, so the upward merges should be empty. [1] --- ext/session/session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/session/session.c b/ext/session/session.c index ea7f2b6403efa..8b95b31e8fe49 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -56,8 +56,9 @@ PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps) -static zend_result php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); -static zend_result (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); +static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra); +/* the following signature must match (*php_rfc1867_callback) in main/rfc1867.h */ +static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra); static void php_session_track_init(void); /* SessionHandler class */ From 404bd30810a716ee78eddf77ac6f9164d90b4d16 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 27 Jul 2024 16:09:50 +0200 Subject: [PATCH 29/51] Fix CI failure after Curl update (#15124) --- ext/standard/tests/file/bug52820.phpt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/standard/tests/file/bug52820.phpt b/ext/standard/tests/file/bug52820.phpt index ff816178cef67..c884f7edb91ff 100644 --- a/ext/standard/tests/file/bug52820.phpt +++ b/ext/standard/tests/file/bug52820.phpt @@ -46,21 +46,21 @@ echo "\nDone.\n"; temp stream \(close after\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( -?\d+)? +\* Closing connection( #?-?\d+)? memory stream \(close after\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( -?\d+)? +\* Closing connection( #?-?\d+)? temp stream \(leak\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( -?\d+)? +\* Closing connection( #?-?\d+)? memory stream \(leak\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( -?\d+)? +\* Closing connection( #?-?\d+)? Done\. From 4df858602a9700a58a402ef2aea18c54d16ef719 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 27 Jul 2024 16:37:01 +0200 Subject: [PATCH 30/51] Fix nightly failure in test variation due to number of temp variables varying when observers are enabled --- ext/opcache/tests/opt/gh11170.phpt | 6 +++--- ext/opcache/tests/opt/nullsafe_002.phpt | 4 ++-- ext/opcache/tests/opt/prop_types.phpt | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/opcache/tests/opt/gh11170.phpt b/ext/opcache/tests/opt/gh11170.phpt index ca00c5e852966..9ea733f92b104 100644 --- a/ext/opcache/tests/opt/gh11170.phpt +++ b/ext/opcache/tests/opt/gh11170.phpt @@ -39,7 +39,7 @@ test_and(); ?> --EXPECTF-- $_main: - ; (lines=5, args=0, vars=0, tmps=2, ssa_vars=0, no_loops) + ; (lines=5, args=0, vars=0, tmps=%d, ssa_vars=0, no_loops) ; (after dfa pass) ; %s ; return [long] RANGE[1..1] @@ -53,7 +53,7 @@ BB0: 0004 RETURN int(1) test_or: - ; (lines=11, args=0, vars=2, tmps=7, ssa_vars=11, no_loops) + ; (lines=11, args=0, vars=2, tmps=%d, ssa_vars=11, no_loops) ; (after dfa pass) ; %s ; return [long] RANGE[-20..-1] @@ -99,7 +99,7 @@ BB3: 0010 RETURN #10.T8 [long] RANGE[-20..-1] test_and: - ; (lines=11, args=0, vars=2, tmps=7, ssa_vars=11, no_loops) + ; (lines=11, args=0, vars=2, tmps=%d, ssa_vars=11, no_loops) ; (after dfa pass) ; %s ; return [long] RANGE[-28..-25] diff --git a/ext/opcache/tests/opt/nullsafe_002.phpt b/ext/opcache/tests/opt/nullsafe_002.phpt index 73e607a66cf22..a8d9f1482c6e1 100644 --- a/ext/opcache/tests/opt/nullsafe_002.phpt +++ b/ext/opcache/tests/opt/nullsafe_002.phpt @@ -20,7 +20,7 @@ function test(?Test $test) { ?> --EXPECTF-- $_main: - ; (lines=1, args=0, vars=0, tmps=0, ssa_vars=0, no_loops) + ; (lines=1, args=0, vars=0, tmps=%d, ssa_vars=0, no_loops) ; (before dfa pass) ; %s ; return [long] RANGE[1..1] @@ -30,7 +30,7 @@ BB0: 0000 RETURN int(1) test: - ; (lines=7, args=1, vars=1, tmps=2, ssa_vars=6, no_loops) + ; (lines=7, args=1, vars=1, tmps=%d, ssa_vars=6, no_loops) ; (before dfa pass) ; %s ; return [null] RANGE[0..0] diff --git a/ext/opcache/tests/opt/prop_types.phpt b/ext/opcache/tests/opt/prop_types.phpt index 44e8f3d9767d2..ec57bf13580cf 100644 --- a/ext/opcache/tests/opt/prop_types.phpt +++ b/ext/opcache/tests/opt/prop_types.phpt @@ -40,7 +40,7 @@ function noScope(Test $test) { ?> --EXPECTF-- $_main: - ; (lines=1, args=0, vars=0, tmps=0, ssa_vars=0, no_loops) + ; (lines=1, args=0, vars=0, tmps=%d, ssa_vars=0, no_loops) ; (before dfa pass) ; %s ; return [long] RANGE[1..1] @@ -50,7 +50,7 @@ BB0: 0000 RETURN int(1) noScope: - ; (lines=10, args=1, vars=1, tmps=4, ssa_vars=5, no_loops) + ; (lines=10, args=1, vars=1, tmps=%d, ssa_vars=5, no_loops) ; (before dfa pass) ; %s ; return [null] RANGE[0..0] @@ -70,7 +70,7 @@ BB0: 0009 RETURN null Test::inTest: - ; (lines=9, args=0, vars=0, tmps=4, ssa_vars=3, no_loops) + ; (lines=9, args=0, vars=0, tmps=%d, ssa_vars=3, no_loops) ; (before dfa pass) ; %s ; return [null] RANGE[0..0] @@ -88,7 +88,7 @@ BB0: 0008 RETURN null Test::inTestWithTest2: - ; (lines=10, args=1, vars=1, tmps=4, ssa_vars=5, no_loops) + ; (lines=10, args=1, vars=1, tmps=%d, ssa_vars=5, no_loops) ; (before dfa pass) ; %s ; return [null] RANGE[0..0] @@ -108,7 +108,7 @@ BB0: 0009 RETURN null Test2::inTest2: - ; (lines=9, args=0, vars=0, tmps=4, ssa_vars=3, no_loops) + ; (lines=9, args=0, vars=0, tmps=%d, ssa_vars=3, no_loops) ; (before dfa pass) ; %s ; return [null] RANGE[0..0] From fdae7c23f0a04a53fa7c640f2f7993b68e73a713 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 28 Jul 2024 14:34:26 +0200 Subject: [PATCH 31/51] Fix CI failure on macOS after Curl update --- ext/standard/tests/file/bug52820.phpt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/standard/tests/file/bug52820.phpt b/ext/standard/tests/file/bug52820.phpt index c884f7edb91ff..2d3cedad87944 100644 --- a/ext/standard/tests/file/bug52820.phpt +++ b/ext/standard/tests/file/bug52820.phpt @@ -46,21 +46,21 @@ echo "\nDone.\n"; temp stream \(close after\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( #?-?\d+)? +\* [Cc]losing connection( #?-?\d+)? memory stream \(close after\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( #?-?\d+)? +\* [Cc]losing connection( #?-?\d+)? temp stream \(leak\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( #?-?\d+)? +\* [Cc]losing connection( #?-?\d+)? memory stream \(leak\): About to rewind! (\* processing: file:\/\/\/i_dont_exist\/\n)?\* Couldn't open file \/i_dont_exist\/ -\* Closing connection( #?-?\d+)? +\* [Cc]losing connection( #?-?\d+)? Done\. From d214a359c90c5122262c609c774f1bc34348836e Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Mon, 29 Jul 2024 00:11:48 +0200 Subject: [PATCH 32/51] [skip ci] Sync CODEOWNERS (#15017) This repeats the sync as noted in the GH-13591 and the discussion https://news-web.php.net/php.internals/124472 The CODEOWNERS file is related to the targeted branch in the pull request and not only the master branch. - Added a note to change the earliest supported PHP branch and not only master branch - Synced GitHub ID's and paths across the PHP-8.2, PHP-8.3 and master branches - Add note how changes here should be analogous to bug fixes with a link to CONTRIBUTING.md which describes which branch to target --- .github/CODEOWNERS | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ed1a5105db797..24a656eac19e0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,36 +5,53 @@ # the problem area and could aid in deciding whether a pull request is ready # for merging. # +# When changing this file, please make sure to commit the changes to the +# earliest supported PHP branch (PHP-X.Y) and not only to the master branch. +# GitHub reads the CODEOWNERS file from the pull request's targeted branch. +# Commit changes here similar to bug fixes: +# https://github.com/php/php-src/blob/master/CONTRIBUTING.md#pull-requests +# # 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/bcmath @Girgias @nielsdos @SakiTakamachi /ext/curl @adoy /ext/date @derickr /ext/dba @Girgias /ext/dom @nielsdos /ext/ffi @dstogov +/ext/gd @devnexen /ext/gettext @devnexen /ext/gmp @Girgias /ext/imap @Girgias /ext/intl @devnexen /ext/json @bukka /ext/libxml @nielsdos -/ext/mbstring @alexdowad +/ext/mbstring @alexdowad @youkidearitai +/ext/mysqlnd @SakiTakamachi /ext/odbc @NattyNarwhal /ext/opcache @dstogov @iluuu1994 /ext/openssl @bukka -/ext/pdo_odbc @NattyNarwhal -/ext/pdo_pgsql @devnexen +/ext/pcntl @devnexen +/ext/pdo @SakiTakamachi +/ext/pdo_dblib @SakiTakamachi +/ext/pdo_firebird @SakiTakamachi +/ext/pdo_mysql @SakiTakamachi +/ext/pdo_odbc @NattyNarwhal @SakiTakamachi +/ext/pdo_pgsql @devnexen @SakiTakamachi +/ext/pdo_sqlite @SakiTakamachi /ext/pgsql @devnexen /ext/random @TimWolla @zeriyoshi /ext/session @Girgias +/ext/simplexml @nielsdos /ext/sockets @devnexen /ext/spl @Girgias /ext/standard @bukka +/ext/xml @nielsdos /ext/xmlreader @nielsdos +/ext/xmlwriter @nielsdos /ext/xsl @nielsdos /main @bukka /sapi/fpm @bukka @@ -44,6 +61,8 @@ /Zend/zend_API.* @dstogov @iluuu1994 /Zend/zend_call_stack.* @arnaud-lb /Zend/zend_closures.* @dstogov +/Zend/zend_compile.* @iluuu1994 +/Zend/zend_enum.* @iluuu1994 /Zend/zend_execute.* @dstogov @iluuu1994 /Zend/zend_execute_API.c @dstogov @iluuu1994 /Zend/zend_gc.* @dstogov @arnaud-lb From 99e0d3fe0981afc9fc1862b0c863a2d267a8c38a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 30 Jul 2024 14:53:19 +0200 Subject: [PATCH 33/51] Fix destruction of generator running in fibers during shutdown (#15158) The destructor of generators is a no-op when the generator is running in a fiber, because the fiber may resume the generator. Normally the destructor is not called in this case, but this can happen during shutdown. We detect that a generator is running in a fiber with the ZEND_GENERATOR_IN_FIBER flag. This change fixes two cases not handled by this mechanism: - The ZEND_GENERATOR_IN_FIBER flag was not added when resuming a "yield from $nonGenerator" - When a generator that is running in a fiber has multiple children (aka multiple generators yielding from it), all of them could be considered to also run in a fiber (only one actually is), and could leak if not destroyed before shutdown. --- Zend/tests/gh15108-001.phpt | 36 ++++++++++++++++++ Zend/tests/gh15108-002.phpt | 40 ++++++++++++++++++++ Zend/tests/gh15108-003.phpt | 38 +++++++++++++++++++ Zend/tests/gh15108-004.phpt | 39 +++++++++++++++++++ Zend/tests/gh15108-005.phpt | 45 ++++++++++++++++++++++ Zend/tests/gh15108-006.phpt | 49 ++++++++++++++++++++++++ Zend/tests/gh15108-007.phpt | 51 +++++++++++++++++++++++++ Zend/zend_generators.c | 75 ++++++++++++++++++++++++++++++++----- Zend/zend_generators.h | 1 + 9 files changed, 364 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/gh15108-001.phpt create mode 100644 Zend/tests/gh15108-002.phpt create mode 100644 Zend/tests/gh15108-003.phpt create mode 100644 Zend/tests/gh15108-004.phpt create mode 100644 Zend/tests/gh15108-005.phpt create mode 100644 Zend/tests/gh15108-006.phpt create mode 100644 Zend/tests/gh15108-007.phpt diff --git a/Zend/tests/gh15108-001.phpt b/Zend/tests/gh15108-001.phpt new file mode 100644 index 0000000000000..9971ada5b37fb --- /dev/null +++ b/Zend/tests/gh15108-001.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-15108 001: Segfault with delegated generator in suspended fiber +--FILE-- +current()); + $iterable->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15108-002.phpt b/Zend/tests/gh15108-002.phpt new file mode 100644 index 0000000000000..64bdafaebf5ed --- /dev/null +++ b/Zend/tests/gh15108-002.phpt @@ -0,0 +1,40 @@ +--TEST-- +GH-15108 002: Segfault with delegated generator in suspended fiber +--FILE-- +current()); + $iterable->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15108-003.phpt b/Zend/tests/gh15108-003.phpt new file mode 100644 index 0000000000000..c32e7b8f0c8d7 --- /dev/null +++ b/Zend/tests/gh15108-003.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-15108 003: Segfault with delegated generator in suspended fiber +--FILE-- +current()); + $b->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15108-004.phpt b/Zend/tests/gh15108-004.phpt new file mode 100644 index 0000000000000..caa548e515d3a --- /dev/null +++ b/Zend/tests/gh15108-004.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-15108 004: Segfault with delegated generator in suspended fiber +--FILE-- +current()); + var_dump($c->current()); + $b->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15108-005.phpt b/Zend/tests/gh15108-005.phpt new file mode 100644 index 0000000000000..76457e62c3f12 --- /dev/null +++ b/Zend/tests/gh15108-005.phpt @@ -0,0 +1,45 @@ +--TEST-- +GH-15108 005: Segfault with delegated generator in suspended fiber +--FILE-- +current()); + +$fiber = new Fiber(function () use ($iterable) { + $iterable->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15108-006.phpt b/Zend/tests/gh15108-006.phpt new file mode 100644 index 0000000000000..5fb830d97cb1d --- /dev/null +++ b/Zend/tests/gh15108-006.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-15108 006: Segfault with delegated generator in suspended fiber +--FILE-- +current()); +var_dump($b->current()); + +$fiber = new Fiber(function () use ($a, $b, $g) { + $a->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15108-007.phpt b/Zend/tests/gh15108-007.phpt new file mode 100644 index 0000000000000..d66a8010a83f4 --- /dev/null +++ b/Zend/tests/gh15108-007.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-15108 007: Segfault with delegated generator in suspended fiber +--FILE-- +current()); +var_dump($b->current()); + +$fiber = new Fiber(function () use ($a, $b, $c, $d, $g) { + $b->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +string(3) "foo" +==DONE== diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 1d785377e82e7..f7475ad6fbb77 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -19,6 +19,7 @@ #include "zend.h" #include "zend_API.h" +#include "zend_hash.h" #include "zend_interfaces.h" #include "zend_exceptions.h" #include "zend_generators.h" @@ -216,19 +217,68 @@ static zend_always_inline void clear_link_to_root(zend_generator *generator) { } } +/* In the context of zend_generator_dtor_storage during shutdown, check if + * the intermediate node 'generator' is running in a fiber */ +static inline bool check_node_running_in_fiber(zend_generator *generator) { + ZEND_ASSERT(EG(flags) & EG_FLAGS_IN_SHUTDOWN); + ZEND_ASSERT(generator->execute_data); + + if (generator->flags & ZEND_GENERATOR_IN_FIBER) { + return true; + } + + if (generator->node.children == 0) { + return false; + } + + if (generator->flags & ZEND_GENERATOR_DTOR_VISITED) { + return false; + } + generator->flags |= ZEND_GENERATOR_DTOR_VISITED; + + if (generator->node.children == 1) { + if (check_node_running_in_fiber(generator->node.child.single)) { + goto in_fiber; + } + return false; + } + + zend_generator *child; + ZEND_HASH_FOREACH_PTR(generator->node.child.ht, child) { + if (check_node_running_in_fiber(child)) { + goto in_fiber; + } + } ZEND_HASH_FOREACH_END(); + return false; + +in_fiber: + generator->flags |= ZEND_GENERATOR_IN_FIBER; + return true; +} + static void zend_generator_dtor_storage(zend_object *object) /* {{{ */ { zend_generator *generator = (zend_generator*) object; + zend_generator *current_generator = zend_generator_get_current(generator); zend_execute_data *ex = generator->execute_data; uint32_t op_num, try_catch_offset; int i; - /* Generator is running in a suspended fiber. - * Will be dtor during fiber dtor */ - if (zend_generator_get_current(generator)->flags & ZEND_GENERATOR_IN_FIBER) { - /* Prevent finally blocks from yielding */ - generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; - return; + /* If current_generator is running in a fiber, there are 2 cases to consider: + * - If generator is also marked with ZEND_GENERATOR_IN_FIBER, then the + * entire path from current_generator to generator is executing in a + * fiber. Do not dtor now: These will be dtor when terminating the fiber. + * - If generator is not marked with ZEND_GENERATOR_IN_FIBER, and has a + * child marked with ZEND_GENERATOR_IN_FIBER, then this an intermediate + * node of case 1. Otherwise generator is not executing in a fiber and we + * can dtor. + */ + if (current_generator->flags & ZEND_GENERATOR_IN_FIBER) { + if (check_node_running_in_fiber(generator)) { + /* Prevent finally blocks from yielding */ + generator->flags |= ZEND_GENERATOR_FORCED_CLOSE; + return; + } } /* leave yield from mode to properly allow finally execution */ @@ -722,6 +772,11 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ return; } + if (EG(active_fiber)) { + orig_generator->flags |= ZEND_GENERATOR_IN_FIBER; + generator->flags |= ZEND_GENERATOR_IN_FIBER; + } + /* Drop the AT_FIRST_YIELD flag */ orig_generator->flags &= ~ZEND_GENERATOR_AT_FIRST_YIELD; @@ -752,7 +807,8 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ EG(current_execute_data) = original_execute_data; EG(jit_trace_num) = original_jit_trace_num; - orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT; + orig_generator->flags &= ~(ZEND_GENERATOR_DO_INIT | ZEND_GENERATOR_IN_FIBER); + generator->flags &= ~ZEND_GENERATOR_IN_FIBER; return; } /* If there are no more delegated values, resume the generator @@ -765,8 +821,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ } /* Resume execution */ - generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING - | (EG(active_fiber) ? ZEND_GENERATOR_IN_FIBER : 0); + generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING; if (!ZEND_OBSERVER_ENABLED) { zend_execute_ex(generator->execute_data); } else { @@ -817,7 +872,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ goto try_again; } - orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT; + orig_generator->flags &= ~(ZEND_GENERATOR_DO_INIT | ZEND_GENERATOR_IN_FIBER); } /* }}} */ diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index 4ccc42b92f668..a3daba3a839bb 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -93,6 +93,7 @@ static const zend_uchar ZEND_GENERATOR_FORCED_CLOSE = 0x2; static const zend_uchar ZEND_GENERATOR_AT_FIRST_YIELD = 0x4; static const zend_uchar ZEND_GENERATOR_DO_INIT = 0x8; static const zend_uchar ZEND_GENERATOR_IN_FIBER = 0x10; +static const zend_uchar ZEND_GENERATOR_DTOR_VISITED = 0x20; void zend_register_generator_ce(void); ZEND_API void zend_generator_close(zend_generator *generator, bool finished_execution); From 58cf903a10037008ae2eb97c640c337862b7beeb Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 30 Jul 2024 14:55:33 +0200 Subject: [PATCH 34/51] [ci skip] NEWS --- NEWS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 59ae1e052b3cb..43bb8f54a8e73 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,8 @@ PHP NEWS . Fixed bug GH-13330 (Append -Wno-implicit-fallthrough flag conditionally). (Peter Kokot) . Fix uninitialized memory in network.c. (nielsdos) + . Fixed bug GH-15108 (Segfault when destroying generator during shutdown). + (Arnaud) - Curl: . Fixed case when curl_error returns an empty string. @@ -25,7 +27,7 @@ PHP NEWS . Fixed bug GH-13817 (Segmentation fault for enabled observers after pass 4). (Bob) . Fixed bug GH-13775 (Memory leak possibly related to opcache SHM placement). - (Arnaud) + (Arnaud, nielsdos) - PDO_Firebird: . Fix bogus fallthrough path in firebird_handle_get_attribute(). (nielsdos) From b282dd749f8b4133724160e3751e2edda03593ae Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:15:53 +0200 Subject: [PATCH 35/51] Fix UAF when removing doctype and using foreach iteration This is an old bug, but this is pretty easy to fix. It's basically applying the same fix as I did for e878b9f. Reported by YuanchengJiang. Closes GH-15143. --- NEWS | 3 +++ ext/dom/dom_iterators.c | 2 +- ext/dom/nodelist.c | 2 +- ext/dom/php_dom.h | 1 + ext/dom/tests/uaf_doctype_iterator.phpt | 26 +++++++++++++++++++++++++ 5 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 ext/dom/tests/uaf_doctype_iterator.phpt diff --git a/NEWS b/NEWS index 43bb8f54a8e73..0036ce3230afd 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,9 @@ PHP NEWS . Fixed case when curl_error returns an empty string. (David Carlier) +- DOM: + . Fix UAF when removing doctype and using foreach iteration. (nielsdos) + - FFI: . Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory leak). (nielsdos, dstogov) diff --git a/ext/dom/dom_iterators.c b/ext/dom/dom_iterators.c index 670f08a679f2e..866cb5a07e99f 100644 --- a/ext/dom/dom_iterators.c +++ b/ext/dom/dom_iterators.c @@ -295,7 +295,7 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, i if (objmap->nodetype == XML_ATTRIBUTE_NODE) { curnode = (xmlNodePtr) nodep->properties; } else { - curnode = (xmlNodePtr) nodep->children; + curnode = dom_nodelist_iter_start_first_child(nodep); } } else { if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) { diff --git a/ext/dom/nodelist.c b/ext/dom/nodelist.c index a8e713f67d03e..6ed561e6d68e0 100644 --- a/ext/dom/nodelist.c +++ b/ext/dom/nodelist.c @@ -31,7 +31,7 @@ * Since: */ -static xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep) +xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep) { if (nodep->type == XML_ENTITY_REF_NODE) { /* See entityreference.c */ diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index ccf665c417cd8..d0637e4674e3d 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -156,6 +156,7 @@ void php_dom_named_node_map_get_item_into_zval(dom_nnodemap_object *objmap, zend void php_dom_nodelist_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value); int php_dom_get_namednodemap_length(dom_object *obj); int php_dom_get_nodelist_length(dom_object *obj); +xmlNodePtr dom_nodelist_iter_start_first_child(xmlNodePtr nodep); #define DOM_GET_OBJ(__ptr, __id, __prtype, __intern) { \ __intern = Z_DOMOBJ_P(__id); \ diff --git a/ext/dom/tests/uaf_doctype_iterator.phpt b/ext/dom/tests/uaf_doctype_iterator.phpt new file mode 100644 index 0000000000000..b166a83955248 --- /dev/null +++ b/ext/dom/tests/uaf_doctype_iterator.phpt @@ -0,0 +1,26 @@ +--TEST-- +UAF when removing doctype and iterating over the child nodes +--EXTENSIONS-- +dom +--CREDITS-- +Yuancheng Jiang +--FILE-- +loadXML(<< +]> +&foo1; +XML); +$ref = $dom->documentElement->firstChild; +$nodes = $ref->childNodes; +$dom->removeChild($dom->doctype); +foreach($nodes as $str) {} +var_dump($nodes); +?> +--EXPECTF-- +object(DOMNodeList)#%d (1) { + ["length"]=> + int(0) +} From dc670cb7f62cf3354abfb10b7c77c74d06715745 Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Fri, 2 Aug 2024 08:33:57 +0200 Subject: [PATCH 36/51] Fix GH-13199: Redundant prompt in phpdbg with libedit/readline When using libedit/readline integration in phpdbg: ./configure --with-libedit --enable-phpdbg-readline EOF makes editline write prompt again in local console mode. For example, this can be noticed when reading phpt test files from STDIN and running phpdbg: ./sapi/cli/php run-tests.php sapi/phpdbg Closes GH-13199 --- NEWS | 4 ++++ sapi/phpdbg/phpdbg_cmd.c | 34 +++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 0036ce3230afd..b2db9a9697dca 100644 --- a/NEWS +++ b/NEWS @@ -35,6 +35,10 @@ PHP NEWS - PDO_Firebird: . Fix bogus fallthrough path in firebird_handle_get_attribute(). (nielsdos) +- PHPDBG: + . Fixed bug GH-13199 (EOF emits redundant prompt in phpdbg local console mode + with libedit/readline). (Peter Kokot) + - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/sapi/phpdbg/phpdbg_cmd.c b/sapi/phpdbg/phpdbg_cmd.c index 7e6a87fcc89e3..6045b6564da0d 100644 --- a/sapi/phpdbg/phpdbg_cmd.c +++ b/sapi/phpdbg/phpdbg_cmd.c @@ -23,6 +23,10 @@ #include "phpdbg_prompt.h" #include "phpdbg_io.h" +#ifdef HAVE_UNISTD_H +# include +#endif + ZEND_EXTERN_MODULE_GLOBALS(phpdbg) static inline const char *phpdbg_command_name(const phpdbg_command_t *command, char *buffer) { @@ -745,17 +749,29 @@ PHPDBG_API char *phpdbg_read_input(const char *buffered) /* {{{ */ if ((PHPDBG_G(flags) & (PHPDBG_IS_STOPPING | PHPDBG_IS_RUNNING)) != PHPDBG_IS_STOPPING) { if (buffered == NULL) { #ifdef HAVE_PHPDBG_READLINE - char *cmd = readline(phpdbg_get_prompt()); - PHPDBG_G(last_was_newline) = 1; +# ifdef HAVE_UNISTD_H + /* EOF makes readline write prompt again in local console mode and + ignored if compiled without readline integration. */ + if (!isatty(PHPDBG_G(io)[PHPDBG_STDIN].fd)) { + char buf[PHPDBG_MAX_CMD]; + phpdbg_write("%s", phpdbg_get_prompt()); + phpdbg_consume_stdin_line(buf); + buffer = estrdup(buf); + } else +# endif + { + char *cmd = readline(phpdbg_get_prompt()); + PHPDBG_G(last_was_newline) = 1; + + if (!cmd) { + PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; + zend_bailout(); + } - if (!cmd) { - PHPDBG_G(flags) |= PHPDBG_IS_QUITTING; - zend_bailout(); + add_history(cmd); + buffer = estrdup(cmd); + free(cmd); } - - add_history(cmd); - buffer = estrdup(cmd); - free(cmd); #else phpdbg_write("%s", phpdbg_get_prompt()); phpdbg_consume_stdin_line(buf); From 67ce8759e87bff6ff783d081cb7780d508197220 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 3 Aug 2024 00:56:17 +0200 Subject: [PATCH 37/51] Fix GH-15179: Segmentation fault (null pointer dereference) in ext/standard/url_scanner_ex.re Based on analysis by Ilija: https://github.com/php/php-src/issues/15179#issuecomment-2261546902 * Apply suggestions from code review Closes GH-15206. Co-authored-by: Ilija Tovilo --- NEWS | 4 ++++ ext/standard/url_scanner_ex.re | 7 ++++++- tests/output/gh15179.phpt | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/output/gh15179.phpt diff --git a/NEWS b/NEWS index b2db9a9697dca..a86d3c59acac9 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,10 @@ PHP NEWS . Fixed bug GH-13775 (Memory leak possibly related to opcache SHM placement). (Arnaud, nielsdos) +- Output: + . Fixed bug GH-15179 (Segmentation fault (null pointer dereference) in + ext/standard/url_scanner_ex.re). (nielsdos) + - PDO_Firebird: . Fix bogus fallthrough path in firebird_handle_get_attribute(). (nielsdos) diff --git a/ext/standard/url_scanner_ex.re b/ext/standard/url_scanner_ex.re index 77b4d79793b65..b22cf3cc49c15 100644 --- a/ext/standard/url_scanner_ex.re +++ b/ext/standard/url_scanner_ex.re @@ -736,6 +736,7 @@ static inline int php_url_scanner_add_var_impl(const char *name, size_t name_len zend_string *encoded; url_adapt_state_ex_t *url_state; php_output_handler_func_t handler; + bool should_start = false; if (type) { url_state = &BG(url_adapt_session_ex); @@ -747,7 +748,7 @@ static inline int php_url_scanner_add_var_impl(const char *name, size_t name_len if (!url_state->active) { php_url_scanner_ex_activate(type); - php_output_start_internal(ZEND_STRL("URL-Rewriter"), handler, 0, PHP_OUTPUT_HANDLER_STDFLAGS); + should_start = true; url_state->active = 1; } @@ -786,6 +787,10 @@ static inline int php_url_scanner_add_var_impl(const char *name, size_t name_len smart_str_free(&hname); smart_str_free(&hvalue); + if (should_start) { + php_output_start_internal(ZEND_STRL("URL-Rewriter"), handler, 0, PHP_OUTPUT_HANDLER_STDFLAGS); + } + return SUCCESS; } diff --git a/tests/output/gh15179.phpt b/tests/output/gh15179.phpt new file mode 100644 index 0000000000000..207728446df75 --- /dev/null +++ b/tests/output/gh15179.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-15179 (Segmentation fault (null pointer dereference) in ext/standard/url_scanner_ex.re) +--CREDITS-- +YuanchengJiang +--INI-- +memory_limit=64M +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of %d bytes exhausted %s From 11fbe8801bb936c7011b4cefb3bea89380bf18e7 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:55:38 +0200 Subject: [PATCH 38/51] Fix SoapFault property destruction Two issues: 1) We should not modify the object when we pass invalid values 2) We should reset the properties to their default value otherwise we get a UAF. Regressed in df219ccf9d6be8302eef3ab6e26fd00fbd2fef71 Closes GH-15248. --- NEWS | 1 + ext/soap/soap.c | 13 ++++++++++--- ext/soap/tests/SoapFault/gh14586.phpt | 10 ++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index a86d3c59acac9..791c64e7197d9 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,7 @@ PHP NEWS - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) + . Fix SoapFault property destruction. (nielsdos) - Standard: . Fix passing non-finite timeout values in stream functions. (nielsdos) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index eaea09b461d57..3320f6dd4807f 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -529,6 +529,13 @@ static void soap_fault_dtor_properties(zval *obj) zval_ptr_dtor(Z_FAULT_DETAIL_P(obj)); zval_ptr_dtor(Z_FAULT_NAME_P(obj)); zval_ptr_dtor(Z_FAULT_HEADERFAULT_P(obj)); + ZVAL_EMPTY_STRING(Z_FAULT_STRING_P(obj)); + ZVAL_NULL(Z_FAULT_CODE_P(obj)); + ZVAL_NULL(Z_FAULT_CODENS_P(obj)); + ZVAL_NULL(Z_FAULT_ACTOR_P(obj)); + ZVAL_NULL(Z_FAULT_DETAIL_P(obj)); + ZVAL_NULL(Z_FAULT_NAME_P(obj)); + ZVAL_NULL(Z_FAULT_HEADERFAULT_P(obj)); } /* {{{ SoapFault constructor */ @@ -550,9 +557,6 @@ PHP_METHOD(SoapFault, __construct) Z_PARAM_ZVAL_OR_NULL(headerfault) ZEND_PARSE_PARAMETERS_END(); - /* Delete previously set properties */ - soap_fault_dtor_properties(ZEND_THIS); - if (code_str) { fault_code = ZSTR_VAL(code_str); fault_code_len = ZSTR_LEN(code_str); @@ -571,6 +575,9 @@ PHP_METHOD(SoapFault, __construct) RETURN_THROWS(); } + /* Delete previously set properties */ + soap_fault_dtor_properties(ZEND_THIS); + if (name != NULL && name_len == 0) { name = NULL; } diff --git a/ext/soap/tests/SoapFault/gh14586.phpt b/ext/soap/tests/SoapFault/gh14586.phpt index 91a273da09d5d..7aa7c37eb542a 100644 --- a/ext/soap/tests/SoapFault/gh14586.phpt +++ b/ext/soap/tests/SoapFault/gh14586.phpt @@ -6,7 +6,17 @@ soap __construct(null, "x"); +try { + $sf->__construct("", ""); +} catch (ValueError) {} +$sf->__construct(null, "x", headerFault: []); +var_dump($sf->headerfault); +$sf->__construct(null, "x"); +var_dump($sf->headerfault); ?> DONE --EXPECT-- +array(0) { +} +NULL DONE From ca84662c8798ce96dc2dffc7562b2c0d96c1a6f3 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 4 Aug 2024 23:49:05 +0200 Subject: [PATCH 39/51] Fix crash when converting array data for array in shm in xxh3 Closes GH-15237. --- NEWS | 3 +++ ext/hash/hash_xxhash.c | 10 +++++++--- ext/hash/tests/xxh3_convert_secret_to_string.phpt | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 ext/hash/tests/xxh3_convert_secret_to_string.phpt diff --git a/NEWS b/NEWS index 791c64e7197d9..050e3369959a1 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,9 @@ PHP NEWS . Fixed bug GH-14286 (ffi enum type (when enum has no name) make memory leak). (nielsdos, dstogov) +- Hash: + . Fix crash when converting array data for array in shm in xxh3. (nielsdos) + - Intl: . Fixed bug GH-15087 (IntlChar::foldCase()'s $option is not optional). (cmb) diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c index 8a155c9862271..24da754d8835a 100644 --- a/ext/hash/hash_xxhash.c +++ b/ext/hash/hash_xxhash.c @@ -174,11 +174,14 @@ zend_always_inline static void _PHP_XXH3_Init(PHP_XXH3_64_CTX *ctx, HashTable *a func_init_seed(&ctx->s, (XXH64_hash_t)Z_LVAL_P(_seed)); return; } else if (_secret) { - if (!try_convert_to_string(_secret)) { + zend_string *secret_string = zval_try_get_string(_secret); + if (UNEXPECTED(!secret_string)) { + ZEND_ASSERT(EG(exception)); return; } - size_t len = Z_STRLEN_P(_secret); + size_t len = ZSTR_LEN(secret_string); if (len < PHP_XXH3_SECRET_SIZE_MIN) { + zend_string_release(secret_string); zend_throw_error(NULL, "%s: Secret length must be >= %u bytes, %zu bytes passed", algo_name, XXH3_SECRET_SIZE_MIN, len); return; } @@ -186,7 +189,8 @@ zend_always_inline static void _PHP_XXH3_Init(PHP_XXH3_64_CTX *ctx, HashTable *a len = sizeof(ctx->secret); php_error_docref(NULL, E_WARNING, "%s: Secret content exceeding %zu bytes discarded", algo_name, sizeof(ctx->secret)); } - memcpy((unsigned char *)ctx->secret, Z_STRVAL_P(_secret), len); + memcpy((unsigned char *)ctx->secret, ZSTR_VAL(secret_string), len); + zend_string_release(secret_string); func_init_secret(&ctx->s, ctx->secret, len); return; } diff --git a/ext/hash/tests/xxh3_convert_secret_to_string.phpt b/ext/hash/tests/xxh3_convert_secret_to_string.phpt new file mode 100644 index 0000000000000..dfc161b084c0c --- /dev/null +++ b/ext/hash/tests/xxh3_convert_secret_to_string.phpt @@ -0,0 +1,14 @@ +--TEST-- +xxh3 convert secret to string should not modify (shm) array +--FILE-- + 4]); +} catch (Throwable) {} +var_dump($x); +?> +--EXPECT-- +array(1) { + ["secret"]=> + int(4) +} From 6713d516319074bc2481b8e7db82b10841c230f7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 6 Aug 2024 14:34:48 +0200 Subject: [PATCH 40/51] Fix odbc_data_source_001.phpt As of PHP 8.1.0, passing `null` to an `int` parameter is deprecated, and as such the deprecation notice breaks the test. So we instead pass an integer, and to avoid hard-coding a value we just add the two supported constants (which are supposed to have the values `1` and `2`, respectively). Closes GH-15254. --- ext/odbc/tests/odbc_data_source_001.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/odbc/tests/odbc_data_source_001.phpt b/ext/odbc/tests/odbc_data_source_001.phpt index b546de2cd9d8c..5ab3c6ca5c524 100644 --- a/ext/odbc/tests/odbc_data_source_001.phpt +++ b/ext/odbc/tests/odbc_data_source_001.phpt @@ -17,7 +17,7 @@ include 'config.inc'; $conn = odbc_connect($dsn, $user, $pass); try { - var_dump(odbc_data_source($conn, NULL)); + var_dump(odbc_data_source($conn, SQL_FETCH_FIRST + SQL_FETCH_NEXT)); } catch (\ValueError $e) { echo $e->getMessage() . \PHP_EOL; } From 28290655e864949ed0c08cad77240fb0956ab6e9 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:02:23 +0200 Subject: [PATCH 41/51] Revert "Fix bug #69280: SoapClient classmap doesn't support fully qualified class name (#14398)" This reverts commit 476706165a227ea6b1d73299b9b6486a6ca073a9. Although the fix is correct, people are relying on the bug and their code stopped working, see GH-15252. --- NEWS | 2 ++ ext/soap/php_encoding.c | 53 ++++-------------------------------- ext/soap/php_encoding.h | 2 -- ext/soap/php_soap.h | 2 +- ext/soap/soap.c | 11 +++++--- ext/soap/tests/bug69280.phpt | 44 ------------------------------ ext/soap/tests/bug69280.wsdl | 46 ------------------------------- 7 files changed, 16 insertions(+), 144 deletions(-) delete mode 100644 ext/soap/tests/bug69280.phpt delete mode 100644 ext/soap/tests/bug69280.wsdl diff --git a/NEWS b/NEWS index 050e3369959a1..c4d189e561d8a 100644 --- a/NEWS +++ b/NEWS @@ -49,6 +49,8 @@ PHP NEWS - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) . Fix SoapFault property destruction. (nielsdos) + . Fixed bug GH-15252 (SOAP XML broken since PHP 8.3.9 when using classmap + constructor option). (nielsdos) - Standard: . Fix passing non-finite timeout values in stream functions. (nielsdos) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 82b21d1588146..6568446249a31 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -449,8 +449,11 @@ static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xml zend_string *type_name; ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(SOAP_GLOBAL(class_map), type_name, tmp) { - if (ZSTR_LEN(ce->name) == Z_STRLEN_P(tmp) && - zend_binary_strncasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), Z_STRVAL_P(tmp), ZSTR_LEN(ce->name), ZSTR_LEN(ce->name)) == 0) { + ZVAL_DEREF(tmp); + if (Z_TYPE_P(tmp) == IS_STRING && + ZSTR_LEN(ce->name) == Z_STRLEN_P(tmp) && + zend_binary_strncasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), Z_STRVAL_P(tmp), ZSTR_LEN(ce->name), ZSTR_LEN(ce->name)) == 0 && + type_name) { /* TODO: namespace isn't stored */ encodePtr enc = NULL; @@ -1379,6 +1382,7 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z zend_class_entry *tmp; if ((classname = zend_hash_str_find_deref(SOAP_GLOBAL(class_map), type->type_str, strlen(type->type_str))) != NULL && + Z_TYPE_P(classname) == IS_STRING && (tmp = zend_fetch_class(Z_STR_P(classname), ZEND_FETCH_CLASS_AUTO)) != NULL) { ce = tmp; } @@ -3630,48 +3634,3 @@ void delete_encoder_persistent(zval *zv) assert(t->details.map == NULL); free(t); } - -/* Normalize leading backslash similarly to how the engine strips it away. */ -static inline zend_string *drop_leading_backslash(zend_string *str) { - if (ZSTR_VAL(str)[0] == '\\') { - return zend_string_init(ZSTR_VAL(str) + 1, ZSTR_LEN(str) - 1, false); - } else { - return zend_string_copy(str); - } -} - -static HashTable *create_normalized_classmap_copy(HashTable *class_map) -{ - HashTable *normalized = zend_new_array(zend_hash_num_elements(class_map)); - - zend_string *key; - zval *value; - ZEND_HASH_FOREACH_STR_KEY_VAL(class_map, key, value) { - ZVAL_DEREF(value); - - if (key != NULL && Z_TYPE_P(value) == IS_STRING) { - zval zv; - ZVAL_STR(&zv, drop_leading_backslash(Z_STR_P(value))); - zend_hash_add_new(normalized, key, &zv); - } - } ZEND_HASH_FOREACH_END(); - - return normalized; -} - -void create_normalized_classmap(zval *return_value, zval *class_map) -{ - /* Check if we need to make a copy. */ - zend_string *key; - zval *value; - ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARR_P(class_map), key, value) { - if (key == NULL || Z_TYPE_P(value) != IS_STRING || ZSTR_VAL(Z_STR_P(value))[0] == '\\') { - /* TODO: should probably throw in some of these cases to indicate programmer error, - * e.g. in the case where a non-string (after dereferencing) is provided. */ - RETURN_ARR(create_normalized_classmap_copy(Z_ARR_P(class_map))); - } - } ZEND_HASH_FOREACH_END(); - - /* We didn't have to make an actual copy, just increment the refcount. */ - RETURN_COPY(class_map); -} diff --git a/ext/soap/php_encoding.h b/ext/soap/php_encoding.h index 574ee4942a5ae..a4e16666e680f 100644 --- a/ext/soap/php_encoding.h +++ b/ext/soap/php_encoding.h @@ -214,8 +214,6 @@ encodePtr get_conversion(int encode); void delete_encoder(zval *zv); void delete_encoder_persistent(zval *zv); -void create_normalized_classmap(zval *return_value, zval *class_map); - extern const encode defaultEncoding[]; extern int numDefaultEncodings; diff --git a/ext/soap/php_soap.h b/ext/soap/php_soap.h index c30a5a45c3a9e..33a071ed41819 100644 --- a/ext/soap/php_soap.h +++ b/ext/soap/php_soap.h @@ -98,7 +98,7 @@ struct _soapService { char *actor; char *uri; xmlCharEncodingHandlerPtr encoding; - zval class_map; + HashTable *class_map; int features; struct _soapHeader **soap_headers_ptr; int send_errors; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 3320f6dd4807f..e98820c630eda 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -837,7 +837,7 @@ PHP_METHOD(SoapServer, __construct) if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL && Z_TYPE_P(tmp) == IS_ARRAY) { - create_normalized_classmap(&service->class_map, tmp); + service->class_map = zend_array_dup(Z_ARRVAL_P(tmp)); } if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL && @@ -1303,7 +1303,7 @@ PHP_METHOD(SoapServer, handle) old_encoding = SOAP_GLOBAL(encoding); SOAP_GLOBAL(encoding) = service->encoding; old_class_map = SOAP_GLOBAL(class_map); - SOAP_GLOBAL(class_map) = Z_ARR(service->class_map); + SOAP_GLOBAL(class_map) = service->class_map; old_typemap = SOAP_GLOBAL(typemap); SOAP_GLOBAL(typemap) = service->typemap; old_features = SOAP_GLOBAL(features); @@ -2003,7 +2003,7 @@ PHP_METHOD(SoapClient, __construct) } if ((tmp = zend_hash_str_find(ht, "classmap", sizeof("classmap")-1)) != NULL && Z_TYPE_P(tmp) == IS_ARRAY) { - create_normalized_classmap(Z_CLIENT_CLASSMAP_P(this_ptr), tmp); + ZVAL_COPY(Z_CLIENT_CLASSMAP_P(this_ptr), tmp); } if ((tmp = zend_hash_str_find(ht, "typemap", sizeof("typemap")-1)) != NULL && @@ -4405,7 +4405,10 @@ static void delete_service(void *data) /* {{{ */ if (service->encoding) { xmlCharEncCloseFunc(service->encoding); } - zval_ptr_dtor(&service->class_map); + if (service->class_map) { + zend_hash_destroy(service->class_map); + FREE_HASHTABLE(service->class_map); + } zval_ptr_dtor(&service->soap_object); efree(service); } diff --git a/ext/soap/tests/bug69280.phpt b/ext/soap/tests/bug69280.phpt deleted file mode 100644 index 8c4e6068591f9..0000000000000 --- a/ext/soap/tests/bug69280.phpt +++ /dev/null @@ -1,44 +0,0 @@ ---TEST-- -Bug #69280 (SoapClient classmap doesn't support fully qualified class name) ---EXTENSIONS-- -soap ---INI-- -soap.wsdl_cache_enabled=0 ---CREDITS-- -champetier dot etienne at gmail dot com ---FILE-- -__soapCall('TestMethod', [$parameters], [ - 'uri' => 'http://tempuri.org/', - 'soapaction' => '' - ] - ); - } - - public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string { - die($request); - } -} - -$a = new TestWS(__DIR__ . '/bug69280.wsdl', ['classmap' => [ - 'AbstractClass' => '\AbstractClass', - 'RealClass1' => '\RealClass1', -]]); -$r1 = new \RealClass1(); -$r1->prop = "prop"; -$r1->prop1 = "prop1"; -$a->TestMethod($r1); -?> ---EXPECT-- - -propprop1 diff --git a/ext/soap/tests/bug69280.wsdl b/ext/soap/tests/bug69280.wsdl deleted file mode 100644 index 8615ac77cdcf2..0000000000000 --- a/ext/soap/tests/bug69280.wsdl +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 423fc811bd8f513ff6c7263d0c521a8de91edb1f Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 6 Aug 2024 18:48:32 +0200 Subject: [PATCH 42/51] zend_enum: Rename try parameter to avoid conflict with C++ `try` is a keyword in C++, and as such C++ code including fails to compile unless a workaround is in place. To resolve this, we simply rename the parameter. We choose `try_from` to make it clear that this parameter is true when the function is called from `BackedEnum::tryFrom()`. For consistency, we also rename the `try` parameter of `zend_enum_from_base()`, although that function is not exported. This issue had been reported by @oplanre, who also provided an initial PR. Closes GH-15259. --- Zend/zend_enum.c | 10 +++++----- Zend/zend_enum.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Zend/zend_enum.c b/Zend/zend_enum.c index f807c8196548e..85d015b19b77b 100644 --- a/Zend/zend_enum.c +++ b/Zend/zend_enum.c @@ -279,7 +279,7 @@ static ZEND_NAMED_FUNCTION(zend_enum_cases_func) } ZEND_HASH_FOREACH_END(); } -ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try) +ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try_from) { if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) { if (zend_update_class_constants(ce) == FAILURE) { @@ -303,7 +303,7 @@ ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_clas if (case_name_zv == NULL) { not_found: - if (try) { + if (try_from) { *result = NULL; return SUCCESS; } @@ -333,7 +333,7 @@ ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_clas return SUCCESS; } -static void zend_enum_from_base(INTERNAL_FUNCTION_PARAMETERS, bool try) +static void zend_enum_from_base(INTERNAL_FUNCTION_PARAMETERS, bool try_from) { zend_class_entry *ce = execute_data->func->common.scope; bool release_string = false; @@ -368,12 +368,12 @@ static void zend_enum_from_base(INTERNAL_FUNCTION_PARAMETERS, bool try) } zend_object *case_obj; - if (zend_enum_get_case_by_value(&case_obj, ce, long_key, string_key, try) == FAILURE) { + if (zend_enum_get_case_by_value(&case_obj, ce, long_key, string_key, try_from) == FAILURE) { goto throw; } if (case_obj == NULL) { - ZEND_ASSERT(try); + ZEND_ASSERT(try_from); goto return_null; } diff --git a/Zend/zend_enum.h b/Zend/zend_enum.h index 797eb0c8ab5b6..86efcf32170e2 100644 --- a/Zend/zend_enum.h +++ b/Zend/zend_enum.h @@ -41,7 +41,7 @@ ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, z ZEND_API void zend_enum_add_case_cstr(zend_class_entry *ce, const char *name, zval *value); ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name); ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char *name); -ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try); +ZEND_API zend_result zend_enum_get_case_by_value(zend_object **result, zend_class_entry *ce, zend_long long_key, zend_string *string_key, bool try_from); static zend_always_inline zval *zend_enum_fetch_case_name(zend_object *zobj) { From 9bfe36508da7aae80f4404c1a41c10d8ca9765f5 Mon Sep 17 00:00:00 2001 From: disservin Date: Thu, 8 Aug 2024 09:57:31 +0200 Subject: [PATCH 43/51] Update ci actions/checkout to v4 (#15283) see 45e60e585eed63353301f797c75da4e553ce21ff see 69dbfadd1eebc2e99f349b6fd617cda1d5cad448 --- .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 34a592c3b0468..8027bcdc85547 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -115,7 +115,7 @@ jobs: MYSQL_ROOT_PASSWORD: root steps: - name: git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: apt uses: ./.github/actions/apt-x32 - name: ccache From a6c547d1dd242a850328368712ee716c1a9ae93f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:06:58 +0200 Subject: [PATCH 44/51] Fix GH-15268: heap buffer overflow in phpdbg (zend_hash_num_elements() Zend/zend_hash.h) The class is not yet linked, so we cannot access `parent`, but only `parent_name`. Closes GH-15277. --- NEWS | 2 ++ sapi/phpdbg/phpdbg_info.c | 15 +++++++++------ sapi/phpdbg/tests/gh15268.phpt | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 sapi/phpdbg/tests/gh15268.phpt diff --git a/NEWS b/NEWS index c4d189e561d8a..0ce27b5776b4b 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,8 @@ PHP NEWS - PHPDBG: . Fixed bug GH-13199 (EOF emits redundant prompt in phpdbg local console mode with libedit/readline). (Peter Kokot) + . Fixed bug GH-15268 (heap buffer overflow in phpdbg + (zend_hash_num_elements() Zend/zend_hash.h)). (nielsdos) - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/sapi/phpdbg/phpdbg_info.c b/sapi/phpdbg/phpdbg_info.c index 0a1e7570a493c..b6c48d548f1f0 100644 --- a/sapi/phpdbg/phpdbg_info.c +++ b/sapi/phpdbg/phpdbg_info.c @@ -403,12 +403,15 @@ PHPDBG_INFO(classes) /* {{{ */ phpdbg_print_class_name(ce); if (ce->parent) { - zend_class_entry *pce; - pce = ce->parent; - do { - phpdbg_out("|-------- "); - phpdbg_print_class_name(pce); - } while ((pce = pce->parent)); + if (ce->ce_flags & ZEND_ACC_LINKED) { + zend_class_entry *pce = ce->parent; + do { + phpdbg_out("|-------- "); + phpdbg_print_class_name(pce); + } while ((pce = pce->parent)); + } else { + phpdbg_writeln("|-------- User Class %s (not yet linked because declaration for parent was not encountered when declaring the class)", ZSTR_VAL(ce->parent_name)); + } } if (ce->info.user.filename) { diff --git a/sapi/phpdbg/tests/gh15268.phpt b/sapi/phpdbg/tests/gh15268.phpt new file mode 100644 index 0000000000000..1afd29fb34668 --- /dev/null +++ b/sapi/phpdbg/tests/gh15268.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-15268 (heap buffer overflow in phpdbg (zend_hash_num_elements() Zend/zend_hash.h)) +--SKIPIF-- + +--FILE-- + +--PHPDBG-- +i classes +q +--EXPECTF-- +[Successful compilation of %s] +prompt> [User Classes (2)] +User Class B (0) +|-------- User Class A (not yet linked because declaration for parent was not encountered when declaring the class) +|---- in %s on line %d +User Class A (0) +|---- in %s on line %d +prompt> From 9aeb6761b5fcf75dcef6fdbb76fde604beeca6c5 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 4 Aug 2024 17:23:16 +0100 Subject: [PATCH 45/51] Fix GH-15210: phpdbg_print_changed_zvals working on a real copy instead. Close GH-15229 --- NEWS | 1 + sapi/phpdbg/phpdbg.h | 1 + sapi/phpdbg/phpdbg_prompt.c | 2 ++ sapi/phpdbg/phpdbg_watch.c | 9 +++++--- sapi/phpdbg/tests/gh15210_001.phpt | 30 +++++++++++++++++++++++++ sapi/phpdbg/tests/gh15210_002.phpt | 36 ++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 sapi/phpdbg/tests/gh15210_001.phpt create mode 100644 sapi/phpdbg/tests/gh15210_002.phpt diff --git a/NEWS b/NEWS index 0ce27b5776b4b..7de98d7bfb621 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,7 @@ PHP NEWS with libedit/readline). (Peter Kokot) . Fixed bug GH-15268 (heap buffer overflow in phpdbg (zend_hash_num_elements() Zend/zend_hash.h)). (nielsdos) + . Fixed bug GH-15210 use-after-free on watchpoint allocations. (nielsdos) - Soap: . Fixed bug #55639 (Digest autentication dont work). (nielsdos) diff --git a/sapi/phpdbg/phpdbg.h b/sapi/phpdbg/phpdbg.h index 76630dc53c7d4..88578168c6ea7 100644 --- a/sapi/phpdbg/phpdbg.h +++ b/sapi/phpdbg/phpdbg.h @@ -254,6 +254,7 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) HashTable watch_recreation; /* watch elements pending recreation of their respective watchpoints */ HashTable watch_free; /* pointers to watch for being freed */ HashTable *watchlist_mem; /* triggered watchpoints */ + HashTable *original_watchlist_mem; /* the original allocation for watchlist_mem, used when watchlist_mem has changed temporarily */ HashTable *watchlist_mem_backup; /* triggered watchpoints backup table while iterating over it */ bool watchpoint_hit; /* a watchpoint was hit */ void (*original_free_function)(void *); /* the original AG(mm_heap)->_free function */ diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c index 994ac829b0a5e..887064cf2e70b 100644 --- a/sapi/phpdbg/phpdbg_prompt.c +++ b/sapi/phpdbg/phpdbg_prompt.c @@ -1551,6 +1551,8 @@ int phpdbg_interactive(bool allow_async_unsafe, char *input) /* {{{ */ ret = phpdbg_stack_execute(&stack, allow_async_unsafe); } zend_catch { phpdbg_stack_free(&stack); + phpdbg_destroy_input(&input); + /* TODO: should use proper unwinding instead of bailing out */ zend_bailout(); } zend_end_try(); diff --git a/sapi/phpdbg/phpdbg_watch.c b/sapi/phpdbg/phpdbg_watch.c index fef29a8293830..54db3edbc9c43 100644 --- a/sapi/phpdbg/phpdbg_watch.c +++ b/sapi/phpdbg/phpdbg_watch.c @@ -516,7 +516,9 @@ phpdbg_watch_element *phpdbg_add_watch_element(phpdbg_watchpoint_t *watch, phpdb phpdbg_watch_element *old_element; watch = res->ptr; if ((old_element = zend_hash_find_ptr(&watch->elements, element->str))) { - phpdbg_free_watch_element(element); + if (element != old_element) { + phpdbg_free_watch_element(element); + } return old_element; } } @@ -1471,6 +1473,7 @@ void phpdbg_setup_watchpoints(void) { /* put these on a separate page, to avoid conflicts with other memory */ PHPDBG_G(watchlist_mem) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable)); + PHPDBG_G(original_watchlist_mem) = PHPDBG_G(watchlist_mem); zend_hash_init(PHPDBG_G(watchlist_mem), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1); PHPDBG_G(watchlist_mem_backup) = malloc(phpdbg_pagesize > sizeof(HashTable) ? phpdbg_pagesize : sizeof(HashTable)); zend_hash_init(PHPDBG_G(watchlist_mem_backup), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1); @@ -1517,8 +1520,8 @@ void phpdbg_destroy_watchpoints(void) { zend_hash_destroy(&PHPDBG_G(watch_recreation)); zend_hash_destroy(&PHPDBG_G(watch_free)); zend_hash_destroy(&PHPDBG_G(watch_collisions)); - zend_hash_destroy(PHPDBG_G(watchlist_mem)); - free(PHPDBG_G(watchlist_mem)); + zend_hash_destroy(PHPDBG_G(original_watchlist_mem)); + free(PHPDBG_G(original_watchlist_mem)); zend_hash_destroy(PHPDBG_G(watchlist_mem_backup)); free(PHPDBG_G(watchlist_mem_backup)); } diff --git a/sapi/phpdbg/tests/gh15210_001.phpt b/sapi/phpdbg/tests/gh15210_001.phpt new file mode 100644 index 0000000000000..c7b4756f75203 --- /dev/null +++ b/sapi/phpdbg/tests/gh15210_001.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-15210 use after free after continue +--PHPDBG-- +b 4 +r +w $a[0] +c +q +--FILE-- + +--EXPECTF-- +[Successful compilation of %s] +prompt> [Breakpoint #0 added at %s:%d] +prompt> [Breakpoint #0 at %s:%d, hits: 1] +>00004: $a[0] = 1; + 00005: ?> + 00006: +prompt> [Added watchpoint #0 for $a[0]] +prompt> [Breaking on watchpoint $a[0]] +Old value: [Breaking on watchpoint $a[0]] +Old value: 0 +New value: 1 +>00002: header_register_callback(function() { echo "sent";}); + 00003: $a = [0]; + 00004: $a[0] = 1; +prompt> [$a[0] has been removed, removing watchpoint] diff --git a/sapi/phpdbg/tests/gh15210_002.phpt b/sapi/phpdbg/tests/gh15210_002.phpt new file mode 100644 index 0000000000000..0ba320eb5e15c --- /dev/null +++ b/sapi/phpdbg/tests/gh15210_002.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-15210 use after free after continue +--PHPDBG-- +b 4 +r +w $a[0] +c +c +q +--FILE-- + +--EXPECTF-- +[Successful compilation of %s] +prompt> [Breakpoint #0 added at %s:%d] +prompt> [Breakpoint #0 at %s:%d, hits: 1] +>00004: $a[0] = 1; + 00005: ?> + 00006: +prompt> [Added watchpoint #0 for $a[0]] +prompt> [Breaking on watchpoint $a[0]] +Old value: [Breaking on watchpoint $a[0]] +Old value: 0 +New value: 1 +>00002: header_register_callback(function() { echo "sent";}); + 00003: $a = [0]; + 00004: $a[0] = 1; +prompt> sent0 +New value: 1 + +[$a[0] has been removed, removing watchpoint] +[Script ended normally] +prompt> From 2e26559fcd8109dd75e68a240a3007ce5c831d3a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:05:10 +0200 Subject: [PATCH 46/51] Fix uninitialized value watchpoint_hit Closes GH-15317. --- sapi/phpdbg/phpdbg_watch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sapi/phpdbg/phpdbg_watch.c b/sapi/phpdbg/phpdbg_watch.c index 54db3edbc9c43..f0a9bf5d4fcb5 100644 --- a/sapi/phpdbg/phpdbg_watch.c +++ b/sapi/phpdbg/phpdbg_watch.c @@ -1479,6 +1479,7 @@ void phpdbg_setup_watchpoints(void) { zend_hash_init(PHPDBG_G(watchlist_mem_backup), phpdbg_pagesize / (sizeof(Bucket) + sizeof(uint32_t)), NULL, NULL, 1); PHPDBG_G(watch_tmp) = NULL; + PHPDBG_G(watchpoint_hit) = false; #ifdef HAVE_USERFAULTFD_WRITEFAULT PHPDBG_G(watch_userfaultfd) = syscall(SYS_userfaultfd, O_CLOEXEC); From 4d71580e005e8711c55130d3080960e81a150922 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 10 Aug 2024 01:10:01 +0200 Subject: [PATCH 47/51] Add necessary SKIPIFs to new phpdbg tests Similarly to other watchpoint tests, we add SKIPIFs. These TRACKED_ALLOC issues should be investigated though [1] [2]. [1] https://github.com/php/php-src/commit/de5c760c698e98b82a1a168b693e4e07bc3a4134#comments [2] https://github.com/php/php-src/pull/15229#pullrequestreview-2230563480 --- sapi/phpdbg/tests/gh15210_001.phpt | 6 ++++++ sapi/phpdbg/tests/gh15210_002.phpt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/sapi/phpdbg/tests/gh15210_001.phpt b/sapi/phpdbg/tests/gh15210_001.phpt index c7b4756f75203..119ed6e460eed 100644 --- a/sapi/phpdbg/tests/gh15210_001.phpt +++ b/sapi/phpdbg/tests/gh15210_001.phpt @@ -1,5 +1,11 @@ --TEST-- GH-15210 use after free after continue +--SKIPIF-- + --PHPDBG-- b 4 r diff --git a/sapi/phpdbg/tests/gh15210_002.phpt b/sapi/phpdbg/tests/gh15210_002.phpt index 0ba320eb5e15c..7848500a9e949 100644 --- a/sapi/phpdbg/tests/gh15210_002.phpt +++ b/sapi/phpdbg/tests/gh15210_002.phpt @@ -1,5 +1,11 @@ --TEST-- GH-15210 use after free after continue +--SKIPIF-- + --PHPDBG-- b 4 r From c767fec2d068cebb114fafaf58c83dc70f1dcac7 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 10 Aug 2024 15:46:31 +0200 Subject: [PATCH 48/51] Fix crash during GC of suspended generator delegate (#15275) --- Zend/tests/gh15275-001.phpt | 38 +++++++++++++++++++++++++ Zend/tests/gh15275-002.phpt | 57 +++++++++++++++++++++++++++++++++++++ Zend/tests/gh15275-003.phpt | 51 +++++++++++++++++++++++++++++++++ Zend/tests/gh15275-004.phpt | 44 ++++++++++++++++++++++++++++ Zend/tests/gh15275-005.phpt | 51 +++++++++++++++++++++++++++++++++ Zend/tests/gh15275-006.phpt | 51 +++++++++++++++++++++++++++++++++ Zend/zend_execute.c | 8 +++++- Zend/zend_generators.c | 19 +++++++++---- 8 files changed, 313 insertions(+), 6 deletions(-) create mode 100644 Zend/tests/gh15275-001.phpt create mode 100644 Zend/tests/gh15275-002.phpt create mode 100644 Zend/tests/gh15275-003.phpt create mode 100644 Zend/tests/gh15275-004.phpt create mode 100644 Zend/tests/gh15275-005.phpt create mode 100644 Zend/tests/gh15275-006.phpt diff --git a/Zend/tests/gh15275-001.phpt b/Zend/tests/gh15275-001.phpt new file mode 100644 index 0000000000000..bfea734c6ba9b --- /dev/null +++ b/Zend/tests/gh15275-001.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-15275 001: Crash during GC of suspended generator delegate +--FILE-- +current()); + $iterable->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +gc_collect_cycles(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +==DONE== diff --git a/Zend/tests/gh15275-002.phpt b/Zend/tests/gh15275-002.phpt new file mode 100644 index 0000000000000..7b1f88c9f2b26 --- /dev/null +++ b/Zend/tests/gh15275-002.phpt @@ -0,0 +1,57 @@ +--TEST-- +GH-15275 002: Crash during GC of suspended generator delegate +--FILE-- +current()); + $gen->next(); + var_dump("not executed"); +}); + +$ref = $fiber; + +$fiber->start(); + +gc_collect_cycles(); + +?> +==DONE== +--EXPECT-- +string(3) "foo" +==DONE== +string(15) "It::getIterator" +string(1) "f" +string(1) "g" diff --git a/Zend/tests/gh15275-003.phpt b/Zend/tests/gh15275-003.phpt new file mode 100644 index 0000000000000..d62187e5342b7 --- /dev/null +++ b/Zend/tests/gh15275-003.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-15275 003: Crash during GC of suspended generator delegate +--FILE-- +current()); +$gen->next(); + +?> +==DONE== +--EXPECTF-- +string(3) "foo" +string(1) "f" +string(1) "g" + +Fatal error: Uncaught Exception in %s:8 +Stack trace: +#0 %s(15): It->getIterator() +#1 %s(23): f() +#2 [internal function]: g() +#3 %s(32): Generator->next() +#4 {main} + thrown in %s on line 8 diff --git a/Zend/tests/gh15275-004.phpt b/Zend/tests/gh15275-004.phpt new file mode 100644 index 0000000000000..61939ad2a4557 --- /dev/null +++ b/Zend/tests/gh15275-004.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-15275 004: Crash during GC of suspended generator delegate +--FILE-- +current()); +$gen->next(); + +gc_collect_cycles(); + +?> +==DONE== +--EXPECTF-- +string(3) "foo" +baz + +Fatal error: Uncaught Exception in %s:9 +Stack trace: +#0 %s(19): It->getIterator() +#1 [internal function]: f() +#2 %s(25): Generator->next() +#3 {main} + thrown in %s on line 9 diff --git a/Zend/tests/gh15275-005.phpt b/Zend/tests/gh15275-005.phpt new file mode 100644 index 0000000000000..07a6f48e7a17e --- /dev/null +++ b/Zend/tests/gh15275-005.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-15275 005: Crash during GC of suspended generator delegate +--FILE-- +current()); +$gen->next(); + +?> +==DONE== +--EXPECTF-- +string(3) "foo" +string(1) "f" +string(1) "g" + +Fatal error: Uncaught Exception in %s:8 +Stack trace: +#0 %s(15): It->getIterator() +#1 %s(23): f() +#2 [internal function]: g() +#3 %s(32): Generator->next() +#4 {main} + thrown in %s on line 8 diff --git a/Zend/tests/gh15275-006.phpt b/Zend/tests/gh15275-006.phpt new file mode 100644 index 0000000000000..7f585acf0f40b --- /dev/null +++ b/Zend/tests/gh15275-006.phpt @@ -0,0 +1,51 @@ +--TEST-- +GH-15275 006: Crash during GC of suspended generator delegate +--FILE-- +current()); +$gen->next(); + +gc_collect_cycles(); + +?> +==DONE== +--EXPECTF-- +string(3) "foo" +baz + +Fatal error: Uncaught Exception in %s:9 +Stack trace: +#0 %s(19): It->getIterator() +#1 [internal function]: f() +#2 %s(25): Generator->next() +#3 {main} + +Next Exception in %s:14 +Stack trace: +#0 %s(19): It->__destruct() +#1 [internal function]: f() +#2 %s(25): Generator->next() +#3 {main} + thrown in %s on line 14 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3de48fb1358c5..716756ad93ba2 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -4471,7 +4471,13 @@ ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_d } if (call) { - uint32_t op_num = execute_data->opline - op_array->opcodes; + uint32_t op_num; + if (UNEXPECTED(execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION)) { + op_num = EG(opline_before_exception) - op_array->opcodes; + } else { + op_num = execute_data->opline - op_array->opcodes; + } + ZEND_ASSERT(op_num < op_array->last); if (suspended_by_yield) { /* When the execution was suspended by yield, EX(opline) points to * next opline to execute. Otherwise, it points to the opline that diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index f7475ad6fbb77..85127025679d6 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -26,6 +26,7 @@ #include "zend_closures.h" #include "zend_generators_arginfo.h" #include "zend_observer.h" +#include "zend_vm_opcodes.h" ZEND_API zend_class_entry *zend_ce_generator; ZEND_API zend_class_entry *zend_ce_ClosedGeneratorException; @@ -512,6 +513,8 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce * to pretend the exception happened during the YIELD opcode. */ EG(current_execute_data) = generator->execute_data; generator->execute_data->opline--; + ZEND_ASSERT(generator->execute_data->opline->opcode == ZEND_YIELD + || generator->execute_data->opline->opcode == ZEND_YIELD_FROM); generator->execute_data->prev_execute_data = original_execute_data; if (exception) { @@ -520,13 +523,14 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce zend_rethrow_exception(EG(current_execute_data)); } + generator->execute_data->opline++; + /* if we don't stop an array/iterator yield from, the exception will only reach the generator after the values were all iterated over */ if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) { zval_ptr_dtor(&generator->values); ZVAL_UNDEF(&generator->values); } - generator->execute_data->opline++; EG(current_execute_data) = original_execute_data; } @@ -656,8 +660,6 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator static zend_result zend_generator_get_next_delegated_value(zend_generator *generator) /* {{{ */ { - --generator->execute_data->opline; - zval *value; if (Z_TYPE(generator->values) == IS_ARRAY) { HashTable *ht = Z_ARR(generator->values); @@ -739,14 +741,12 @@ static zend_result zend_generator_get_next_delegated_value(zend_generator *gener } } - ++generator->execute_data->opline; return SUCCESS; failure: zval_ptr_dtor(&generator->values); ZVAL_UNDEF(&generator->values); - ++generator->execute_data->opline; return FAILURE; } /* }}} */ @@ -811,6 +811,15 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */ generator->flags &= ~ZEND_GENERATOR_IN_FIBER; return; } + if (UNEXPECTED(EG(exception))) { + /* Decrementing opline_before_exception to pretend the exception + * happened during the YIELD_FROM opcode. */ + if (generator->execute_data) { + ZEND_ASSERT(generator->execute_data->opline == EG(exception_op)); + ZEND_ASSERT((EG(opline_before_exception)-1)->opcode == ZEND_YIELD_FROM); + EG(opline_before_exception)--; + } + } /* If there are no more delegated values, resume the generator * after the "yield from" expression. */ } From 39bacafeed6e1d7021eb910300f74cc72ac1f1d8 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Sat, 10 Aug 2024 15:48:30 +0200 Subject: [PATCH 49/51] [ci skip] NEWS for GH-15275 --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 7de98d7bfb621..8d3550cfb80a7 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ PHP NEWS . Fix uninitialized memory in network.c. (nielsdos) . Fixed bug GH-15108 (Segfault when destroying generator during shutdown). (Arnaud) + . Fixed bug GH-15275 (Crash during GC of suspended generator delegate). + (Arnaud) - Curl: . Fixed case when curl_error returns an empty string. From 9be52dcd62e77b6ae8c74720f315ff0b5fbf3fa8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 12 Aug 2024 15:57:34 +0200 Subject: [PATCH 50/51] Fix git check in verify generated files (GH-15363) Git 2.46.0 accidentally broke git diff --exit-code for files flagged with -diff. Add the -a flag to restore the previous behavior. This issue is already fixed in gits next branch. --- .github/actions/verify-generated-files/action.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/verify-generated-files/action.yml b/.github/actions/verify-generated-files/action.yml index 139dd84662411..266f4d33c93b1 100644 --- a/.github/actions/verify-generated-files/action.yml +++ b/.github/actions/verify-generated-files/action.yml @@ -12,4 +12,5 @@ runs: ext/tokenizer/tokenizer_data_gen.php build/gen_stub.php -f build/gen_stub.php --generate-optimizer-info - git add . -N && git diff --exit-code + # Use the -a flag for a bug in git 2.46.0, which doesn't consider changed -diff files. + git add . -N && git diff -a --exit-code From b56653c44ddd929f7c59e080f4e7b78c6cfd60f3 Mon Sep 17 00:00:00 2001 From: Sergey Panteleev Date: Tue, 27 Aug 2024 18:32:20 +0300 Subject: [PATCH 51/51] Update versions for PHP 8.2.23 --- 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 8d3550cfb80a7..2df0f27a93017 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.2.23 +29 Aug 2024, PHP 8.2.23 - Core: . Fixed bug GH-15020 (Memory leak in Zend/Optimizer/escape_analysis.c). diff --git a/Zend/zend.h b/Zend/zend.h index c9018454dfc60..dfd34e2886648 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.2.23-dev" +#define ZEND_VERSION "4.2.23" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 8e8682095520a..50992e95f7fc8 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.23-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.2.23],[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 5d1d455b26508..36fa814789d65 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 2 #define PHP_RELEASE_VERSION 23 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.2.23-dev" +#define PHP_EXTRA_VERSION "" +#define PHP_VERSION "8.2.23" #define PHP_VERSION_ID 80223