From a757f276f95e20c1bd0e5102e6af9cddcdaf0149 Mon Sep 17 00:00:00 2001 From: George Wang Date: Sat, 6 Sep 2025 12:38:13 -0400 Subject: [PATCH 01/64] fix pipe detection for STDERR. --- sapi/litespeed/lsapilib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c index 09cd2e6bf9a7..2ab314d7d73f 100644 --- a/sapi/litespeed/lsapilib.c +++ b/sapi/litespeed/lsapilib.c @@ -634,8 +634,8 @@ static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; - if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& - ( errno == ENOTCONN )) + if ((getpeername(fd, (struct sockaddr *)achPeer, &len) != 0 ) + && (errno == ENOTCONN || errno == ENOTSOCK)) return 0; else return 1; From 828080146b648c7474ab6a6f585739aa3ac7ef8c Mon Sep 17 00:00:00 2001 From: George Wang Date: Sat, 6 Sep 2025 12:38:13 -0400 Subject: [PATCH 02/64] fix pipe detection for STDERR. --- sapi/litespeed/lsapilib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c index fc2882d898d3..6b63053cced6 100644 --- a/sapi/litespeed/lsapilib.c +++ b/sapi/litespeed/lsapilib.c @@ -634,8 +634,8 @@ static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; - if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& - ( errno == ENOTCONN )) + if ((getpeername(fd, (struct sockaddr *)achPeer, &len) != 0 ) + && (errno == ENOTCONN || errno == ENOTSOCK)) return 0; else return 1; From 215ebbb8d5c44ae86dc1c21097cee77dc9491320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Tue, 9 Sep 2025 19:33:45 +0200 Subject: [PATCH 03/64] zend_API: Do not overwrite `readonly` properties in `object_properties_load()` (#19767) Fixes php/php-src#19765. --- NEWS | 2 ++ Zend/zend_API.c | 8 +++++++ .../03_randomizer/gh_19765_unserialize.phpt | 21 +++++++++++++++++++ .../03_randomizer/gh_9186_unserialize.phpt | 2 +- 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 ext/random/tests/03_randomizer/gh_19765_unserialize.phpt diff --git a/NEWS b/NEWS index b006f93e0c32..b11f00ad7d16 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,8 @@ PHP NEWS . Fixed bug GH-19681 (PHP_EXPAND_PATH broken with bash 5.3.0). (Remi) . Fixed bug GH-19720 (Assertion failure when error handler throws when accessing a deprecated constant). (nielsdos) + . Fixed bug GH-19765 (object_properties_load() bypasses readonly property + checks). (timwolla) - CLI: . Fixed bug GH-19461 (Improve error message on listening error with IPv6 diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 79800a61a047..ed6b24bc5521 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1701,6 +1701,14 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) property_info && (property_info->flags & ZEND_ACC_STATIC) == 0) { zval *slot = OBJ_PROP(object, property_info->offset); + if (UNEXPECTED((property_info->flags & ZEND_ACC_READONLY) && !Z_ISUNDEF_P(slot))) { + if (Z_PROP_FLAG_P(slot) & IS_PROP_REINITABLE) { + Z_PROP_FLAG_P(slot) &= ~IS_PROP_REINITABLE; + } else { + zend_readonly_property_modification_error(property_info); + return; + } + } zval_ptr_dtor(slot); ZVAL_COPY_VALUE(slot, prop); zval_add_ref(slot); diff --git a/ext/random/tests/03_randomizer/gh_19765_unserialize.phpt b/ext/random/tests/03_randomizer/gh_19765_unserialize.phpt new file mode 100644 index 000000000000..24abfca293fc --- /dev/null +++ b/ext/random/tests/03_randomizer/gh_19765_unserialize.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-19765: object_properties_load() bypasses readonly property checks +--FILE-- +__unserialize([['engine' => new PcgOneseq128XslRr64()]]); +} catch (Exception $error) { + echo $error->getMessage() . "\n"; +} +var_dump($r->engine::class); + +?> +--EXPECT-- +Invalid serialization data for Random\Randomizer object +string(21) "Random\Engine\Mt19937" diff --git a/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt b/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt index fe1acb2f74be..edadb7380bd1 100644 --- a/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt +++ b/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt @@ -1,5 +1,5 @@ --TEST-- -Fix GH-9186 @strict-properties can be bypassed using unserialization +GH-9186: @strict-properties can be bypassed using unserialization --FILE-- Date: Tue, 9 Sep 2025 21:57:54 +0200 Subject: [PATCH 04/64] Revert "fix pipe detection for STDERR." This reverts commit a757f276f95e20c1bd0e5102e6af9cddcdaf0149. --- sapi/litespeed/lsapilib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c index 2ab314d7d73f..09cd2e6bf9a7 100644 --- a/sapi/litespeed/lsapilib.c +++ b/sapi/litespeed/lsapilib.c @@ -634,8 +634,8 @@ static inline int isPipe( int fd ) { char achPeer[128]; socklen_t len = 128; - if ((getpeername(fd, (struct sockaddr *)achPeer, &len) != 0 ) - && (errno == ENOTCONN || errno == ENOTSOCK)) + if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&& + ( errno == ENOTCONN )) return 0; else return 1; From c9cc68b9edaac690b2c337dccd8ee865118296cd Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 9 Sep 2025 23:02:24 +0200 Subject: [PATCH 05/64] PHP-8.3 is now for PHP-8.3.27-dev --- NEWS | 10 +++++++--- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index b11f00ad7d16..b035fa999995 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.26 +?? ??? ????, PHP 8.3.27 + +- Core: + . Fixed bug GH-19765 (object_properties_load() bypasses readonly property + checks). (timwolla) + +25 Sep 2025, PHP 8.3.26 - Core: . Fixed bug GH-18850 (Repeated inclusion of file with __halt_compiler() @@ -14,8 +20,6 @@ PHP NEWS . Fixed bug GH-19681 (PHP_EXPAND_PATH broken with bash 5.3.0). (Remi) . Fixed bug GH-19720 (Assertion failure when error handler throws when accessing a deprecated constant). (nielsdos) - . Fixed bug GH-19765 (object_properties_load() bypasses readonly property - checks). (timwolla) - CLI: . Fixed bug GH-19461 (Improve error message on listening error with IPv6 diff --git a/Zend/zend.h b/Zend/zend.h index 23df63cde2d4..f0925298413f 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.26-dev" +#define ZEND_VERSION "4.3.27-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 0c9bf96e64b9..1e39e16644b1 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.26-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.27-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 866ca3a80a07..bf1b95c63193 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 -#define PHP_RELEASE_VERSION 26 +#define PHP_RELEASE_VERSION 27 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.26-dev" -#define PHP_VERSION_ID 80326 +#define PHP_VERSION "8.3.27-dev" +#define PHP_VERSION_ID 80327 From f6f17484abb592b20297ef26e18807da85af7d4d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 23 Sep 2023 20:53:07 +0200 Subject: [PATCH 06/64] Fix GH-12265: Cloning an object breaks serialization recursion Closes GH-12287. --- NEWS | 4 ++ ext/standard/tests/serialize/gh12265.phpt | 47 +++++++++++++++++++++ ext/standard/tests/serialize/gh12265b.phpt | 48 ++++++++++++++++++++++ ext/standard/var.c | 5 ++- 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/serialize/gh12265.phpt create mode 100644 ext/standard/tests/serialize/gh12265b.phpt diff --git a/NEWS b/NEWS index b035fa999995..b50dd0802a7d 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Fixed bug GH-19765 (object_properties_load() bypasses readonly property checks). (timwolla) +- Standard: + . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). + (nielsdos) + 25 Sep 2025, PHP 8.3.26 - Core: diff --git a/ext/standard/tests/serialize/gh12265.phpt b/ext/standard/tests/serialize/gh12265.phpt new file mode 100644 index 000000000000..5f49a62fee29 --- /dev/null +++ b/ext/standard/tests/serialize/gh12265.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-12265 (Cloning an object breaks serialization recursion) - __serialize variation +--FILE-- + new A($this)]; + } +} + +class C { + public B $b; + + public function __construct() { + $this->b = new B; + } +} + +$b = new B(); +$sb = serialize($b); +$stb = serialize(new B); + +printf("serialized original: %s\n", $sb); +printf("serialized temp : %s\n", $stb); + +$c = new C; +$sc = serialize($c); +$stc = serialize(new C); + +printf("serialized original: %s\n", $sc); +printf("serialized temp : %s\n", $stc); + +?> +--EXPECT-- +serialized original: O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized temp : O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized original: O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} +serialized temp : O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} diff --git a/ext/standard/tests/serialize/gh12265b.phpt b/ext/standard/tests/serialize/gh12265b.phpt new file mode 100644 index 000000000000..2b9d80a848ce --- /dev/null +++ b/ext/standard/tests/serialize/gh12265b.phpt @@ -0,0 +1,48 @@ +--TEST-- +GH-12265 (Cloning an object breaks serialization recursion) - __sleep variation +--FILE-- +a = new A($this); + return ['a']; + } +} + +class C { + public B $b; + + public function __construct() { + $this->b = new B; + } +} + +$b = new B(); +$sb = serialize($b); +$stb = serialize(new B); + +printf("serialized original: %s\n", $sb); +printf("serialized temp : %s\n", $stb); + +$c = new C; +$sc = serialize($c); +$stc = serialize(new C); + +printf("serialized original: %s\n", $sc); +printf("serialized temp : %s\n", $stc); + +?> +--EXPECT-- +serialized original: O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized temp : O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized original: O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} +serialized temp : O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} diff --git a/ext/standard/var.c b/ext/standard/var.c index 3d53ebf5137a..b7dc6dff1d88 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -681,7 +681,10 @@ static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var, b return 0; } else if (!in_rcn_array && Z_REFCOUNT_P(var) == 1 - && (Z_OBJ_P(var)->properties == NULL || GC_REFCOUNT(Z_OBJ_P(var)->properties) == 1)) { + && (Z_OBJ_P(var)->properties == NULL || GC_REFCOUNT(Z_OBJ_P(var)->properties) == 1) + /* __serialize and __sleep may arbitrarily increase the refcount */ + && Z_OBJCE_P(var)->__serialize == NULL + && zend_hash_find_known_hash(&Z_OBJCE_P(var)->function_table, ZSTR_KNOWN(ZEND_STR_SLEEP)) == NULL) { return 0; } From 901f71e6e3a9c97928a8c32ab7e70bd52e93819c Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 3 Sep 2025 22:45:24 +0200 Subject: [PATCH 07/64] Fix GH-19688: Remove pattern overflow in zip addGlob() memcmp() can overread the filename if the filename is shorter than the pattern. Closes GH-19689. --- NEWS | 3 +++ ext/zip/php_zip.c | 2 +- ext/zip/tests/gh19688.phpt | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 ext/zip/tests/gh19688.phpt diff --git a/NEWS b/NEWS index b50dd0802a7d..8ed895987f9c 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,9 @@ PHP NEWS . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). (nielsdos) +- Zip: + . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos) + 25 Sep 2025, PHP 8.3.26 - Core: diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 9f1d296336e0..3613fb0f7ca7 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1784,7 +1784,7 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* basename = php_basename(Z_STRVAL_P(zval_file), Z_STRLEN_P(zval_file), NULL, 0); file_stripped = ZSTR_VAL(basename); file_stripped_len = ZSTR_LEN(basename); - } else if (opts.remove_path && !memcmp(Z_STRVAL_P(zval_file), opts.remove_path, opts.remove_path_len)) { + } else if (opts.remove_path && Z_STRLEN_P(zval_file) > opts.remove_path_len && !memcmp(Z_STRVAL_P(zval_file), opts.remove_path, opts.remove_path_len)) { if (IS_SLASH(Z_STRVAL_P(zval_file)[opts.remove_path_len])) { file_stripped = Z_STRVAL_P(zval_file) + opts.remove_path_len + 1; file_stripped_len = Z_STRLEN_P(zval_file) - opts.remove_path_len - 1; diff --git a/ext/zip/tests/gh19688.phpt b/ext/zip/tests/gh19688.phpt new file mode 100644 index 000000000000..7e2a2800b255 --- /dev/null +++ b/ext/zip/tests/gh19688.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-19688 (Remove pattern overflow in zip addGlob()) +--EXTENSIONS-- +zip +--FILE-- +open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE); +$options = array('remove_path' => $dir . 'a very long string here that will overrun'); +$zip->addGlob($testfile, 0, $options); +var_dump($zip->getNameIndex(0)); +?> +--CLEAN-- + +--EXPECTF-- +string(%d) "%s001.phpt" From ed9430a5d1c1023bf25769aa33539fd33c6d3a32 Mon Sep 17 00:00:00 2001 From: Appla Date: Wed, 10 Sep 2025 16:37:55 +0800 Subject: [PATCH 08/64] Fix hard_timeout when zend-max-execution-timers is enabled Closes GH-19786 --- NEWS | 1 + Zend/zend_execute_API.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 8ed895987f9c..1af55dd4c84f 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - Core: . Fixed bug GH-19765 (object_properties_load() bypasses readonly property checks). (timwolla) + . Fixed hard_timeout with --enable-zend-max-execution-timers. (Appla) - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fe37b024934d..d4a373616fe9 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1531,7 +1531,9 @@ static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */ return; } #elif defined(ZEND_MAX_EXECUTION_TIMERS) - zend_max_execution_timer_settime(seconds); + if (seconds > 0) { + zend_max_execution_timer_settime(seconds); + } if (reset_signals) { sigset_t sigset; @@ -1618,7 +1620,9 @@ void zend_unset_timeout(void) /* {{{ */ tq_timer = NULL; } #elif ZEND_MAX_EXECUTION_TIMERS - zend_max_execution_timer_settime(0); + if (EG(timeout_seconds)) { + zend_max_execution_timer_settime(0); + } #elif defined(HAVE_SETITIMER) if (EG(timeout_seconds)) { struct itimerval no_timeout; From be5b2bf4b8fa20273d6bdf82d7c200fda1fc4318 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 11 Sep 2025 14:59:11 +0200 Subject: [PATCH 09/64] [skip ci] Add --enable-zend-max-execution-timers to variation nightly build Only enable for 8.3 because of GH-19786. --- .github/workflows/nightly.yml | 4 ++++ .github/workflows/root.yml | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 62ea79650212..a8c8c80d7d50 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -44,6 +44,9 @@ on: skip_wordpress: required: true type: boolean + variation_enable_zend_max_execution_timers: + required: true + type: boolean permissions: contents: read jobs: @@ -199,6 +202,7 @@ jobs: zts: true configuration_parameters: >- CFLAGS="-DZEND_RC_DEBUG=1 -DPROFITABILITY_CHECKS=0 -DZEND_VERIFY_FUNC_INFO=1 -DZEND_VERIFY_TYPE_INFERENCE" + ${{ inputs.variation_enable_zend_max_execution_timers && '--enable-zend-max-execution-timers' || '' }} run_tests_parameters: -d zend_test.observer.enabled=1 -d zend_test.observer.show_output=0 timeout_minutes: 360 test_function_jit: true diff --git a/.github/workflows/root.yml b/.github/workflows/root.yml index 16418b1aa1d3..b70b026eced0 100644 --- a/.github/workflows/root.yml +++ b/.github/workflows/root.yml @@ -64,4 +64,5 @@ jobs: skip_laravel: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} skip_symfony: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} skip_wordpress: ${{ matrix.branch.version[0] == 8 && matrix.branch.version[1] == 1 }} + variation_enable_zend_max_execution_timers: ${{ (matrix.branch.version[0] == 8 && matrix.branch.version[1] >= 3) || matrix.branch.version[0] >= 9 }} secrets: inherit From 2ad0b5cf052eba0c3c16fb0800fafe74412e8629 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 10 Sep 2025 21:28:23 +0200 Subject: [PATCH 10/64] Fix GH-19792: SCCP causes UAF for return value if both warning and exception are triggered If an exception _and_ a warning (or deprecation) is emitted, then the result is destroyed twice. Use an `else if` to prevent this. This is tested via zend_test because the deprecation that triggered the original reproducer may disappear in the future. Closes GH-19793. --- NEWS | 2 ++ Zend/Optimizer/sccp.c | 4 +--- ext/opcache/tests/opt/gh19792.phpt | 27 +++++++++++++++++++++++++++ ext/zend_test/test.c | 9 +++++++++ ext/zend_test/test.stub.php | 3 +++ ext/zend_test/test_arginfo.h | 6 +++++- 6 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 ext/opcache/tests/opt/gh19792.phpt diff --git a/NEWS b/NEWS index 1af55dd4c84f..9f97a6985f9e 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ PHP NEWS . Fixed bug GH-19765 (object_properties_load() bypasses readonly property checks). (timwolla) . Fixed hard_timeout with --enable-zend-max-execution-timers. (Appla) + . Fixed bug GH-19792 (SCCP causes UAF for return value if both warning and + exception are triggered). (nielsdos) - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index d5486803e19a..4b7a77abb091 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -842,9 +842,7 @@ static inline zend_result ct_eval_func_call( zval_ptr_dtor(result); zend_clear_exception(); retval = FAILURE; - } - - if (EG(capture_warnings_during_sccp) > 1) { + } else if (EG(capture_warnings_during_sccp) > 1) { zval_ptr_dtor(result); retval = FAILURE; } diff --git a/ext/opcache/tests/opt/gh19792.phpt b/ext/opcache/tests/opt/gh19792.phpt new file mode 100644 index 000000000000..edd805ca57a1 --- /dev/null +++ b/ext/opcache/tests/opt/gh19792.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-19792 (SCCP causes UAF for return value if both warning and exception are triggered) +--EXTENSIONS-- +opcache +zend_test +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECTF-- +Warning: a warning in %s on line %d +an exception diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index e7bb97cb44ab..67150d47b044 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1528,3 +1528,12 @@ static PHP_FUNCTION(zend_test_gh18756) zend_mm_gc(heap); zend_mm_shutdown(heap, true, false); } + +static PHP_FUNCTION(zend_test_gh19792) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + RETVAL_STRING("this is a non-interned string"); + zend_error(E_WARNING, "a warning"); + zend_throw_error(NULL, "an exception"); +} diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index f9cb93b5a1cc..290f55976d16 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -264,6 +264,9 @@ function zend_test_is_zend_ptr(int $addr): bool {} function zend_test_log_err_debug(string $str): void {} function zend_test_gh18756(): void {} + + /** @compile-time-eval */ + function zend_test_gh19792(): void {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index c7e3df5c58d2..cccd4608d982 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2f161861ab09b6b5b594dc2db7c2c9df49d76aa7 */ + * Stub hash: fa769dbbf7ba1d10f0141fed6a45fc06a84cd94c */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -164,6 +164,8 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_gh18756 arginfo_zend_test_void_return +#define arginfo_zend_test_gh19792 arginfo_zend_test_void_return + #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return @@ -295,6 +297,7 @@ static ZEND_FUNCTION(zend_test_cast_fread); static ZEND_FUNCTION(zend_test_is_zend_ptr); static ZEND_FUNCTION(zend_test_log_err_debug); static ZEND_FUNCTION(zend_test_gh18756); +static ZEND_FUNCTION(zend_test_gh19792); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -376,6 +379,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_is_zend_ptr, arginfo_zend_test_is_zend_ptr) ZEND_FE(zend_test_log_err_debug, arginfo_zend_test_log_err_debug) ZEND_FE(zend_test_gh18756, arginfo_zend_test_gh18756) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(zend_test_gh19792, arginfo_zend_test_gh19792) ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func) From 4974d5ef49f4467ce183df73ffa85493cff93712 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 8 Sep 2025 18:55:47 +0200 Subject: [PATCH 11/64] Fix GH-19701: Serialize/deserialize loses some data See GH-19701 for discussion. This now restores the (correct) serialization output from versions PHP 7.4.1 and below. Closes GH-19762. --- NEWS | 1 + ext/standard/tests/serialize/gh19701.phpt | 30 +++++++++++++++++++++++ ext/standard/var.c | 9 +------ 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 ext/standard/tests/serialize/gh19701.phpt diff --git a/NEWS b/NEWS index 9f97a6985f9e..28b811682f2c 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ PHP NEWS - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). (nielsdos) + . Fixed bug GH-19701 (Serialize/deserialize loses some data). (nielsdos) - Zip: . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos) diff --git a/ext/standard/tests/serialize/gh19701.phpt b/ext/standard/tests/serialize/gh19701.phpt new file mode 100644 index 000000000000..a1a3fd5c64bc --- /dev/null +++ b/ext/standard/tests/serialize/gh19701.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-19701 (Serialize/deserialize loses some data) +--CREDITS-- +cuchac +DanielEScherzer +--FILE-- +parent = $baseProduct; +$baseProduct->children = [ $child ]; + +$data = [clone $baseProduct, $baseProduct]; + +echo serialize($data), "\n"; + +?> +--EXPECT-- +a:2:{i:0;O:4:"Item":2:{s:8:"children";a:1:{i:0;O:4:"Item":2:{s:8:"children";a:0:{}s:6:"parent";O:4:"Item":2:{s:8:"children";a:1:{i:0;r:4;}s:6:"parent";N;}}}s:6:"parent";N;}i:1;r:6;} diff --git a/ext/standard/var.c b/ext/standard/var.c index b7dc6dff1d88..c6e280d15ab9 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -954,18 +954,11 @@ static void php_var_serialize_nested_data(smart_str *buf, zval *struc, HashTable /* we should still add element even if it's not OK, * since we already wrote the length of the array before */ if (Z_TYPE_P(data) == IS_ARRAY) { - if (UNEXPECTED(Z_IS_RECURSIVE_P(data)) - || UNEXPECTED(Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))) { + if (UNEXPECTED(Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))) { php_add_var_hash(var_hash, struc, in_rcn_array); smart_str_appendl(buf, "N;", 2); } else { - if (Z_REFCOUNTED_P(data)) { - Z_PROTECT_RECURSION_P(data); - } php_var_serialize_intern(buf, data, var_hash, in_rcn_array, false); - if (Z_REFCOUNTED_P(data)) { - Z_UNPROTECT_RECURSION_P(data); - } } } else { php_var_serialize_intern(buf, data, var_hash, in_rcn_array, false); From 871fe600c244f3b63817ce1929e349fc02da8ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Fri, 12 Sep 2025 20:53:14 +0200 Subject: [PATCH 12/64] curl: Fix cloning of POST fields (#19813) --- NEWS | 4 +++ ext/curl/interface.c | 2 +- .../curl_copy_handle_variation3_clone.phpt | 34 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 ext/curl/tests/curl_copy_handle_variation3_clone.phpt diff --git a/NEWS b/NEWS index 28b811682f2c..8dde1a0cd87d 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,10 @@ PHP NEWS . Fixed bug GH-19792 (SCCP causes UAF for return value if both warning and exception are triggered). (nielsdos) +- Curl: + . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead + of the curl_copy_handle() function to clone a CurlHandle. + - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). (nielsdos) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index b3139422cffa..79f53be14f3d 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -468,7 +468,7 @@ static zend_object *curl_clone_obj(zend_object *object) { clone_ch->cp = cp; _php_setup_easy_copy_handlers(clone_ch, ch); - postfields = &clone_ch->postfields; + postfields = &ch->postfields; if (Z_TYPE_P(postfields) != IS_UNDEF) { if (build_mime_structure_from_hash(clone_ch, postfields) == FAILURE) { zend_throw_exception(NULL, "Failed to clone CurlHandle", 0); diff --git a/ext/curl/tests/curl_copy_handle_variation3_clone.phpt b/ext/curl/tests/curl_copy_handle_variation3_clone.phpt new file mode 100644 index 000000000000..7951cb025811 --- /dev/null +++ b/ext/curl/tests/curl_copy_handle_variation3_clone.phpt @@ -0,0 +1,34 @@ +--TEST-- +clone() allows to post CURLFile multiple times +--EXTENSIONS-- +curl +--FILE-- + $file); +var_dump(curl_setopt($ch1, CURLOPT_POSTFIELDS, $params)); + +$ch2 = clone($ch1); + +var_dump(curl_exec($ch1)); + +var_dump(curl_exec($ch2)); +?> +--EXPECTF-- +bool(true) +string(%d) "curl_copy_handle_variation3_clone.txt|application/octet-stream|5" +string(%d) "curl_copy_handle_variation3_clone.txt|application/octet-stream|5" +--CLEAN-- + From b8a9d790af149633ef3783d12dc099fe88560b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Fri, 12 Sep 2025 20:55:00 +0200 Subject: [PATCH 13/64] [skip ci] Add missing name for GH-19813 in NEWS --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 8dde1a0cd87d..04bd8789f30b 100644 --- a/NEWS +++ b/NEWS @@ -11,7 +11,7 @@ PHP NEWS - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead - of the curl_copy_handle() function to clone a CurlHandle. + of the curl_copy_handle() function to clone a CurlHandle. (timwolla) - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). From d30dd1b47b023ffa98b2f2b62a6f209f64822c32 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 12 Sep 2025 21:45:46 +0200 Subject: [PATCH 14/64] Fix GH-19784: SoapServer memory leak Closes GH-19818. --- NEWS | 3 +++ ext/soap/soap.c | 8 +++++++- ext/soap/tests/bugs/gh19784.phpt | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 ext/soap/tests/bugs/gh19784.phpt diff --git a/NEWS b/NEWS index 04bd8789f30b..3572f9517846 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,9 @@ PHP NEWS . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead of the curl_copy_handle() function to clone a CurlHandle. (timwolla) +- Soap: + . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) + - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). (nielsdos) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index fc51e32658f3..4a4fa4f4e626 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -880,7 +880,13 @@ PHP_METHOD(SoapServer, __construct) service->soap_functions.ft = zend_new_array(0); if (wsdl) { - service->sdl = get_sdl(ZEND_THIS, ZSTR_VAL(wsdl), cache_wsdl); + zend_try { + service->sdl = get_sdl(ZEND_THIS, ZSTR_VAL(wsdl), cache_wsdl); + } zend_catch { + xmlCharEncCloseFunc(service->encoding); + service->encoding = NULL; + zend_bailout(); + } zend_end_try(); if (service->uri == NULL) { if (service->sdl->target_ns) { service->uri = estrdup(service->sdl->target_ns); diff --git a/ext/soap/tests/bugs/gh19784.phpt b/ext/soap/tests/bugs/gh19784.phpt new file mode 100644 index 000000000000..1f718e74c459 --- /dev/null +++ b/ext/soap/tests/bugs/gh19784.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-19784 (SoapServer memory leak) +--EXTENSIONS-- +soap +--FILE-- + $v_5257); +new SoapServer('foobarbaz',$v_5238,); +?> +--EXPECTF-- + +%s%a From b46681d68685408f49e921f54e3b422180f1c096 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 13 Sep 2025 00:15:01 +0200 Subject: [PATCH 15/64] Fix curl build failure on macOS+curl 8.16 Closes GH-19820. --- NEWS | 1 + ext/curl/interface.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 3572f9517846..e40677a759f1 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ PHP NEWS - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead of the curl_copy_handle() function to clone a CurlHandle. (timwolla) + . Fix curl build failure on macOS+curl 8.16. (nielsdos) - Soap: . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 79f53be14f3d..67ec5aabc391 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -677,11 +677,11 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string) /* }}} */ /* {{{ curl_progress */ -static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) +static int curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { php_curl *ch = (php_curl *)clientp; php_curl_callback *t = ch->handlers.progress; - size_t rval = 0; + int rval = 0; #if PHP_CURL_DEBUG fprintf(stderr, "curl_progress() called\n"); @@ -726,11 +726,11 @@ static size_t curl_progress(void *clientp, double dltotal, double dlnow, double #if LIBCURL_VERSION_NUM >= 0x072000 /* {{{ curl_xferinfo */ -static size_t curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) +static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { php_curl *ch = (php_curl *)clientp; php_curl_callback *t = ch->handlers.xferinfo; - size_t rval = 0; + int rval = 0; #if PHP_CURL_DEBUG fprintf(stderr, "curl_xferinfo() called\n"); @@ -1154,8 +1154,8 @@ static void _php_curl_set_default_options(php_curl *ch) { char *cainfo; - curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0); + curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0L); curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str); curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write); curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch); @@ -1164,10 +1164,10 @@ static void _php_curl_set_default_options(php_curl *ch) curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_header); curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch); #ifndef ZTS - curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1); + curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1L); #endif - curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120); - curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20); /* prevent infinite redirects */ + curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120L); + curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20L); /* prevent infinite redirects */ cainfo = INI_STR("openssl.cafile"); if (!(cainfo && cainfo[0] != '\0')) { @@ -2278,7 +2278,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue /* no need to build the mime structure for empty hashtables; also works around https://github.com/curl/curl/issues/6455 */ curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, ""); - error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0); + error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0L); } else { return build_mime_structure_from_hash(ch, zvalue); } @@ -2371,7 +2371,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue case CURLOPT_POSTREDIR: lval = zval_get_long(zvalue); - error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, lval & CURL_REDIR_POST_ALL); + error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, (long) (lval & CURL_REDIR_POST_ALL)); break; /* the following options deal with files, therefore the open_basedir check @@ -2406,11 +2406,11 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue if (zend_is_true(zvalue)) { curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug); curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch); - curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1); + curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1L); } else { curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, NULL); curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, NULL); - curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0); + curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0L); } break; From 22252954efd1a8e81f735dd4ebd908b66f8fc733 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 31 Aug 2025 21:28:22 +0200 Subject: [PATCH 16/64] Fix GH-19653: Closure named argument unpacking between temporary closures can cause a crash Due to user closures, the `fbc` address isn't unique if the memory address is reused. We need to distinguish using a unique key, and we choose arg_info such that it can be reused across different functions. Closes GH-19654. --- NEWS | 2 ++ Zend/tests/closures/gh19653_1.phpt | 27 +++++++++++++++++++++++++++ Zend/tests/closures/gh19653_2.phpt | 23 +++++++++++++++++++++++ Zend/zend_execute.c | 21 +++++++++++++++------ 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 Zend/tests/closures/gh19653_1.phpt create mode 100644 Zend/tests/closures/gh19653_2.phpt diff --git a/NEWS b/NEWS index e40677a759f1..643763166e82 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ PHP NEWS . Fixed hard_timeout with --enable-zend-max-execution-timers. (Appla) . Fixed bug GH-19792 (SCCP causes UAF for return value if both warning and exception are triggered). (nielsdos) + . Fixed bug GH-19653 (Closure named argument unpacking between temporary + closures can cause a crash). (nielsdos, Arnaud, Bob) - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead diff --git a/Zend/tests/closures/gh19653_1.phpt b/Zend/tests/closures/gh19653_1.phpt new file mode 100644 index 000000000000..93b119eb5782 --- /dev/null +++ b/Zend/tests/closures/gh19653_1.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-19653 (Closure named argument unpacking between temporary closures can cause a crash) +--CREDITS-- +ivan-u7n +--FILE-- + +--EXPECT-- +usage1() func1() a1=a1 a2=a2 a3=m3+ +usage1() [function] func1() a1=a1 a2=m2+ a3=m3+ diff --git a/Zend/tests/closures/gh19653_2.phpt b/Zend/tests/closures/gh19653_2.phpt new file mode 100644 index 000000000000..7eb837dd22c4 --- /dev/null +++ b/Zend/tests/closures/gh19653_2.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-19653 (Closure named argument unpacking between temporary closures can cause a crash) - eval variation +--CREDITS-- +arnaud-lb +--FILE-- + +--EXPECTF-- +int(1) + +Fatal error: Uncaught Error: Unknown named parameter $a in %s:%d +Stack trace: +#0 %s(%d): usage1(Object(Closure)) +#1 {main} + thrown in %s on line %d diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 99da3a4a051f..4e6339ca901c 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -5058,7 +5058,12 @@ static zend_never_inline zend_result ZEND_FASTCALL zend_quick_check_constant( static zend_always_inline uint32_t zend_get_arg_offset_by_name( zend_function *fbc, zend_string *arg_name, void **cache_slot) { - if (EXPECTED(*cache_slot == fbc)) { + /* Due to closures, the `fbc` address isn't unique if the memory address is reused. + * The argument info will be however and uniquely positions the arguments. + * We do support NULL arg_info, so we have to distinguish that from an uninitialized cache slot. */ + void *unique_id = (void *) ((uintptr_t) fbc->common.arg_info | 1); + + if (EXPECTED(*cache_slot == unique_id)) { return *(uintptr_t *)(cache_slot + 1); } @@ -5069,8 +5074,10 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( for (uint32_t i = 0; i < num_args; i++) { zend_arg_info *arg_info = &fbc->op_array.arg_info[i]; if (zend_string_equals(arg_name, arg_info->name)) { - *cache_slot = fbc; - *(uintptr_t *)(cache_slot + 1) = i; + if (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE)) { + *cache_slot = unique_id; + *(uintptr_t *)(cache_slot + 1) = i; + } return i; } } @@ -5079,7 +5086,7 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( zend_internal_arg_info *arg_info = &fbc->internal_function.arg_info[i]; size_t len = strlen(arg_info->name); if (zend_string_equals_cstr(arg_name, arg_info->name, len)) { - *cache_slot = fbc; + *cache_slot = unique_id; *(uintptr_t *)(cache_slot + 1) = i; return i; } @@ -5087,8 +5094,10 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( } if (fbc->common.fn_flags & ZEND_ACC_VARIADIC) { - *cache_slot = fbc; - *(uintptr_t *)(cache_slot + 1) = fbc->common.num_args; + if (fbc->type == ZEND_INTERNAL_FUNCTION || !fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE)) { + *cache_slot = unique_id; + *(uintptr_t *)(cache_slot + 1) = fbc->common.num_args; + } return fbc->common.num_args; } From a0329dbab009d984926f8817359ba5d83195d960 Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Mon, 15 Sep 2025 10:38:53 +0100 Subject: [PATCH 17/64] Update timelib to 2022.14 --- ext/date/lib/parse_date.c | 213 +++++++++++++++-------------- ext/date/lib/parse_date.re | 5 +- ext/date/lib/parse_iso_intervals.c | 18 +-- ext/date/lib/timelib.h | 8 +- 4 files changed, 125 insertions(+), 119 deletions(-) diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c index ea1602ef13b4..d27511cad35e 100644 --- a/ext/date/lib/parse_date.c +++ b/ext/date/lib/parse_date.c @@ -1,4 +1,4 @@ -/* Generated by re2c 1.0.3 on Wed Sep 11 17:29:29 2024 */ +/* Generated by re2c 1.0.3 on Mon Sep 15 10:38:03 2025 */ #line 1 "ext/date/lib/parse_date.re" /* * The MIT License (MIT) @@ -941,10 +941,12 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int { timelib_tzinfo *res; timelib_long retval = 0; + size_t paren_count = 0; *tz_not_found = 0; while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') { + paren_count += **ptr == '('; ++*ptr; } if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) { @@ -993,8 +995,9 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int *tz_not_found = (found == 0); retval = offset; } - while (**ptr == ')') { + while (paren_count > 0 && **ptr == ')') { ++*ptr; + paren_count--; } return retval; } @@ -1018,11 +1021,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) std: s->tok = cursor; s->len = 0; -#line 1151 "ext/date/lib/parse_date.re" +#line 1154 "ext/date/lib/parse_date.re" -#line 1026 "" +#line 1029 "ext/date/lib/parse_date.c" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -1203,23 +1206,23 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(2, *YYCURSOR); ++YYCURSOR; YYDEBUG(3, *YYCURSOR); -#line 1984 "ext/date/lib/parse_date.re" +#line 1987 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 1212 "" +#line 1215 "ext/date/lib/parse_date.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; yy5: YYDEBUG(5, *YYCURSOR); -#line 1990 "ext/date/lib/parse_date.re" +#line 1993 "ext/date/lib/parse_date.re" { add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character"); goto std; } -#line 1223 "" +#line 1226 "ext/date/lib/parse_date.c" yy6: YYDEBUG(6, *YYCURSOR); yyaccept = 0; @@ -1234,11 +1237,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy58; yy8: YYDEBUG(8, *YYCURSOR); -#line 1979 "ext/date/lib/parse_date.re" +#line 1982 "ext/date/lib/parse_date.re" { goto std; } -#line 1242 "" +#line 1245 "ext/date/lib/parse_date.c" yy9: YYDEBUG(9, *YYCURSOR); yych = *++YYCURSOR; @@ -1272,11 +1275,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(11, *YYCURSOR); ++YYCURSOR; YYDEBUG(12, *YYCURSOR); -#line 1974 "ext/date/lib/parse_date.re" +#line 1977 "ext/date/lib/parse_date.re" { goto std; } -#line 1280 "" +#line 1283 "ext/date/lib/parse_date.c" yy13: YYDEBUG(13, *YYCURSOR); yyaccept = 1; @@ -1777,7 +1780,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy20: YYDEBUG(20, *YYCURSOR); -#line 1889 "ext/date/lib/parse_date.re" +#line 1892 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -1791,7 +1794,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 1795 "" +#line 1798 "ext/date/lib/parse_date.c" yy21: YYDEBUG(21, *YYCURSOR); yych = *++YYCURSOR; @@ -3596,7 +3599,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy81: YYDEBUG(81, *YYCURSOR); -#line 1636 "ext/date/lib/parse_date.re" +#line 1639 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -3607,7 +3610,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 3611 "" +#line 3614 "ext/date/lib/parse_date.c" yy82: YYDEBUG(82, *YYCURSOR); yych = *++YYCURSOR; @@ -4122,7 +4125,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } if (yych == '.') goto yy289; YYDEBUG(114, *YYCURSOR); -#line 1211 "ext/date/lib/parse_date.re" +#line 1214 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -4147,7 +4150,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 4151 "" +#line 4154 "ext/date/lib/parse_date.c" yy115: YYDEBUG(115, *YYCURSOR); ++YYCURSOR; @@ -5873,7 +5876,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy177: YYDEBUG(177, *YYCURSOR); -#line 1377 "ext/date/lib/parse_date.re" +#line 1380 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long"); @@ -5900,7 +5903,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 5904 "" +#line 5907 "ext/date/lib/parse_date.c" yy178: YYDEBUG(178, *YYCURSOR); yyaccept = 4; @@ -6929,7 +6932,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy224: YYDEBUG(224, *YYCURSOR); -#line 1471 "ext/date/lib/parse_date.re" +#line 1474 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("americanshort | american"); @@ -6944,7 +6947,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 6948 "" +#line 6951 "ext/date/lib/parse_date.c" yy225: YYDEBUG(225, *YYCURSOR); yyaccept = 5; @@ -7187,7 +7190,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy431; yy251: YYDEBUG(251, *YYCURSOR); -#line 1553 "ext/date/lib/parse_date.re" +#line 1556 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datefull"); @@ -7201,7 +7204,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 7205 "" +#line 7208 "ext/date/lib/parse_date.c" yy252: YYDEBUG(252, *YYCURSOR); yyaccept = 3; @@ -7315,7 +7318,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy440; yy260: YYDEBUG(260, *YYCURSOR); -#line 1958 "ext/date/lib/parse_date.re" +#line 1961 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -7330,7 +7333,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7334 "" +#line 7337 "ext/date/lib/parse_date.c" yy261: YYDEBUG(261, *YYCURSOR); yych = *++YYCURSOR; @@ -7776,7 +7779,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy471; yy290: YYDEBUG(290, *YYCURSOR); -#line 1237 "ext/date/lib/parse_date.re" +#line 1240 "ext/date/lib/parse_date.re" { timelib_sll i; timelib_ull us; @@ -7815,7 +7818,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7819 "" +#line 7822 "ext/date/lib/parse_date.c" yy291: YYDEBUG(291, *YYCURSOR); yych = *++YYCURSOR; @@ -7840,7 +7843,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy293: YYDEBUG(293, *YYCURSOR); -#line 1799 "ext/date/lib/parse_date.re" +#line 1802 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -7860,7 +7863,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 7864 "" +#line 7867 "ext/date/lib/parse_date.c" yy294: YYDEBUG(294, *YYCURSOR); yyaccept = 7; @@ -7899,7 +7902,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy295: YYDEBUG(295, *YYCURSOR); -#line 1879 "ext/date/lib/parse_date.re" +#line 1882 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -7908,7 +7911,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 7912 "" +#line 7915 "ext/date/lib/parse_date.c" yy296: YYDEBUG(296, *YYCURSOR); yyaccept = 7; @@ -8483,7 +8486,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy315: YYDEBUG(315, *YYCURSOR); -#line 1820 "ext/date/lib/parse_date.re" +#line 1823 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -8500,7 +8503,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 8504 "" +#line 8507 "ext/date/lib/parse_date.c" yy316: YYDEBUG(316, *YYCURSOR); yych = *++YYCURSOR; @@ -8768,7 +8771,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy325: YYDEBUG(325, *YYCURSOR); -#line 1622 "ext/date/lib/parse_date.re" +#line 1625 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datetextual | datenoyear"); @@ -8781,7 +8784,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 8785 "" +#line 8788 "ext/date/lib/parse_date.c" yy326: YYDEBUG(326, *YYCURSOR); yyaccept = 10; @@ -9475,7 +9478,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy351: YYDEBUG(351, *YYCURSOR); -#line 1168 "ext/date/lib/parse_date.re" +#line 1171 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -9483,7 +9486,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 9487 "" +#line 9490 "ext/date/lib/parse_date.c" yy352: YYDEBUG(352, *YYCURSOR); yyaccept = 2; @@ -10986,7 +10989,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy420: YYDEBUG(420, *YYCURSOR); -#line 1405 "ext/date/lib/parse_date.re" +#line 1408 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -11008,7 +11011,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 11012 "" +#line 11015 "ext/date/lib/parse_date.c" yy421: YYDEBUG(421, *YYCURSOR); yyaccept = 13; @@ -11089,7 +11092,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy422: YYDEBUG(422, *YYCURSOR); -#line 1790 "ext/date/lib/parse_date.re" +#line 1793 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -11097,7 +11100,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 11101 "" +#line 11104 "ext/date/lib/parse_date.c" yy423: YYDEBUG(423, *YYCURSOR); yyaccept = 3; @@ -11704,7 +11707,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(456, *YYCURSOR); ++YYCURSOR; YYDEBUG(457, *YYCURSOR); -#line 1339 "ext/date/lib/parse_date.re" +#line 1342 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -11721,7 +11724,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 11725 "" +#line 11728 "ext/date/lib/parse_date.c" yy458: YYDEBUG(458, *YYCURSOR); yych = *++YYCURSOR; @@ -13048,7 +13051,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy526: YYDEBUG(526, *YYCURSOR); -#line 1177 "ext/date/lib/parse_date.re" +#line 1180 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -13059,7 +13062,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 13063 "" +#line 13066 "ext/date/lib/parse_date.c" yy527: YYDEBUG(527, *YYCURSOR); yyaccept = 2; @@ -14105,7 +14108,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy567: YYDEBUG(567, *YYCURSOR); -#line 1539 "ext/date/lib/parse_date.re" +#line 1542 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshort"); @@ -14118,7 +14121,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14122 "" +#line 14125 "ext/date/lib/parse_date.c" yy568: YYDEBUG(568, *YYCURSOR); yyaccept = 15; @@ -14569,7 +14572,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy600: YYDEBUG(600, *YYCURSOR); -#line 1608 "ext/date/lib/parse_date.re" +#line 1611 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenodayrev"); @@ -14582,7 +14585,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 14586 "" +#line 14589 "ext/date/lib/parse_date.c" yy601: YYDEBUG(601, *YYCURSOR); yych = *++YYCURSOR; @@ -15957,7 +15960,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(696, *YYCURSOR); ++YYCURSOR; YYDEBUG(697, *YYCURSOR); -#line 1594 "ext/date/lib/parse_date.re" +#line 1597 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenoday"); @@ -15970,7 +15973,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 15974 "" +#line 15977 "ext/date/lib/parse_date.c" yy698: YYDEBUG(698, *YYCURSOR); yych = *++YYCURSOR; @@ -16531,7 +16534,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy722: YYDEBUG(722, *YYCURSOR); -#line 1189 "ext/date/lib/parse_date.re" +#line 1192 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -16540,7 +16543,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 16544 "" +#line 16547 "ext/date/lib/parse_date.c" yy723: YYDEBUG(723, *YYCURSOR); yych = *++YYCURSOR; @@ -16850,7 +16853,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy897; yy739: YYDEBUG(739, *YYCURSOR); -#line 1580 "ext/date/lib/parse_date.re" +#line 1583 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pointed date YY"); @@ -16863,7 +16866,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 16867 "" +#line 16870 "ext/date/lib/parse_date.c" yy740: YYDEBUG(740, *YYCURSOR); yyaccept = 15; @@ -16975,7 +16978,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy752: YYDEBUG(752, *YYCURSOR); -#line 1525 "ext/date/lib/parse_date.re" +#line 1528 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshorter"); @@ -16988,7 +16991,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 16992 "" +#line 16995 "ext/date/lib/parse_date.c" yy753: YYDEBUG(753, *YYCURSOR); yyaccept = 18; @@ -17237,7 +17240,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy777: YYDEBUG(777, *YYCURSOR); -#line 1451 "ext/date/lib/parse_date.re" +#line 1454 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -17256,7 +17259,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 17260 "" +#line 17263 "ext/date/lib/parse_date.c" yy778: YYDEBUG(778, *YYCURSOR); yyaccept = 19; @@ -18484,7 +18487,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy849: YYDEBUG(849, *YYCURSOR); -#line 1928 "ext/date/lib/parse_date.re" +#line 1931 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -18513,7 +18516,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 18517 "" +#line 18520 "ext/date/lib/parse_date.c" yy850: YYDEBUG(850, *YYCURSOR); yyaccept = 20; @@ -19557,7 +19560,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy926: YYDEBUG(926, *YYCURSOR); -#line 1686 "ext/date/lib/parse_date.re" +#line 1689 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgydotd"); @@ -19570,7 +19573,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 19574 "" +#line 19577 "ext/date/lib/parse_date.c" yy927: YYDEBUG(927, *YYCURSOR); yyaccept = 21; @@ -19824,7 +19827,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '7') goto yy1059; yy942: YYDEBUG(942, *YYCURSOR); -#line 1719 "ext/date/lib/parse_date.re" +#line 1722 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -19842,7 +19845,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 19846 "" +#line 19849 "ext/date/lib/parse_date.c" yy943: YYDEBUG(943, *YYCURSOR); yych = *++YYCURSOR; @@ -20318,7 +20321,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy1094; yy982: YYDEBUG(982, *YYCURSOR); -#line 1862 "ext/date/lib/parse_date.re" +#line 1865 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -20334,7 +20337,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 20338 "" +#line 20341 "ext/date/lib/parse_date.c" yy983: YYDEBUG(983, *YYCURSOR); yych = *++YYCURSOR; @@ -20681,7 +20684,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1020, *YYCURSOR); ++YYCURSOR; YYDEBUG(1021, *YYCURSOR); -#line 1568 "ext/date/lib/parse_date.re" +#line 1571 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -20692,7 +20695,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 20696 "" +#line 20699 "ext/date/lib/parse_date.c" yy1022: YYDEBUG(1022, *YYCURSOR); ++YYCURSOR; @@ -20721,7 +20724,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1025: YYDEBUG(1025, *YYCURSOR); -#line 1499 "ext/date/lib/parse_date.re" +#line 1502 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("iso8601date2"); @@ -20734,7 +20737,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20738 "" +#line 20741 "ext/date/lib/parse_date.c" yy1026: YYDEBUG(1026, *YYCURSOR); yyaccept = 15; @@ -20954,7 +20957,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1043: YYDEBUG(1043, *YYCURSOR); -#line 1487 "ext/date/lib/parse_date.re" +#line 1490 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -20965,7 +20968,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20969 "" +#line 20972 "ext/date/lib/parse_date.c" yy1044: YYDEBUG(1044, *YYCURSOR); yyaccept = 26; @@ -21080,7 +21083,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1048: YYDEBUG(1048, *YYCURSOR); -#line 1648 "ext/date/lib/parse_date.re" +#line 1651 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -21091,7 +21094,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 21095 "" +#line 21098 "ext/date/lib/parse_date.c" yy1049: YYDEBUG(1049, *YYCURSOR); yych = *++YYCURSOR; @@ -21161,7 +21164,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1059, *YYCURSOR); ++YYCURSOR; YYDEBUG(1060, *YYCURSOR); -#line 1700 "ext/date/lib/parse_date.re" +#line 1703 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -21179,7 +21182,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 21183 "" +#line 21186 "ext/date/lib/parse_date.c" yy1061: YYDEBUG(1061, *YYCURSOR); yych = *++YYCURSOR; @@ -21242,7 +21245,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1143; yy1070: YYDEBUG(1070, *YYCURSOR); -#line 1738 "ext/date/lib/parse_date.re" +#line 1741 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextshort"); @@ -21255,7 +21258,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 21259 "" +#line 21262 "ext/date/lib/parse_date.c" yy1071: YYDEBUG(1071, *YYCURSOR); yych = *++YYCURSOR; @@ -21728,7 +21731,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1107: YYDEBUG(1107, *YYCURSOR); -#line 1199 "ext/date/lib/parse_date.re" +#line 1202 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -21739,7 +21742,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21743 "" +#line 21746 "ext/date/lib/parse_date.c" yy1108: YYDEBUG(1108, *YYCURSOR); yyaccept = 28; @@ -22076,7 +22079,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1140, *YYCURSOR); ++YYCURSOR; YYDEBUG(1141, *YYCURSOR); -#line 1752 "ext/date/lib/parse_date.re" +#line 1755 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextreverse"); @@ -22089,7 +22092,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 22093 "" +#line 22096 "ext/date/lib/parse_date.c" yy1142: YYDEBUG(1142, *YYCURSOR); ++YYCURSOR; @@ -22133,7 +22136,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1145: YYDEBUG(1145, *YYCURSOR); -#line 1294 "ext/date/lib/parse_date.re" +#line 1297 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("backof | frontof"); TIMELIB_INIT; @@ -22155,7 +22158,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 22159 "" +#line 22162 "ext/date/lib/parse_date.c" yy1146: YYDEBUG(1146, *YYCURSOR); yyaccept = 29; @@ -22479,7 +22482,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1172: YYDEBUG(1172, *YYCURSOR); -#line 1838 "ext/date/lib/parse_date.re" +#line 1841 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -22502,7 +22505,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22506 "" +#line 22509 "ext/date/lib/parse_date.c" yy1173: YYDEBUG(1173, *YYCURSOR); yych = *++YYCURSOR; @@ -22514,7 +22517,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1175: YYDEBUG(1175, *YYCURSOR); -#line 1156 "ext/date/lib/parse_date.re" +#line 1159 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -22525,7 +22528,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22529 "" +#line 22532 "ext/date/lib/parse_date.c" yy1176: YYDEBUG(1176, *YYCURSOR); yyaccept = 31; @@ -23018,7 +23021,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1222, *YYCURSOR); ++YYCURSOR; YYDEBUG(1223, *YYCURSOR); -#line 1904 "ext/date/lib/parse_date.re" +#line 1907 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -23041,7 +23044,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 23045 "" +#line 23048 "ext/date/lib/parse_date.c" yy1224: YYDEBUG(1224, *YYCURSOR); yych = *++YYCURSOR; @@ -23543,7 +23546,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1268, *YYCURSOR); ++YYCURSOR; YYDEBUG(1269, *YYCURSOR); -#line 1317 "ext/date/lib/parse_date.re" +#line 1320 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -23564,7 +23567,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEK_DAY_OF_MONTH; } -#line 23568 "" +#line 23571 "ext/date/lib/parse_date.c" yy1270: YYDEBUG(1270, *YYCURSOR); yyaccept = 24; @@ -23611,7 +23614,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1273, *YYCURSOR); ++YYCURSOR; YYDEBUG(1274, *YYCURSOR); -#line 1277 "ext/date/lib/parse_date.re" +#line 1280 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("firstdayof | lastdayof"); TIMELIB_INIT; @@ -23627,12 +23630,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 23631 "" +#line 23634 "ext/date/lib/parse_date.c" yy1275: YYDEBUG(1275, *YYCURSOR); ++YYCURSOR; YYDEBUG(1276, *YYCURSOR); -#line 1513 "ext/date/lib/parse_date.re" +#line 1516 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601datex"); TIMELIB_INIT; @@ -23643,7 +23646,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 23647 "" +#line 23650 "ext/date/lib/parse_date.c" yy1277: YYDEBUG(1277, *YYCURSOR); yych = *++YYCURSOR; @@ -23746,7 +23749,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1290, *YYCURSOR); ++YYCURSOR; YYDEBUG(1291, *YYCURSOR); -#line 1357 "ext/date/lib/parse_date.re" +#line 1360 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("mssqltime"); TIMELIB_INIT; @@ -23765,7 +23768,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 23769 "" +#line 23772 "ext/date/lib/parse_date.c" yy1292: YYDEBUG(1292, *YYCURSOR); yych = *++YYCURSOR; @@ -24189,7 +24192,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1331; yy1329: YYDEBUG(1329, *YYCURSOR); -#line 1660 "ext/date/lib/parse_date.re" +#line 1663 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -24214,7 +24217,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 24218 "" +#line 24221 "ext/date/lib/parse_date.c" yy1330: YYDEBUG(1330, *YYCURSOR); yych = *++YYCURSOR; @@ -24584,7 +24587,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= ':') goto yy1383; yy1375: YYDEBUG(1375, *YYCURSOR); -#line 1766 "ext/date/lib/parse_date.re" +#line 1769 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -24607,7 +24610,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 24611 "" +#line 24614 "ext/date/lib/parse_date.c" yy1376: YYDEBUG(1376, *YYCURSOR); yyaccept = 33; @@ -24839,7 +24842,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == ':') goto yy1286; goto yy1329; } -#line 1994 "ext/date/lib/parse_date.re" +#line 1997 "ext/date/lib/parse_date.re" } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index d32be9bfe7be..c40a5c07c9aa 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -939,10 +939,12 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int { timelib_tzinfo *res; timelib_long retval = 0; + size_t paren_count = 0; *tz_not_found = 0; while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') { + paren_count += **ptr == '('; ++*ptr; } if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) { @@ -991,8 +993,9 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int *tz_not_found = (found == 0); retval = offset; } - while (**ptr == ')') { + while (paren_count > 0 && **ptr == ')') { ++*ptr; + paren_count--; } return retval; } diff --git a/ext/date/lib/parse_iso_intervals.c b/ext/date/lib/parse_iso_intervals.c index cdc329431ec4..a9fca1b60941 100644 --- a/ext/date/lib/parse_iso_intervals.c +++ b/ext/date/lib/parse_iso_intervals.c @@ -1,4 +1,4 @@ -/* Generated by re2c 1.0.3 on Wed Sep 11 17:29:40 2024 */ +/* Generated by re2c 1.0.3 on Mon Sep 15 10:38:16 2025 */ #line 1 "ext/date/lib/parse_iso_intervals.re" /* * The MIT License (MIT) @@ -180,7 +180,7 @@ static int scan(Scanner *s) -#line 184 "" +#line 184 "ext/date/lib/parse_iso_intervals.c" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -252,7 +252,7 @@ static int scan(Scanner *s) s->pos = cursor; s->line++; goto std; } -#line 256 "" +#line 256 "ext/date/lib/parse_iso_intervals.c" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; @@ -263,7 +263,7 @@ static int scan(Scanner *s) add_error(s, "Unexpected character"); goto std; } -#line 267 "" +#line 267 "ext/date/lib/parse_iso_intervals.c" yy6: YYDEBUG(6, *YYCURSOR); ++YYCURSOR; @@ -272,7 +272,7 @@ static int scan(Scanner *s) { goto std; } -#line 276 "" +#line 276 "ext/date/lib/parse_iso_intervals.c" yy8: YYDEBUG(8, *YYCURSOR); yyaccept = 0; @@ -330,7 +330,7 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_PERIOD; } -#line 334 "" +#line 334 "ext/date/lib/parse_iso_intervals.c" yy11: YYDEBUG(11, *YYCURSOR); yych = *++YYCURSOR; @@ -399,7 +399,7 @@ static int scan(Scanner *s) s->have_recurrences = 1; return TIMELIB_PERIOD; } -#line 403 "" +#line 403 "ext/date/lib/parse_iso_intervals.c" yy19: YYDEBUG(19, *YYCURSOR); yych = *++YYCURSOR; @@ -917,7 +917,7 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 921 "" +#line 921 "ext/date/lib/parse_iso_intervals.c" yy91: YYDEBUG(91, *YYCURSOR); yych = *++YYCURSOR; @@ -956,7 +956,7 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_PERIOD; } -#line 960 "" +#line 960 "ext/date/lib/parse_iso_intervals.c" } #line 321 "ext/date/lib/parse_iso_intervals.re" diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index a2c976af7ed9..ef57a7ee783f 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2024 Derick Rethans + * Copyright (c) 2015-2025 Derick Rethans * Copyright (c) 2018,2021 MongoDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202212 -#define TIMELIB_EXTENDED_VERSION 20221201 -#define TIMELIB_ASCII_VERSION "2022.12" +#define TIMELIB_VERSION 202214 +#define TIMELIB_EXTENDED_VERSION 20221401 +#define TIMELIB_ASCII_VERSION "2022.14" #include #include From b42bd2a359d9c907de17e9f97cc35d6feb3309f0 Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Mon, 15 Sep 2025 10:42:24 +0100 Subject: [PATCH 18/64] Update NEWS --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index ab450fa128e2..10c314bf4d35 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.30 +- Date: + . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. + (nielsdos) + - Opcache: . Reset global pointers to prevent use-after-free in zend_jit_status(). (Florian Engelhardt) From be5784dfec962cc92fd700667969f36fd4c17023 Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Mon, 15 Sep 2025 14:16:24 +0100 Subject: [PATCH 19/64] Revert "Update timelib to 2022.14" This reverts commits: - a0329dbab009d984926f8817359ba5d83195d960 - b42bd2a359d9c907de17e9f97cc35d6feb3309f0 --- NEWS | 4 - ext/date/lib/parse_date.c | 213 ++++++++++++++--------------- ext/date/lib/parse_date.re | 5 +- ext/date/lib/parse_iso_intervals.c | 18 +-- ext/date/lib/timelib.h | 8 +- 5 files changed, 119 insertions(+), 129 deletions(-) diff --git a/NEWS b/NEWS index 10c314bf4d35..ab450fa128e2 100644 --- a/NEWS +++ b/NEWS @@ -2,10 +2,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.30 -- Date: - . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. - (nielsdos) - - Opcache: . Reset global pointers to prevent use-after-free in zend_jit_status(). (Florian Engelhardt) diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c index d27511cad35e..ea1602ef13b4 100644 --- a/ext/date/lib/parse_date.c +++ b/ext/date/lib/parse_date.c @@ -1,4 +1,4 @@ -/* Generated by re2c 1.0.3 on Mon Sep 15 10:38:03 2025 */ +/* Generated by re2c 1.0.3 on Wed Sep 11 17:29:29 2024 */ #line 1 "ext/date/lib/parse_date.re" /* * The MIT License (MIT) @@ -941,12 +941,10 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int { timelib_tzinfo *res; timelib_long retval = 0; - size_t paren_count = 0; *tz_not_found = 0; while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') { - paren_count += **ptr == '('; ++*ptr; } if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) { @@ -995,9 +993,8 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int *tz_not_found = (found == 0); retval = offset; } - while (paren_count > 0 && **ptr == ')') { + while (**ptr == ')') { ++*ptr; - paren_count--; } return retval; } @@ -1021,11 +1018,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) std: s->tok = cursor; s->len = 0; -#line 1154 "ext/date/lib/parse_date.re" +#line 1151 "ext/date/lib/parse_date.re" -#line 1029 "ext/date/lib/parse_date.c" +#line 1026 "" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -1206,23 +1203,23 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(2, *YYCURSOR); ++YYCURSOR; YYDEBUG(3, *YYCURSOR); -#line 1987 "ext/date/lib/parse_date.re" +#line 1984 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 1215 "ext/date/lib/parse_date.c" +#line 1212 "" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; yy5: YYDEBUG(5, *YYCURSOR); -#line 1993 "ext/date/lib/parse_date.re" +#line 1990 "ext/date/lib/parse_date.re" { add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character"); goto std; } -#line 1226 "ext/date/lib/parse_date.c" +#line 1223 "" yy6: YYDEBUG(6, *YYCURSOR); yyaccept = 0; @@ -1237,11 +1234,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy58; yy8: YYDEBUG(8, *YYCURSOR); -#line 1982 "ext/date/lib/parse_date.re" +#line 1979 "ext/date/lib/parse_date.re" { goto std; } -#line 1245 "ext/date/lib/parse_date.c" +#line 1242 "" yy9: YYDEBUG(9, *YYCURSOR); yych = *++YYCURSOR; @@ -1275,11 +1272,11 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(11, *YYCURSOR); ++YYCURSOR; YYDEBUG(12, *YYCURSOR); -#line 1977 "ext/date/lib/parse_date.re" +#line 1974 "ext/date/lib/parse_date.re" { goto std; } -#line 1283 "ext/date/lib/parse_date.c" +#line 1280 "" yy13: YYDEBUG(13, *YYCURSOR); yyaccept = 1; @@ -1780,7 +1777,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy20: YYDEBUG(20, *YYCURSOR); -#line 1892 "ext/date/lib/parse_date.re" +#line 1889 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -1794,7 +1791,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 1798 "ext/date/lib/parse_date.c" +#line 1795 "" yy21: YYDEBUG(21, *YYCURSOR); yych = *++YYCURSOR; @@ -3599,7 +3596,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy81: YYDEBUG(81, *YYCURSOR); -#line 1639 "ext/date/lib/parse_date.re" +#line 1636 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -3610,7 +3607,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 3614 "ext/date/lib/parse_date.c" +#line 3611 "" yy82: YYDEBUG(82, *YYCURSOR); yych = *++YYCURSOR; @@ -4125,7 +4122,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } if (yych == '.') goto yy289; YYDEBUG(114, *YYCURSOR); -#line 1214 "ext/date/lib/parse_date.re" +#line 1211 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -4150,7 +4147,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 4154 "ext/date/lib/parse_date.c" +#line 4151 "" yy115: YYDEBUG(115, *YYCURSOR); ++YYCURSOR; @@ -5876,7 +5873,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy177: YYDEBUG(177, *YYCURSOR); -#line 1380 "ext/date/lib/parse_date.re" +#line 1377 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long"); @@ -5903,7 +5900,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 5907 "ext/date/lib/parse_date.c" +#line 5904 "" yy178: YYDEBUG(178, *YYCURSOR); yyaccept = 4; @@ -6932,7 +6929,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy224: YYDEBUG(224, *YYCURSOR); -#line 1474 "ext/date/lib/parse_date.re" +#line 1471 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("americanshort | american"); @@ -6947,7 +6944,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 6951 "ext/date/lib/parse_date.c" +#line 6948 "" yy225: YYDEBUG(225, *YYCURSOR); yyaccept = 5; @@ -7190,7 +7187,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy431; yy251: YYDEBUG(251, *YYCURSOR); -#line 1556 "ext/date/lib/parse_date.re" +#line 1553 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datefull"); @@ -7204,7 +7201,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 7208 "ext/date/lib/parse_date.c" +#line 7205 "" yy252: YYDEBUG(252, *YYCURSOR); yyaccept = 3; @@ -7318,7 +7315,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy440; yy260: YYDEBUG(260, *YYCURSOR); -#line 1961 "ext/date/lib/parse_date.re" +#line 1958 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -7333,7 +7330,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7337 "ext/date/lib/parse_date.c" +#line 7334 "" yy261: YYDEBUG(261, *YYCURSOR); yych = *++YYCURSOR; @@ -7779,7 +7776,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy471; yy290: YYDEBUG(290, *YYCURSOR); -#line 1240 "ext/date/lib/parse_date.re" +#line 1237 "ext/date/lib/parse_date.re" { timelib_sll i; timelib_ull us; @@ -7818,7 +7815,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 7822 "ext/date/lib/parse_date.c" +#line 7819 "" yy291: YYDEBUG(291, *YYCURSOR); yych = *++YYCURSOR; @@ -7843,7 +7840,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy293: YYDEBUG(293, *YYCURSOR); -#line 1802 "ext/date/lib/parse_date.re" +#line 1799 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -7863,7 +7860,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 7867 "ext/date/lib/parse_date.c" +#line 7864 "" yy294: YYDEBUG(294, *YYCURSOR); yyaccept = 7; @@ -7902,7 +7899,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy295: YYDEBUG(295, *YYCURSOR); -#line 1882 "ext/date/lib/parse_date.re" +#line 1879 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -7911,7 +7908,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 7915 "ext/date/lib/parse_date.c" +#line 7912 "" yy296: YYDEBUG(296, *YYCURSOR); yyaccept = 7; @@ -8486,7 +8483,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy315: YYDEBUG(315, *YYCURSOR); -#line 1823 "ext/date/lib/parse_date.re" +#line 1820 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -8503,7 +8500,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 8507 "ext/date/lib/parse_date.c" +#line 8504 "" yy316: YYDEBUG(316, *YYCURSOR); yych = *++YYCURSOR; @@ -8771,7 +8768,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy325: YYDEBUG(325, *YYCURSOR); -#line 1625 "ext/date/lib/parse_date.re" +#line 1622 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datetextual | datenoyear"); @@ -8784,7 +8781,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 8788 "ext/date/lib/parse_date.c" +#line 8785 "" yy326: YYDEBUG(326, *YYCURSOR); yyaccept = 10; @@ -9478,7 +9475,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy351: YYDEBUG(351, *YYCURSOR); -#line 1171 "ext/date/lib/parse_date.re" +#line 1168 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -9486,7 +9483,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 9490 "ext/date/lib/parse_date.c" +#line 9487 "" yy352: YYDEBUG(352, *YYCURSOR); yyaccept = 2; @@ -10989,7 +10986,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy420: YYDEBUG(420, *YYCURSOR); -#line 1408 "ext/date/lib/parse_date.re" +#line 1405 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -11011,7 +11008,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 11015 "ext/date/lib/parse_date.c" +#line 11012 "" yy421: YYDEBUG(421, *YYCURSOR); yyaccept = 13; @@ -11092,7 +11089,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy422: YYDEBUG(422, *YYCURSOR); -#line 1793 "ext/date/lib/parse_date.re" +#line 1790 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -11100,7 +11097,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 11104 "ext/date/lib/parse_date.c" +#line 11101 "" yy423: YYDEBUG(423, *YYCURSOR); yyaccept = 3; @@ -11707,7 +11704,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(456, *YYCURSOR); ++YYCURSOR; YYDEBUG(457, *YYCURSOR); -#line 1342 "ext/date/lib/parse_date.re" +#line 1339 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -11724,7 +11721,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 11728 "ext/date/lib/parse_date.c" +#line 11725 "" yy458: YYDEBUG(458, *YYCURSOR); yych = *++YYCURSOR; @@ -13051,7 +13048,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy526: YYDEBUG(526, *YYCURSOR); -#line 1180 "ext/date/lib/parse_date.re" +#line 1177 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -13062,7 +13059,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 13066 "ext/date/lib/parse_date.c" +#line 13063 "" yy527: YYDEBUG(527, *YYCURSOR); yyaccept = 2; @@ -14108,7 +14105,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy567: YYDEBUG(567, *YYCURSOR); -#line 1542 "ext/date/lib/parse_date.re" +#line 1539 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshort"); @@ -14121,7 +14118,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14125 "ext/date/lib/parse_date.c" +#line 14122 "" yy568: YYDEBUG(568, *YYCURSOR); yyaccept = 15; @@ -14572,7 +14569,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy600: YYDEBUG(600, *YYCURSOR); -#line 1611 "ext/date/lib/parse_date.re" +#line 1608 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenodayrev"); @@ -14585,7 +14582,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 14589 "ext/date/lib/parse_date.c" +#line 14586 "" yy601: YYDEBUG(601, *YYCURSOR); yych = *++YYCURSOR; @@ -15960,7 +15957,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(696, *YYCURSOR); ++YYCURSOR; YYDEBUG(697, *YYCURSOR); -#line 1597 "ext/date/lib/parse_date.re" +#line 1594 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("datenoday"); @@ -15973,7 +15970,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 15977 "ext/date/lib/parse_date.c" +#line 15974 "" yy698: YYDEBUG(698, *YYCURSOR); yych = *++YYCURSOR; @@ -16534,7 +16531,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy722: YYDEBUG(722, *YYCURSOR); -#line 1192 "ext/date/lib/parse_date.re" +#line 1189 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -16543,7 +16540,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 16547 "ext/date/lib/parse_date.c" +#line 16544 "" yy723: YYDEBUG(723, *YYCURSOR); yych = *++YYCURSOR; @@ -16853,7 +16850,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy897; yy739: YYDEBUG(739, *YYCURSOR); -#line 1583 "ext/date/lib/parse_date.re" +#line 1580 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pointed date YY"); @@ -16866,7 +16863,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 16870 "ext/date/lib/parse_date.c" +#line 16867 "" yy740: YYDEBUG(740, *YYCURSOR); yyaccept = 15; @@ -16978,7 +16975,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy752: YYDEBUG(752, *YYCURSOR); -#line 1528 "ext/date/lib/parse_date.re" +#line 1525 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("gnudateshorter"); @@ -16991,7 +16988,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 16995 "ext/date/lib/parse_date.c" +#line 16992 "" yy753: YYDEBUG(753, *YYCURSOR); yyaccept = 18; @@ -17240,7 +17237,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy777: YYDEBUG(777, *YYCURSOR); -#line 1454 "ext/date/lib/parse_date.re" +#line 1451 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -17259,7 +17256,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 17263 "ext/date/lib/parse_date.c" +#line 17260 "" yy778: YYDEBUG(778, *YYCURSOR); yyaccept = 19; @@ -18487,7 +18484,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy849: YYDEBUG(849, *YYCURSOR); -#line 1931 "ext/date/lib/parse_date.re" +#line 1928 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -18516,7 +18513,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 18520 "ext/date/lib/parse_date.c" +#line 18517 "" yy850: YYDEBUG(850, *YYCURSOR); yyaccept = 20; @@ -19560,7 +19557,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy926: YYDEBUG(926, *YYCURSOR); -#line 1689 "ext/date/lib/parse_date.re" +#line 1686 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgydotd"); @@ -19573,7 +19570,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 19577 "ext/date/lib/parse_date.c" +#line 19574 "" yy927: YYDEBUG(927, *YYCURSOR); yyaccept = 21; @@ -19827,7 +19824,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '7') goto yy1059; yy942: YYDEBUG(942, *YYCURSOR); -#line 1722 "ext/date/lib/parse_date.re" +#line 1719 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -19845,7 +19842,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 19849 "ext/date/lib/parse_date.c" +#line 19846 "" yy943: YYDEBUG(943, *YYCURSOR); yych = *++YYCURSOR; @@ -20321,7 +20318,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == 'e') goto yy1094; yy982: YYDEBUG(982, *YYCURSOR); -#line 1865 "ext/date/lib/parse_date.re" +#line 1862 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -20337,7 +20334,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 20341 "ext/date/lib/parse_date.c" +#line 20338 "" yy983: YYDEBUG(983, *YYCURSOR); yych = *++YYCURSOR; @@ -20684,7 +20681,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1020, *YYCURSOR); ++YYCURSOR; YYDEBUG(1021, *YYCURSOR); -#line 1571 "ext/date/lib/parse_date.re" +#line 1568 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -20695,7 +20692,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 20699 "ext/date/lib/parse_date.c" +#line 20696 "" yy1022: YYDEBUG(1022, *YYCURSOR); ++YYCURSOR; @@ -20724,7 +20721,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1025: YYDEBUG(1025, *YYCURSOR); -#line 1502 "ext/date/lib/parse_date.re" +#line 1499 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("iso8601date2"); @@ -20737,7 +20734,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20741 "ext/date/lib/parse_date.c" +#line 20738 "" yy1026: YYDEBUG(1026, *YYCURSOR); yyaccept = 15; @@ -20957,7 +20954,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1043: YYDEBUG(1043, *YYCURSOR); -#line 1490 "ext/date/lib/parse_date.re" +#line 1487 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -20968,7 +20965,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 20972 "ext/date/lib/parse_date.c" +#line 20969 "" yy1044: YYDEBUG(1044, *YYCURSOR); yyaccept = 26; @@ -21083,7 +21080,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1048: YYDEBUG(1048, *YYCURSOR); -#line 1651 "ext/date/lib/parse_date.re" +#line 1648 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -21094,7 +21091,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 21098 "ext/date/lib/parse_date.c" +#line 21095 "" yy1049: YYDEBUG(1049, *YYCURSOR); yych = *++YYCURSOR; @@ -21164,7 +21161,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1059, *YYCURSOR); ++YYCURSOR; YYDEBUG(1060, *YYCURSOR); -#line 1703 "ext/date/lib/parse_date.re" +#line 1700 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -21182,7 +21179,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 21186 "ext/date/lib/parse_date.c" +#line 21183 "" yy1061: YYDEBUG(1061, *YYCURSOR); yych = *++YYCURSOR; @@ -21245,7 +21242,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1143; yy1070: YYDEBUG(1070, *YYCURSOR); -#line 1741 "ext/date/lib/parse_date.re" +#line 1738 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextshort"); @@ -21258,7 +21255,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 21262 "ext/date/lib/parse_date.c" +#line 21259 "" yy1071: YYDEBUG(1071, *YYCURSOR); yych = *++YYCURSOR; @@ -21731,7 +21728,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1107: YYDEBUG(1107, *YYCURSOR); -#line 1202 "ext/date/lib/parse_date.re" +#line 1199 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -21742,7 +21739,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21746 "ext/date/lib/parse_date.c" +#line 21743 "" yy1108: YYDEBUG(1108, *YYCURSOR); yyaccept = 28; @@ -22079,7 +22076,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1140, *YYCURSOR); ++YYCURSOR; YYDEBUG(1141, *YYCURSOR); -#line 1755 "ext/date/lib/parse_date.re" +#line 1752 "ext/date/lib/parse_date.re" { int length = 0; DEBUG_OUTPUT("pgtextreverse"); @@ -22092,7 +22089,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 22096 "ext/date/lib/parse_date.c" +#line 22093 "" yy1142: YYDEBUG(1142, *YYCURSOR); ++YYCURSOR; @@ -22136,7 +22133,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1145: YYDEBUG(1145, *YYCURSOR); -#line 1297 "ext/date/lib/parse_date.re" +#line 1294 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("backof | frontof"); TIMELIB_INIT; @@ -22158,7 +22155,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 22162 "ext/date/lib/parse_date.c" +#line 22159 "" yy1146: YYDEBUG(1146, *YYCURSOR); yyaccept = 29; @@ -22482,7 +22479,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) } yy1172: YYDEBUG(1172, *YYCURSOR); -#line 1841 "ext/date/lib/parse_date.re" +#line 1838 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -22505,7 +22502,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22509 "ext/date/lib/parse_date.c" +#line 22506 "" yy1173: YYDEBUG(1173, *YYCURSOR); yych = *++YYCURSOR; @@ -22517,7 +22514,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) ++YYCURSOR; yy1175: YYDEBUG(1175, *YYCURSOR); -#line 1159 "ext/date/lib/parse_date.re" +#line 1156 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -22528,7 +22525,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22532 "ext/date/lib/parse_date.c" +#line 22529 "" yy1176: YYDEBUG(1176, *YYCURSOR); yyaccept = 31; @@ -23021,7 +23018,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1222, *YYCURSOR); ++YYCURSOR; YYDEBUG(1223, *YYCURSOR); -#line 1907 "ext/date/lib/parse_date.re" +#line 1904 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -23044,7 +23041,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 23048 "ext/date/lib/parse_date.c" +#line 23045 "" yy1224: YYDEBUG(1224, *YYCURSOR); yych = *++YYCURSOR; @@ -23546,7 +23543,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1268, *YYCURSOR); ++YYCURSOR; YYDEBUG(1269, *YYCURSOR); -#line 1320 "ext/date/lib/parse_date.re" +#line 1317 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -23567,7 +23564,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_WEEK_DAY_OF_MONTH; } -#line 23571 "ext/date/lib/parse_date.c" +#line 23568 "" yy1270: YYDEBUG(1270, *YYCURSOR); yyaccept = 24; @@ -23614,7 +23611,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1273, *YYCURSOR); ++YYCURSOR; YYDEBUG(1274, *YYCURSOR); -#line 1280 "ext/date/lib/parse_date.re" +#line 1277 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("firstdayof | lastdayof"); TIMELIB_INIT; @@ -23630,12 +23627,12 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_LF_DAY_OF_MONTH; } -#line 23634 "ext/date/lib/parse_date.c" +#line 23631 "" yy1275: YYDEBUG(1275, *YYCURSOR); ++YYCURSOR; YYDEBUG(1276, *YYCURSOR); -#line 1516 "ext/date/lib/parse_date.re" +#line 1513 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601datex"); TIMELIB_INIT; @@ -23646,7 +23643,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 23650 "ext/date/lib/parse_date.c" +#line 23647 "" yy1277: YYDEBUG(1277, *YYCURSOR); yych = *++YYCURSOR; @@ -23749,7 +23746,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) YYDEBUG(1290, *YYCURSOR); ++YYCURSOR; YYDEBUG(1291, *YYCURSOR); -#line 1360 "ext/date/lib/parse_date.re" +#line 1357 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("mssqltime"); TIMELIB_INIT; @@ -23768,7 +23765,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 23772 "ext/date/lib/parse_date.c" +#line 23769 "" yy1292: YYDEBUG(1292, *YYCURSOR); yych = *++YYCURSOR; @@ -24192,7 +24189,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= '9') goto yy1331; yy1329: YYDEBUG(1329, *YYCURSOR); -#line 1663 "ext/date/lib/parse_date.re" +#line 1660 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -24217,7 +24214,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 24221 "ext/date/lib/parse_date.c" +#line 24218 "" yy1330: YYDEBUG(1330, *YYCURSOR); yych = *++YYCURSOR; @@ -24587,7 +24584,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych <= ':') goto yy1383; yy1375: YYDEBUG(1375, *YYCURSOR); -#line 1769 "ext/date/lib/parse_date.re" +#line 1766 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -24610,7 +24607,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 24614 "ext/date/lib/parse_date.c" +#line 24611 "" yy1376: YYDEBUG(1376, *YYCURSOR); yyaccept = 33; @@ -24842,7 +24839,7 @@ static int scan(Scanner *s, timelib_tz_get_wrapper tz_get_wrapper) if (yych == ':') goto yy1286; goto yy1329; } -#line 1997 "ext/date/lib/parse_date.re" +#line 1994 "ext/date/lib/parse_date.re" } diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index c40a5c07c9aa..d32be9bfe7be 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -939,12 +939,10 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int { timelib_tzinfo *res; timelib_long retval = 0; - size_t paren_count = 0; *tz_not_found = 0; while (**ptr == ' ' || **ptr == '\t' || **ptr == '(') { - paren_count += **ptr == '('; ++*ptr; } if ((*ptr)[0] == 'G' && (*ptr)[1] == 'M' && (*ptr)[2] == 'T' && ((*ptr)[3] == '+' || (*ptr)[3] == '-')) { @@ -993,9 +991,8 @@ timelib_long timelib_parse_zone(const char **ptr, int *dst, timelib_time *t, int *tz_not_found = (found == 0); retval = offset; } - while (paren_count > 0 && **ptr == ')') { + while (**ptr == ')') { ++*ptr; - paren_count--; } return retval; } diff --git a/ext/date/lib/parse_iso_intervals.c b/ext/date/lib/parse_iso_intervals.c index a9fca1b60941..cdc329431ec4 100644 --- a/ext/date/lib/parse_iso_intervals.c +++ b/ext/date/lib/parse_iso_intervals.c @@ -1,4 +1,4 @@ -/* Generated by re2c 1.0.3 on Mon Sep 15 10:38:16 2025 */ +/* Generated by re2c 1.0.3 on Wed Sep 11 17:29:40 2024 */ #line 1 "ext/date/lib/parse_iso_intervals.re" /* * The MIT License (MIT) @@ -180,7 +180,7 @@ static int scan(Scanner *s) -#line 184 "ext/date/lib/parse_iso_intervals.c" +#line 184 "" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -252,7 +252,7 @@ static int scan(Scanner *s) s->pos = cursor; s->line++; goto std; } -#line 256 "ext/date/lib/parse_iso_intervals.c" +#line 256 "" yy4: YYDEBUG(4, *YYCURSOR); ++YYCURSOR; @@ -263,7 +263,7 @@ static int scan(Scanner *s) add_error(s, "Unexpected character"); goto std; } -#line 267 "ext/date/lib/parse_iso_intervals.c" +#line 267 "" yy6: YYDEBUG(6, *YYCURSOR); ++YYCURSOR; @@ -272,7 +272,7 @@ static int scan(Scanner *s) { goto std; } -#line 276 "ext/date/lib/parse_iso_intervals.c" +#line 276 "" yy8: YYDEBUG(8, *YYCURSOR); yyaccept = 0; @@ -330,7 +330,7 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_PERIOD; } -#line 334 "ext/date/lib/parse_iso_intervals.c" +#line 334 "" yy11: YYDEBUG(11, *YYCURSOR); yych = *++YYCURSOR; @@ -399,7 +399,7 @@ static int scan(Scanner *s) s->have_recurrences = 1; return TIMELIB_PERIOD; } -#line 403 "ext/date/lib/parse_iso_intervals.c" +#line 403 "" yy19: YYDEBUG(19, *YYCURSOR); yych = *++YYCURSOR; @@ -917,7 +917,7 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 921 "ext/date/lib/parse_iso_intervals.c" +#line 921 "" yy91: YYDEBUG(91, *YYCURSOR); yych = *++YYCURSOR; @@ -956,7 +956,7 @@ static int scan(Scanner *s) TIMELIB_DEINIT; return TIMELIB_PERIOD; } -#line 960 "ext/date/lib/parse_iso_intervals.c" +#line 960 "" } #line 321 "ext/date/lib/parse_iso_intervals.re" diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index ef57a7ee783f..a2c976af7ed9 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2025 Derick Rethans + * Copyright (c) 2015-2024 Derick Rethans * Copyright (c) 2018,2021 MongoDB, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202214 -#define TIMELIB_EXTENDED_VERSION 20221401 -#define TIMELIB_ASCII_VERSION "2022.14" +#define TIMELIB_VERSION 202212 +#define TIMELIB_EXTENDED_VERSION 20221201 +#define TIMELIB_ASCII_VERSION "2022.12" #include #include From f045716288af47499fe5c87104e0d3db0570072d Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 15 Sep 2025 22:07:38 +0200 Subject: [PATCH 20/64] Fix incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland array Fixes GH-19839 Closes GH-19851 --- NEWS | 2 ++ Zend/tests/gh19839.phpt | 18 ++++++++++++++++++ Zend/zend_hash.c | 5 ++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh19839.phpt diff --git a/NEWS b/NEWS index 028617dfae40..0891acce266b 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS exception are triggered). (nielsdos) . Fixed bug GH-19653 (Closure named argument unpacking between temporary closures can cause a crash). (nielsdos, Arnaud, Bob) + . Fixed bug GH-19839 (Incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland + array). (ilutov) - Date: . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. diff --git a/Zend/tests/gh19839.phpt b/Zend/tests/gh19839.phpt new file mode 100644 index 000000000000..cc589ce0605f --- /dev/null +++ b/Zend/tests/gh19839.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-19839: Incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland array +--FILE-- + +===DONE=== +--EXPECT-- +===DONE=== diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 07d5bed6d765..fdc05ff8cbfa 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2466,6 +2466,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) target->nTableSize = HT_MIN_SIZE; HT_SET_DATA_ADDR(target, &uninitialized_bucket); } else if (GC_FLAGS(source) & IS_ARRAY_IMMUTABLE) { + ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_HAS_EMPTY_IND)); HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK; target->nTableMask = source->nTableMask; target->nNumUsed = source->nNumUsed; @@ -2482,6 +2483,7 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) memcpy(HT_GET_DATA_ADDR(target), HT_GET_DATA_ADDR(source), HT_USED_SIZE(source)); } } else if (HT_IS_PACKED(source)) { + ZEND_ASSERT(!(HT_FLAGS(source) & HASH_FLAG_HAS_EMPTY_IND)); HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK; target->nTableMask = HT_MIN_MASK; target->nNumUsed = source->nNumUsed; @@ -2501,7 +2503,8 @@ ZEND_API HashTable* ZEND_FASTCALL zend_array_dup(HashTable *source) zend_array_dup_packed_elements(source, target, 1); } } else { - HT_FLAGS(target) = HT_FLAGS(source) & HASH_FLAG_MASK; + /* Indirects are removed during duplication, remove HASH_FLAG_HAS_EMPTY_IND accordingly. */ + HT_FLAGS(target) = HT_FLAGS(source) & (HASH_FLAG_MASK & ~HASH_FLAG_HAS_EMPTY_IND); target->nTableMask = source->nTableMask; target->nNextFreeElement = source->nNextFreeElement; target->nInternalPointer = From 75217c16c89639fe3b01e43d1cdc4a701063347d Mon Sep 17 00:00:00 2001 From: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:05:45 +0200 Subject: [PATCH 21/64] Fix GH-19801: address leak when calling var_dump() with recursion in __debugInfo() (#19837) --- NEWS | 2 ++ .../debug_zval_dump_gh19801_memory_leak.phpt | 32 +++++++++++++++++++ .../var_dump_gh19801_memory_leak.phpt | 30 +++++++++++++++++ ext/standard/var.c | 4 +-- 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt create mode 100644 ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt diff --git a/NEWS b/NEWS index 0891acce266b..b3cdd047e509 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,8 @@ PHP NEWS . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). (nielsdos) . Fixed bug GH-19701 (Serialize/deserialize loses some data). (nielsdos) + . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()). + (alexandre-daubois) - Zip: . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos) diff --git a/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt b/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt new file mode 100644 index 000000000000..8d65cd6d1858 --- /dev/null +++ b/ext/standard/tests/general_functions/debug_zval_dump_gh19801_memory_leak.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-19801 (debug_zval_dump() leak with __debugInfo() that modifies circular references) +--FILE-- +a = null; + gc_collect_cycles(); + return []; + } + }, +]; + +$b = new stdClass; +$b->a = &$a; + +debug_zval_dump($b); +?> +--EXPECTF-- +object(stdClass)#2 (1) refcount(%d){ + ["a"]=> + reference refcount(%d) { + array(1) refcount(%d){ + [0]=> + object(class@anonymous)#1 (0) refcount(%d){ + } + } + } +} diff --git a/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt b/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt new file mode 100644 index 000000000000..f0522916de4e --- /dev/null +++ b/ext/standard/tests/general_functions/var_dump_gh19801_memory_leak.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-19801 (var_dump() memory leak with __debugInfo() that modifies circular references) +--FILE-- +a = null; + gc_collect_cycles(); + return []; + } + }, +]; + +$b = new stdClass; +$b->a = &$a; + +var_dump($b); +?> +--EXPECTF-- +object(stdClass)#2 (1) { + ["a"]=> + &array(1) { + [0]=> + object(class@anonymous)#1 (0) { + } + } +} diff --git a/ext/standard/var.c b/ext/standard/var.c index c6e280d15ab9..795fb366c601 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -139,7 +139,7 @@ PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */ } ZEND_HASH_FOREACH_END(); if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) { GC_UNPROTECT_RECURSION(myht); - GC_DELREF(myht); + GC_DTOR_NO_REF(myht); } if (level > 1) { php_printf("%*c", level-1, ' '); @@ -336,7 +336,7 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */ } ZEND_HASH_FOREACH_END(); if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) { GC_UNPROTECT_RECURSION(myht); - GC_DELREF(myht); + GC_DTOR_NO_REF(myht); } if (level > 1) { php_printf("%*c", level - 1, ' '); From 6eb3faef3bc1df238b824630dbdcd95c27ddb2f8 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 16 Sep 2025 13:39:35 +0200 Subject: [PATCH 22/64] Fix use-of-uninitialized-value in zend_get_arg_offset_by_name() Don't access fbc->op_array.refcount on internal function. Don't attempt to cache ZEND_ACC_USER_ARG_INFO at all, which is only used in zend_get_closure_invoke_method(). This may reuse arg_info from a temporary closure, and hence caching would also be unsafe. Also avoid populating the cache slot for variadic parameters, where the ZEND_ACC_USER_ARG_INFO is set for the same reason. Closes GH-19856 --- Zend/zend_execute.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 4e6339ca901c..d44af38c64c6 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -5072,9 +5072,9 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) || EXPECTED(fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { for (uint32_t i = 0; i < num_args; i++) { - zend_arg_info *arg_info = &fbc->op_array.arg_info[i]; + zend_arg_info *arg_info = &fbc->common.arg_info[i]; if (zend_string_equals(arg_name, arg_info->name)) { - if (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE)) { + if (fbc->type == ZEND_USER_FUNCTION && (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE))) { *cache_slot = unique_id; *(uintptr_t *)(cache_slot + 1) = i; } @@ -5094,7 +5094,10 @@ static zend_always_inline uint32_t zend_get_arg_offset_by_name( } if (fbc->common.fn_flags & ZEND_ACC_VARIADIC) { - if (fbc->type == ZEND_INTERNAL_FUNCTION || !fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE)) { + if ((fbc->type == ZEND_USER_FUNCTION + && (!fbc->op_array.refcount || !(fbc->op_array.fn_flags & ZEND_ACC_CLOSURE))) + || (fbc->type == ZEND_INTERNAL_FUNCTION + && !(fbc->common.fn_flags & ZEND_ACC_USER_ARG_INFO))) { *cache_slot = unique_id; *(uintptr_t *)(cache_slot + 1) = fbc->common.num_args; } From 7a1bb711272540acc880215c51d818cd0c4f61b4 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Fri, 15 Aug 2025 11:06:53 +0200 Subject: [PATCH 23/64] Fix GH-19480: error_log php.ini cannot be unset when open_basedir is configured Since the ini message handlers already check for basedir, we need to drop the basedir check from ini_set. Then we also fix the exceptional case for the empty string: it should bypass the basedir check. Furthermore, there was a regression introduced with the error_log "syslog" check in ddfe269a (inverted check), so we fix that as well. Closes GH-19487 --- NEWS | 2 ++ ext/standard/basic_functions.c | 4 +--- main/main.c | 12 +++++++----- tests/security/error_log_special_values.phpt | 13 +++++++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 tests/security/error_log_special_values.phpt diff --git a/NEWS b/NEWS index b3cdd047e509..ace911f500c4 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,8 @@ PHP NEWS closures can cause a crash). (nielsdos, Arnaud, Bob) . Fixed bug GH-19839 (Incorrect HASH_FLAG_HAS_EMPTY_IND flag on userland array). (ilutov) + . Fixed bug GH-19480 (error_log php.ini cannot be unset when open_basedir is + configured). (nielsdos) - Date: . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index d2a99fccc95f..02b63beb59d0 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2037,10 +2037,8 @@ PHP_FUNCTION(ini_set) #define _CHECK_PATH(var, var_len, ini) php_ini_check_path(var, var_len, ini, sizeof(ini)) /* open basedir check */ if (PG(open_basedir)) { - if (_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "error_log") || - _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.class.path") || + if (_CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.class.path") || _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.home") || - _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "mail.log") || _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "java.library.path") || _CHECK_PATH(ZSTR_VAL(varname), ZSTR_LEN(varname), "vpopmail.directory")) { if (php_check_open_basedir(ZSTR_VAL(new_value_str))) { diff --git a/main/main.c b/main/main.c index 60e970b76ad7..e7797a4f89e4 100644 --- a/main/main.c +++ b/main/main.c @@ -625,12 +625,13 @@ static PHP_INI_MH(OnUpdateErrorLog) { /* Only do the safemode/open_basedir check at runtime */ if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && - new_value && zend_string_equals_literal(new_value, "syslog")) { + new_value && !zend_string_equals_literal(new_value, "syslog") && ZSTR_LEN(new_value) > 0) { if (PG(open_basedir) && php_check_open_basedir(ZSTR_VAL(new_value))) { return FAILURE; } } - OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + char **p = (char **) ZEND_INI_GET_ADDR(); + *p = new_value && ZSTR_LEN(new_value) > 0 ? ZSTR_VAL(new_value) : NULL; return SUCCESS; } /* }}} */ @@ -638,13 +639,14 @@ static PHP_INI_MH(OnUpdateErrorLog) /* {{{ PHP_INI_MH */ static PHP_INI_MH(OnUpdateMailLog) { - /* Only do the safemode/open_basedir check at runtime */ - if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value) { + /* Only do the open_basedir check at runtime */ + if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value && ZSTR_LEN(new_value) > 0) { if (PG(open_basedir) && php_check_open_basedir(ZSTR_VAL(new_value))) { return FAILURE; } } - OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + char **p = (char **) ZEND_INI_GET_ADDR(); + *p = new_value && ZSTR_LEN(new_value) > 0 ? ZSTR_VAL(new_value) : NULL; return SUCCESS; } /* }}} */ diff --git a/tests/security/error_log_special_values.phpt b/tests/security/error_log_special_values.phpt new file mode 100644 index 000000000000..949adb5e2538 --- /dev/null +++ b/tests/security/error_log_special_values.phpt @@ -0,0 +1,13 @@ +--TEST-- +Setting error_log to special values with open_basedir enabled +--INI-- +open_basedir=foo +error_log= +--FILE-- + +--EXPECT-- +string(0) "" +string(6) "syslog" From 933e087843a29f8b1d5c2a62c3081ec04ada5933 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 19 Sep 2025 12:29:46 +0100 Subject: [PATCH 24/64] Fix GH-19885: dba_fetch() overflow on skip argument. close GH-19887 --- NEWS | 3 +++ ext/dba/dba.c | 5 +++++ ext/dba/tests/gh19885.phpt | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 ext/dba/tests/gh19885.phpt diff --git a/NEWS b/NEWS index ace911f500c4..fc3c0662b932 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,9 @@ PHP NEWS . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. (nielsdos) +- DBA: + . Fixed GH-19885 (dba_fetch() overflow on skip argument). (David Carlier) + - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead of the curl_copy_handle() function to clone a CurlHandle. (timwolla) diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 9affb5aa6fc1..1474573f3e4d 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -984,6 +984,11 @@ PHP_FUNCTION(dba_fetch) ZEND_PARSE_PARAMETERS_END(); } + if (ZEND_LONG_EXCEEDS_INT(skip)) { + zend_argument_value_error(3, "must be between %d and %d", INT_MIN, INT_MAX); + RETURN_THROWS(); + } + DBA_FETCH_RESOURCE(info, id); if (key_ht) { diff --git a/ext/dba/tests/gh19885.phpt b/ext/dba/tests/gh19885.phpt new file mode 100644 index 000000000000..987aea4f175a --- /dev/null +++ b/ext/dba/tests/gh19885.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-19885 (dba_fetch() segfault on large skip values) +--EXTENSIONS-- +dba +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; +} + +try { + dba_fetch("https://redirect.github.com/1", $db, PHP_INT_MAX); +} catch (\ValueError $e) { + echo $e->getMessage(), PHP_EOL; +} +// negative skip needs to remain acceptable albeit corrected down the line +var_dump(dba_fetch("https://redirect.github.com/1", $db, -1000000)); +?> +--EXPECTF-- +dba_fetch(): Argument #3 ($skip) must be between -%d and %d +dba_fetch(): Argument #3 ($skip) must be between -%d and %d + +Notice: dba_fetch(): Handler cdb accepts only skip values greater than or equal to zero, using skip=0 in %s on line %d +string(1) "1" From 266cb7d892d65e1ddcacc643853897033558a5d1 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 22 Sep 2025 10:55:59 +0200 Subject: [PATCH 25/64] Fix curl 8.16.0 compilation with zts --- ext/curl/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 67ec5aabc391..2f0181504198 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1178,7 +1178,7 @@ static void _php_curl_set_default_options(php_curl *ch) } #ifdef ZTS - curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1L); #endif } /* }}} */ From a885372a081e76975ce8696e918c35fe1a4864d3 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 23 Sep 2025 14:14:09 +0200 Subject: [PATCH 26/64] Fix more curl 8.16 issues The CURLOPT_FOLLOWLOCATION seems like a gcc bug, where the integer extension of bool to long is lost, but I was unable to reproduce on godbolt.org. --- ext/curl/interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 2f0181504198..bf8703278b5d 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1689,7 +1689,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue lval = zval_get_long(zvalue); if (lval == 1) { php_error_docref(NULL, E_NOTICE, "CURLOPT_SSL_VERIFYHOST no longer accepts the value 1, value 2 will be used instead"); - error = curl_easy_setopt(ch->cp, option, 2); + error = curl_easy_setopt(ch->cp, option, 2L); break; } ZEND_FALLTHROUGH; @@ -2260,7 +2260,7 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue case CURLOPT_FOLLOWLOCATION: lval = zend_is_true(zvalue); - error = curl_easy_setopt(ch->cp, option, lval); + error = curl_easy_setopt(ch->cp, option, (long) lval); break; case CURLOPT_HEADERFUNCTION: From c6a6cb79f9ea30d97602fd5d01fe2c1ad9659a4f Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 22 Sep 2025 19:46:17 +0200 Subject: [PATCH 27/64] [skip ci] Skip php_cli_server_pdeathsig.phpt if pgrep is missing Fixes GH-19911 Closes GH-19923 --- sapi/cli/tests/php_cli_server_pdeathsig.phpt | 1 + 1 file changed, 1 insertion(+) diff --git a/sapi/cli/tests/php_cli_server_pdeathsig.phpt b/sapi/cli/tests/php_cli_server_pdeathsig.phpt index 8b70bbcad492..66a76a84ccaf 100644 --- a/sapi/cli/tests/php_cli_server_pdeathsig.phpt +++ b/sapi/cli/tests/php_cli_server_pdeathsig.phpt @@ -9,6 +9,7 @@ if (!(str_contains(PHP_OS, 'Linux') || str_contains(PHP_OS, 'FreeBSD'))) { die('skip PDEATHSIG is only supported on Linux and FreeBSD'); } if (@file_exists('/.dockerenv')) die("skip Broken in Docker"); +if (!shell_exec("which pgrep")) die("skip Missing pgrep command"); ?> --FILE-- Date: Tue, 23 Sep 2025 23:41:42 +0200 Subject: [PATCH 28/64] [skip ci] Add 8.6 to nightly_matrix.php --- .github/nightly_matrix.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index 311176ef5e53..846c60e8fd56 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -1,7 +1,8 @@ 'master', 'version' => [8, 5]], + ['ref' => 'master', 'version' => [8, 6]], + ['ref' => 'PHP-8.5', 'version' => [8, 5]], ['ref' => 'PHP-8.4', 'version' => [8, 4]], ['ref' => 'PHP-8.3', 'version' => [8, 3]], ['ref' => 'PHP-8.2', 'version' => [8, 2]], From f9dc073b04b4b2bcfd46d39f140d2747ac5f8c2f Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 27 Sep 2025 12:43:28 +0200 Subject: [PATCH 29/64] Add stream filter convert.* tests (#19976) The convert.* filters are quite untested so this tries to improve it. Closes GH-19976 --- ext/standard/tests/filters/convert.phpt | 130 ++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 ext/standard/tests/filters/convert.phpt diff --git a/ext/standard/tests/filters/convert.phpt b/ext/standard/tests/filters/convert.phpt new file mode 100644 index 000000000000..a99579b5dd8f --- /dev/null +++ b/ext/standard/tests/filters/convert.phpt @@ -0,0 +1,130 @@ +--TEST-- +convert stream filter tests +--FILE-- + 20, 'line-break-chars' => "\n"); +test_roundtrip("Long text that will be wrapped", "convert.base64-encode", "convert.base64-decode", $opts); + +$opts2 = array('binary' => true); +test_roundtrip("Text\t\r\n", "convert.quoted-printable-encode", "convert.quoted-printable-decode", $opts2); + +$fp = tmpfile(); +fwrite($fp, "Test"); +rewind($fp); +stream_filter_prepend($fp, 'convert.base64-encode', STREAM_FILTER_READ); +$result = stream_get_contents($fp); +fclose($fp); +var_dump($result === base64_encode("Test")); + +?> +--EXPECTF-- +Filter: convert.base64-encode +Original: Hello World! +Encoded: SGVsbG8gV29ybGQh +Decoded: Hello World! +bool(true) + +Filter: convert.base64-encode +Original (hex): 414243ff +Encoded: QUJD/w== +Decoded (hex): 414243ff +bool(true) + +Filter: convert.base64-encode +Original: +Encoded: +Decoded: +bool(true) + +Filter: convert.base64-encode +Original: A +Encoded: QQ== +Decoded: A +bool(true) + +Filter: convert.quoted-printable-encode +Original: Hello World! +Encoded: Hello World! +Decoded: Hello World! +bool(true) + +Filter: convert.quoted-printable-encode +Original: Line1 +Line2 +Encoded: Line1=0D=0ALine2 +Decoded: Line1 +Line2 +bool(true) + +Filter: convert.base64-encode +Original: Long text that will be wrapped +Encoded: TG9uZyB0ZXh0IHRoYXQg +d2lsbCBiZSB3cmFwcGVk +Decoded: Long text that will be wrapped +bool(true) + +Filter: convert.quoted-printable-encode +Original: Text + +Encoded: Text=09=0D=0A +Decoded: Text + +bool(true) + +bool(true) From 107075605db6f1b15ce275e345d1c6de04a464b0 Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Sun, 28 Sep 2025 09:54:13 +0530 Subject: [PATCH 30/64] Change master branch check to 8.6 --- .github/scripts/windows/find-target-branch.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/windows/find-target-branch.bat b/.github/scripts/windows/find-target-branch.bat index a0b47f248894..44b0bde1ec8c 100644 --- a/.github/scripts/windows/find-target-branch.bat +++ b/.github/scripts/windows/find-target-branch.bat @@ -3,6 +3,6 @@ for /f "usebackq tokens=3" %%i in (`findstr PHP_MAJOR_VERSION main\php_version.h`) do set BRANCH=%%i for /f "usebackq tokens=3" %%i in (`findstr PHP_MINOR_VERSION main\php_version.h`) do set BRANCH=%BRANCH%.%%i -if /i "%BRANCH%" equ "8.5" ( +if /i "%BRANCH%" equ "8.6" ( set BRANCH=master ) From d94846c3b4d6cfc2564b59aebcb9abe6b347ace6 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:18:03 +0200 Subject: [PATCH 31/64] Fix GH-19988: zend_string_init with NULL pointer in simplexml (UB) Normally, simplexml cannot import document nodes, but xsl allows to circumvent this. A document does not have a name, so we return the empty string in that case. While we could add an explicit check, we might as well switch the macro to a form that would be more optimal anyway as many tag names can be single characters. The test was added in xsl because adding it in simplexml would break out-of-tree builds of simplexml. Closes GH-19990. --- NEWS | 4 ++++ ext/simplexml/simplexml.c | 2 +- ext/xsl/tests/gh19988.phpt | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 ext/xsl/tests/gh19988.phpt diff --git a/NEWS b/NEWS index fc3c0662b932..249ef8f98ed8 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ PHP NEWS of the curl_copy_handle() function to clone a CurlHandle. (timwolla) . Fix curl build failure on macOS+curl 8.16. (nielsdos) +- SimpleXML: + . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). + (nielsdos) + - Soap: . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 11f497a6673e..6eae5650340c 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1661,7 +1661,7 @@ PHP_METHOD(SimpleXMLElement, getName) node = php_sxe_get_first_node(sxe, node); if (node) { namelen = xmlStrlen(node->name); - RETURN_STRINGL((char*)node->name, namelen); + RETURN_STRINGL_FAST((const char *) node->name, namelen); } else { RETURN_EMPTY_STRING(); } diff --git a/ext/xsl/tests/gh19988.phpt b/ext/xsl/tests/gh19988.phpt new file mode 100644 index 000000000000..174af282f9c0 --- /dev/null +++ b/ext/xsl/tests/gh19988.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-19988 (zend_string_init with NULL pointer in simplexml (UB)) +--EXTENSIONS-- +simplexml +xsl +--CREDITS-- +YuanchengJiang +--FILE-- +load(__DIR__ . '/53965/collection.xsl'); +$processor->importStylesheet($dom); +$result = $processor->transformToDoc($sxe, SimpleXMLElement::class); +var_dump($result->getName()); +?> +--EXPECT-- +string(0) "" From 190f427198b2e789f33f8ba8a225a9140458786a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:05:33 +0200 Subject: [PATCH 32/64] Fix NEWS order --- NEWS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 249ef8f98ed8..3955fab9ed22 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,11 @@ PHP NEWS . Fixed bug GH-19480 (error_log php.ini cannot be unset when open_basedir is configured). (nielsdos) +- Curl: + . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead + of the curl_copy_handle() function to clone a CurlHandle. (timwolla) + . Fix curl build failure on macOS+curl 8.16. (nielsdos) + - Date: . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. (nielsdos) @@ -22,11 +27,6 @@ PHP NEWS - DBA: . Fixed GH-19885 (dba_fetch() overflow on skip argument). (David Carlier) -- Curl: - . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead - of the curl_copy_handle() function to clone a CurlHandle. (timwolla) - . Fix curl build failure on macOS+curl 8.16. (nielsdos) - - SimpleXML: . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). (nielsdos) From 3ee56f68edb2d1c2a3dc3713d499af42f37b00ad Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 23 Sep 2025 19:02:14 +0100 Subject: [PATCH 33/64] Fix GH-19932: Zip::setEncryptionName()/setEncryptionIndex() memory leak. On successive usage, the password is copied as much but the older address is never freed. Thus, we are hinting a password reset to address it. close GH-19936 --- NEWS | 2 ++ ext/zip/php_zip.c | 10 ++++++++++ ext/zip/tests/gh19932.phpt | 25 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 ext/zip/tests/gh19932.phpt diff --git a/NEWS b/NEWS index 3955fab9ed22..26860c58ee94 100644 --- a/NEWS +++ b/NEWS @@ -43,6 +43,8 @@ PHP NEWS - Zip: . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos) + . Fixed bug GH-19932 (Memory leak in zip setEncryptionName()/setEncryptionIndex()). + (David Carlier) 25 Sep 2025, PHP 8.3.26 diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 3613fb0f7ca7..552d3a7571de 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -2380,6 +2380,11 @@ PHP_METHOD(ZipArchive, setEncryptionName) RETURN_FALSE; } + if (UNEXPECTED(zip_file_set_encryption(intern, idx, ZIP_EM_NONE, NULL) < 0)) { + php_error_docref(NULL, E_WARNING, "password reset failed"); + RETURN_FALSE; + } + if (zip_file_set_encryption(intern, idx, (zip_uint16_t)method, password)) { RETURN_FALSE; } @@ -2403,6 +2408,11 @@ PHP_METHOD(ZipArchive, setEncryptionIndex) ZIP_FROM_OBJECT(intern, self); + if (UNEXPECTED(zip_file_set_encryption(intern, index, ZIP_EM_NONE, NULL) < 0)) { + php_error_docref(NULL, E_WARNING, "password reset failed"); + RETURN_FALSE; + } + if (zip_file_set_encryption(intern, index, (zip_uint16_t)method, password)) { RETURN_FALSE; } diff --git a/ext/zip/tests/gh19932.phpt b/ext/zip/tests/gh19932.phpt new file mode 100644 index 000000000000..760fa1c9e766 --- /dev/null +++ b/ext/zip/tests/gh19932.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-19932 (ZipArchive::setEncryptionName()/setEncryptionIndex() memory leak) +--EXTENSIONS-- +zip +--SKIPIF-- + +--FILE-- +open(__DIR__ . "/gh19932.zip", ZipArchive::CREATE); +$zip->addFromString("test.txt", "test"); +$zip->setEncryptionName("test.txt", ZipArchive::EM_AES_256, "password"); +$zip->setEncryptionName("test.txt", ZipArchive::EM_AES_256, "password"); +$zip->setEncryptionIndex("0", ZipArchive::EM_AES_256, "password"); +$zip->setEncryptionIndex("0", ZipArchive::EM_AES_256, "password"); +$zip->close(); +echo "OK"; +?> +--CLEAN-- + +--EXPECT-- +OK + From 93bac8cb1a7230ac9d34a7cb8f392aeaa621723d Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 22 Sep 2025 19:02:46 +0100 Subject: [PATCH 34/64] Fix GH-19922: gzopen() double free close GH-19924 --- NEWS | 3 +++ ext/zlib/tests/gh19922.phpt | 12 ++++++++++++ main/streams/streams.c | 9 +-------- 3 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 ext/zlib/tests/gh19922.phpt diff --git a/NEWS b/NEWS index 26860c58ee94..a7f5149c5e21 100644 --- a/NEWS +++ b/NEWS @@ -46,6 +46,9 @@ PHP NEWS . Fixed bug GH-19932 (Memory leak in zip setEncryptionName()/setEncryptionIndex()). (David Carlier) +- Zlib: + . Fixed bug GH-19922 (Double free on gzopen). (David Carlier) + 25 Sep 2025, PHP 8.3.26 - Core: diff --git a/ext/zlib/tests/gh19922.phpt b/ext/zlib/tests/gh19922.phpt new file mode 100644 index 000000000000..71644512e665 --- /dev/null +++ b/ext/zlib/tests/gh19922.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-19922 (gzopen double free on debug build and unseekable stream) +--EXTENSIONS-- +zlib +--FILE-- + +--EXPECTF-- + +Warning: gzopen(php://output): could not make seekable - php://output in %s on line %d +bool(false) diff --git a/main/streams/streams.c b/main/streams/streams.c index 7a1b52110825..6dc073cd0baa 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2219,7 +2219,6 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod int persistent = options & STREAM_OPEN_PERSISTENT; zend_string *path_str = NULL; zend_string *resolved_path = NULL; - char *copy_of_path = NULL; if (opened_path) { if (options & STREAM_OPEN_FOR_ZEND_STREAM) { @@ -2296,8 +2295,7 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod if (stream->orig_path) { pefree(stream->orig_path, persistent); } - copy_of_path = pestrdup(path, persistent); - stream->orig_path = copy_of_path; + stream->orig_path = pestrdup(path, persistent); #if ZEND_DEBUG stream->open_filename = __zend_orig_filename ? __zend_orig_filename : __zend_filename; stream->open_lineno = __zend_orig_lineno ? __zend_orig_lineno : __zend_lineno; @@ -2356,11 +2354,6 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod } } php_stream_tidy_wrapper_error_log(wrapper); -#if ZEND_DEBUG - if (stream == NULL && copy_of_path != NULL) { - pefree(copy_of_path, persistent); - } -#endif if (resolved_path) { zend_string_release_ex(resolved_path, 0); } From e029f8f45b6d3f1a468d5e8d476e99c01fffdada Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 25 Sep 2025 19:49:38 +0100 Subject: [PATCH 35/64] Fix GH-19955: imagefttext() memory leak close GH-19968 --- NEWS | 3 +++ ext/gd/libgd/gdkanji.c | 2 ++ ext/gd/tests/gh19955.phpt | 15 +++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 ext/gd/tests/gh19955.phpt diff --git a/NEWS b/NEWS index a7f5149c5e21..58d9ebc69ad0 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,9 @@ PHP NEWS - DBA: . Fixed GH-19885 (dba_fetch() overflow on skip argument). (David Carlier) +- GD: + . FIxed GH-19955 (imagefttext() memory leak). (David Carlier) + - SimpleXML: . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). (nielsdos) diff --git a/ext/gd/libgd/gdkanji.c b/ext/gd/libgd/gdkanji.c index 21bc2280982a..ef769f89badd 100644 --- a/ext/gd/libgd/gdkanji.c +++ b/ext/gd/libgd/gdkanji.c @@ -368,6 +368,8 @@ do_convert (unsigned char *to, unsigned char *from, const char *code) else error ("something happen"); strcpy ((char *) to, (const char *) from); + if (iconv_close (cd) != 0) + error ("iconv_close() error"); return; } diff --git a/ext/gd/tests/gh19955.phpt b/ext/gd/tests/gh19955.phpt new file mode 100644 index 000000000000..a4b58e403cf4 --- /dev/null +++ b/ext/gd/tests/gh19955.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-19955: (imagefttext() memory leak) +--EXTENSIONS-- +gd +--CREDITS-- +YuanchengJiang +--FILE-- + +--EXPECT-- +OK From 21c2c07a249ff03d0d1dff3b06545dbd3322e86f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:06:21 +0200 Subject: [PATCH 36/64] Fix GH-19998: ext/standard/tests/file/bug46347.phpt sometimes fails: racy in parallel The same test file name is already used in parse_ini_file.phpt. Closes GH-20000. --- ext/standard/tests/file/bug46347.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/tests/file/bug46347.phpt b/ext/standard/tests/file/bug46347.phpt index 903a6e35cc2b..e337ade9eb8f 100644 --- a/ext/standard/tests/file/bug46347.phpt +++ b/ext/standard/tests/file/bug46347.phpt @@ -8,14 +8,14 @@ $str = <<< EOF part1.*.part2 = 1 EOF; -$file = __DIR__ . '/parse.ini'; +$file = __DIR__ . '/bug46347.ini'; file_put_contents($file, $str); var_dump(parse_ini_file($file)); ?> --CLEAN-- --EXPECT-- array(1) { From 6db12e7cd89fa4643f42a884e8323a3aef1b52cc Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 7 Sep 2025 21:08:10 +0200 Subject: [PATCH 37/64] Fix bug #67563: mysqli compiled with mysqlnd does not take ipv6 adress as parameter In the past, when libmysqlclient could be used, it accepted ipv6 addresses as hostname without enclosing it first in brackets. However, in mysqlnd this never worked. In the past this caused a discrepancy between the two implementations. Nowadays, mysqli only works with mysqlnd so we don't even have to cater to libmysqlclient. However, a plain ipv6 address should still work as a hostname. Also for people migrating to newer PHP versions it's nice if this keeps working. The solution is to check if we're dealing with an ipv6 address not yet enclosed in brackets. In that case we add the brackets automatically. Closes GH-19750. --- NEWS | 4 ++++ ext/mysqli/tests/bug67563.phpt | 40 ++++++++++++++++++++++++++++++++ ext/mysqlnd/mysqlnd_connection.c | 18 +++++++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 ext/mysqli/tests/bug67563.phpt diff --git a/NEWS b/NEWS index 58d9ebc69ad0..067cceab3be1 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,10 @@ PHP NEWS - GD: . FIxed GH-19955 (imagefttext() memory leak). (David Carlier) +- MySQLnd: + . Fixed bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress + as parameter). (nielsdos) + - SimpleXML: . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). (nielsdos) diff --git a/ext/mysqli/tests/bug67563.phpt b/ext/mysqli/tests/bug67563.phpt new file mode 100644 index 000000000000..72a51ecdccd2 --- /dev/null +++ b/ext/mysqli/tests/bug67563.phpt @@ -0,0 +1,40 @@ +--TEST-- +Fix bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress as parameter) +--EXTENSIONS-- +mysqli +--SKIPIF-- + +--INI-- +max_execution_time=240 +--FILE-- +close(); + } +} + +print "done!"; +?> +--EXPECT-- +done! diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index d46029889fad..a97f2820a319 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -513,6 +513,16 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn, } /* }}} */ +/* ipv6 addresses have at least two colons, which is how we can differentiate between domain names and addresses */ +static bool mysqlnd_fast_is_ipv6_address(const char *s) +{ + const char *first_colon = strchr(s, ':'); + if (!first_colon) { + return false; + } + return strchr(first_colon + 1, ':') != NULL; +} + /* {{{ mysqlnd_conn_data::get_scheme */ static MYSQLND_STRING MYSQLND_METHOD(mysqlnd_conn_data, get_scheme)(MYSQLND_CONN_DATA * conn, MYSQLND_CSTRING hostname, MYSQLND_CSTRING *socket_or_pipe, unsigned int port, bool * unix_socket, bool * named_pipe) @@ -542,7 +552,13 @@ MYSQLND_METHOD(mysqlnd_conn_data, get_scheme)(MYSQLND_CONN_DATA * conn, MYSQLND_ if (!port) { port = 3306; } - transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s:%u", hostname.s, port); + + /* ipv6 addresses are in the format [address]:port */ + if (hostname.s[0] != '[' && mysqlnd_fast_is_ipv6_address(hostname.s)) { + transport.l = mnd_sprintf(&transport.s, 0, "tcp://[%s]:%u", hostname.s, port); + } else { + transport.l = mnd_sprintf(&transport.s, 0, "tcp://%s:%u", hostname.s, port); + } } DBG_INF_FMT("transport=%s", transport.s? transport.s:"OOM"); DBG_RETURN(transport); From d9ee711baf7ce799b3b1cd8d7c726aa62bbb878d Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 30 Sep 2025 15:21:47 +0200 Subject: [PATCH 38/64] Fix NEWS formatting --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 067cceab3be1..d1d7335c132e 100644 --- a/NEWS +++ b/NEWS @@ -28,7 +28,7 @@ PHP NEWS . Fixed GH-19885 (dba_fetch() overflow on skip argument). (David Carlier) - GD: - . FIxed GH-19955 (imagefttext() memory leak). (David Carlier) + . Fixed GH-19955 (imagefttext() memory leak). (David Carlier) - MySQLnd: . Fixed bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress From c617afd6d6e46ebbb896bab96761df2168be82d1 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 30 Sep 2025 16:55:33 +0200 Subject: [PATCH 39/64] Fix GH-20009: XMLReader leak on RelaxNG schema failure Closes GH-20014. --- NEWS | 3 +++ ext/xmlreader/php_xmlreader.c | 1 + 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index d1d7335c132e..c7765950f8cc 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,9 @@ PHP NEWS . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()). (alexandre-daubois) +- XMLReader: + . Fixed bug GH-20009 (XMLReader leak on RelaxNG schema failure). (nielsdos) + - Zip: . Fixed bug GH-19688 (Remove pattern overflow in zip addGlob()). (nielsdos) . Fixed bug GH-19932 (Memory leak in zip setEncryptionName()/setEncryptionIndex()). diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index dca1898f1c04..7a50b660fb59 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -508,6 +508,7 @@ static void php_xmlreader_set_relaxng_schema(INTERNAL_FUNCTION_PARAMETERS, int t RETURN_TRUE; } else { + xmlRelaxNGFree(schema); php_error_docref(NULL, E_WARNING, "Schema contains errors"); RETURN_FALSE; } From 7c859268c0306ccf237d18ef8cae97e60b1ac278 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 30 Sep 2025 10:48:42 +0200 Subject: [PATCH 40/64] Fix memory leak and invalid continuation after tar header writing fails Closes GH-20003. --- NEWS | 4 ++ ext/phar/tar.c | 17 ++++---- .../tests/tar_flush_too_long_filename.phpt | 41 +++++++++++++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 ext/phar/tests/tar_flush_too_long_filename.phpt diff --git a/NEWS b/NEWS index c7765950f8cc..9f32973e94a2 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,10 @@ PHP NEWS . Fixed bug #67563 (mysqli compiled with mysqlnd does not take ipv6 adress as parameter). (nielsdos) +- Phar: + . Fix memory leak and invalid continuation after tar header writing fails. + (nielsdos) + - SimpleXML: . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). (nielsdos) diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 687ca34c173c..e675b8694321 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -1211,7 +1211,16 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int } zend_hash_apply_with_argument(&phar->manifest, phar_tar_writeheaders, (void *) &pass); - /* TODO: memory leak and incorrect continuation if phar_tar_writeheaders fails? */ + + if (error && *error) { + if (closeoldfile) { + php_stream_close(oldfile); + } + + /* on error in the hash iterator above, error is set */ + php_stream_close(newfile); + return EOF; + } /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */ if (!phar->is_data || phar->sig_flags) { @@ -1294,12 +1303,6 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int php_stream_close(oldfile); } - /* on error in the hash iterator above, error is set */ - if (error && *error) { - php_stream_close(newfile); - return EOF; - } - if (phar->fp && pass.free_fp) { php_stream_close(phar->fp); } diff --git a/ext/phar/tests/tar_flush_too_long_filename.phpt b/ext/phar/tests/tar_flush_too_long_filename.phpt new file mode 100644 index 000000000000..be18f5e48168 --- /dev/null +++ b/ext/phar/tests/tar_flush_too_long_filename.phpt @@ -0,0 +1,41 @@ +--TEST-- +Tar flush with too long file name +--EXTENSIONS-- +phar +--SKIPIF-- + +--INI-- +phar.require_hash=0 +--FILE-- +addEmptyDir('blah1/'); +$phar->setSignatureAlgorithm(Phar::OPENSSL, "randomcrap"); +try { + $phar->addEmptyDir('blah2/' . str_repeat('X', 1000)); +} catch (PharException $e) { + echo $e->getMessage(); +} + +?> +--CLEAN-- + +--EXPECTF-- +tar-based phar "%s" cannot be created, filename "%s" is too long for tar file format From b7fdfb71478f55d6ebf6c812c467ed260ad26d80 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 26 Jul 2025 17:22:28 +0200 Subject: [PATCH 41/64] Fix GH-19248: Use strerror_r instead of strerror in main Or on Windows it is going to use either FormatMessageW or strerror_s for compatibility with previous error messages. It also needs to accomodate for GNU and BSD versions of strerror_r returning different type. Closes GH-19251 --- NEWS | 4 ++ main/network.c | 76 +++++++++++++++++++++++++++++++----- main/php_network.h | 5 +++ main/rfc1867.c | 3 +- main/streams/plain_wrapper.c | 47 +++++++++++++++------- main/streams/streams.c | 3 +- main/streams/xp_socket.c | 3 +- 7 files changed, 114 insertions(+), 27 deletions(-) diff --git a/NEWS b/NEWS index 9f32973e94a2..e60af85379c8 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,10 @@ PHP NEWS . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()). (alexandre-daubois) +- Streams: + . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). + (Jakub Zelenka) + - XMLReader: . Fixed bug GH-20009 (XMLReader leak on RelaxNG schema failure). (nielsdos) diff --git a/main/network.c b/main/network.c index 8de81a6271a2..7102dad20798 100644 --- a/main/network.c +++ b/main/network.c @@ -1052,6 +1052,28 @@ PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr) } /* }}} */ +#ifdef PHP_WIN32 +char *php_socket_strerror_s(long err, char *buf, size_t bufsize) +{ + if (buf == NULL) { + char ebuf[1024]; + errno_t res = strerror_s(ebuf, sizeof(ebuf), err); + if (res == 0) { + buf = estrdup(ebuf); + } else { + buf = estrdup("Unknown error"); + } + } else { + errno_t res = strerror_s(buf, bufsize, err); + if (res != 0) { + strncpy(buf, "Unknown error", bufsize); + buf[bufsize?(bufsize-1):0] = 0; + } + } + return buf; +} +#endif + /* Given a socket error code, if buf == NULL: * emallocs storage for the error message and returns * else @@ -1061,16 +1083,40 @@ PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr) PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize) { #ifndef PHP_WIN32 - char *errstr; - - errstr = strerror(err); +# ifdef HAVE_STRERROR_R + if (buf == NULL) { + char ebuf[1024]; +# ifdef STRERROR_R_CHAR_P + char *errstr = strerror_r(err, ebuf, sizeof(ebuf)); + buf = estrdup(errstr); +# else + errno_t res = strerror_r(err, ebuf, sizeof(ebuf)); + if (res == 0) { + buf = estrdup(ebuf); + } else { + buf = estrdup("Unknown error"); + } +# endif + } else { +# ifdef STRERROR_R_CHAR_P + buf = strerror_r(err, buf, bufsize); +# else + errno_t res = strerror_r(err, buf, bufsize); + if (res != 0) { + strncpy(buf, "Unknown error", bufsize); + buf[bufsize?(bufsize-1):0] = 0; + } +# endif + } +# else + char *errstr = strerror(err); if (buf == NULL) { buf = estrdup(errstr); } else { strncpy(buf, errstr, bufsize); buf[bufsize?(bufsize-1):0] = 0; } - return buf; +# endif #else char *sysbuf = php_win32_error_to_msg(err); if (!sysbuf[0]) { @@ -1085,9 +1131,8 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize) } php_win32_error_msg_free(sysbuf); - - return buf; #endif + return buf; } /* }}} */ @@ -1095,9 +1140,22 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize) PHPAPI zend_string *php_socket_error_str(long err) { #ifndef PHP_WIN32 - char *errstr; - - errstr = strerror(err); +# ifdef HAVE_STRERROR_R + char ebuf[1024]; +# ifdef STRERROR_R_CHAR_P + char *errstr = strerror_r(err, ebuf, sizeof(ebuf)); +# else + const char *errstr; + errno_t res = strerror_r(err, ebuf, sizeof(ebuf)); + if (res == 0) { + errstr = ebuf; + } else { + errstr = "Unknown error"; + } +# endif +# else + char *errstr = strerror(err); +# endif return zend_string_init(errstr, strlen(errstr), 0); #else zend_string *ret; diff --git a/main/php_network.h b/main/php_network.h index 6fc210b56837..6b6e486fe48f 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -66,6 +66,11 @@ * unless buf is not NULL. * Also works sensibly for win32 */ BEGIN_EXTERN_C() +#ifdef PHP_WIN32 +char *php_socket_strerror_s(long err, char *buf, size_t bufsize); +#else +#define php_socket_strerror_s php_socket_strerror +#endif PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize); PHPAPI zend_string *php_socket_error_str(long err); END_EXTERN_C() diff --git a/main/rfc1867.c b/main/rfc1867.c index cbdf8aaa07c5..43c4185677a4 100644 --- a/main/rfc1867.c +++ b/main/rfc1867.c @@ -1038,7 +1038,8 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */ if (wlen == (size_t)-1) { /* write failed */ #if DEBUG_FILE_UPLOAD - sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno)); + char errstr[256]; + sapi_module.sapi_error(E_NOTICE, "write() failed - %s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); #endif cancel_upload = PHP_UPLOAD_ERROR_F; } else if (wlen < blen) { diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 1d5b7cfdac40..9ac049f74684 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -368,7 +368,9 @@ static ssize_t php_stdiop_write(php_stream *stream, const char *buf, size_t coun return bytes_written; } if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { - php_error_docref(NULL, E_NOTICE, "Write of %zu bytes failed with errno=%d %s", count, errno, strerror(errno)); + char errstr[256]; + php_error_docref(NULL, E_NOTICE, "Write of %zu bytes failed with errno=%d %s", + count, errno, php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } } else { @@ -444,7 +446,9 @@ static ssize_t php_stdiop_read(php_stream *stream, char *buf, size_t count) /* TODO: Should this be treated as a proper error or not? */ } else { if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { - php_error_docref(NULL, E_NOTICE, "Read of %zu bytes failed with errno=%d %s", count, errno, strerror(errno)); + char errstr[256]; + php_error_docref(NULL, E_NOTICE, "Read of %zu bytes failed with errno=%d %s", + count, errno, php_socket_strerror_s(errno, errstr, sizeof(errstr))); } /* TODO: Remove this special-case? */ @@ -1278,7 +1282,9 @@ static int php_plain_files_unlink(php_stream_wrapper *wrapper, const char *url, ret = VCWD_UNLINK(url); if (ret == -1) { if (options & REPORT_ERRORS) { - php_error_docref1(NULL, url, E_WARNING, "%s", strerror(errno)); + char errstr[256]; + php_error_docref1(NULL, url, E_WARNING, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1324,6 +1330,7 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f if (ret == -1) { #ifndef PHP_WIN32 + char errstr[256]; # ifdef EXDEV if (errno == EXDEV) { zend_stat_t sb; @@ -1344,7 +1351,8 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f * access to the file in the meantime. */ if (VCWD_CHOWN(url_to, sb.st_uid, sb.st_gid)) { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); + php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); if (errno != EPERM) { success = 0; } @@ -1352,7 +1360,8 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f if (success) { if (VCWD_CHMOD(url_to, sb.st_mode)) { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); + php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); if (errno != EPERM) { success = 0; } @@ -1363,10 +1372,12 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f VCWD_UNLINK(url_from); } } else { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); + php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); } } else { - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); + php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); } # if !defined(ZTS) && !defined(TSRM_WIN32) umask(oldmask); @@ -1379,7 +1390,8 @@ static int php_plain_files_rename(php_stream_wrapper *wrapper, const char *url_f #ifdef PHP_WIN32 php_win32_docref2_from_error(GetLastError(), url_from, url_to); #else - php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", strerror(errno)); + php_error_docref2(NULL, url_from, url_to, E_WARNING, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); #endif return 0; } @@ -1449,11 +1461,12 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i if (!p) { p = buf; } + char errstr[256]; while (true) { int ret = VCWD_MKDIR(buf, (mode_t) mode); if (ret < 0 && errno != EEXIST) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); + php_error_docref(NULL, E_WARNING, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1473,7 +1486,7 @@ static int php_plain_files_mkdir(php_stream_wrapper *wrapper, const char *dir, i /* issue a warning to client when the last directory was created failed */ if (ret < 0) { if (options & REPORT_ERRORS) { - php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); + php_error_docref(NULL, E_WARNING, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1492,15 +1505,16 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, const char *url, i return 0; } + char errstr[256]; #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { - php_error_docref1(NULL, url, E_WARNING, "%s", strerror(ENOENT)); + php_error_docref1(NULL, url, E_WARNING, "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } #endif if (VCWD_RMDIR(url) < 0) { - php_error_docref1(NULL, url, E_WARNING, "%s", strerror(errno)); + php_error_docref1(NULL, url, E_WARNING, "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } @@ -1519,10 +1533,11 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url #endif mode_t mode; int ret = 0; + char errstr[256]; #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { - php_error_docref1(NULL, url, E_WARNING, "%s", strerror(ENOENT)); + php_error_docref1(NULL, url, E_WARNING, "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } #endif @@ -1541,7 +1556,8 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url if (VCWD_ACCESS(url, F_OK) != 0) { FILE *file = VCWD_FOPEN(url, "w"); if (file == NULL) { - php_error_docref1(NULL, url, E_WARNING, "Unable to create file %s because %s", url, strerror(errno)); + php_error_docref1(NULL, url, E_WARNING, "Unable to create file %s because %s", url, + php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } fclose(file); @@ -1584,7 +1600,8 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url return 0; } if (ret == -1) { - php_error_docref1(NULL, url, E_WARNING, "Operation failed: %s", strerror(errno)); + php_error_docref1(NULL, url, E_WARNING, "Operation failed: %s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } php_clear_stat_cache(0, NULL, 0); diff --git a/main/streams/streams.c b/main/streams/streams.c index 6dc073cd0baa..46fd85e05e35 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -203,7 +203,8 @@ static void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const free_msg = 1; } else { if (wrapper == &php_plain_files_wrapper) { - msg = strerror(errno); /* TODO: not ts on linux */ + char errstr[256]; + msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); } else { msg = "operation failed"; } diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index b1d89bc44cb2..ef07f5f48660 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -674,9 +674,10 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * if (sock->socket == SOCK_ERR) { if (xparam->want_errortext) { + char errstr[256]; xparam->outputs.error_text = strpprintf(0, "Failed to create unix%s socket %s", stream->ops == &php_stream_unix_socket_ops ? "" : "datagram", - strerror(errno)); + php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return -1; } From 9fc14a90c6d16f447d50612e0626fbcefcc89343 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:24:58 +0200 Subject: [PATCH 42/64] Fix GH-16319: protect fiber backtrace with null filename from crashing (#19973) --- ext/zend_test/observer.c | 4 +- .../tests/observer_fiber_backtrace_crash.phpt | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 ext/zend_test/tests/observer_fiber_backtrace_crash.phpt diff --git a/ext/zend_test/observer.c b/ext/zend_test/observer.c index 9d0fb27c8a55..bff1d6ff9342 100644 --- a/ext/zend_test/observer.c +++ b/ext/zend_test/observer.c @@ -155,7 +155,7 @@ static void observer_show_init(zend_function *fbc) php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->common.function_name)); } } else { - php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->op_array.filename)); + php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", fbc->op_array.filename ? ZSTR_VAL(fbc->op_array.filename) : "[no active file]"); } } @@ -178,7 +178,7 @@ static void observer_show_init_backtrace(zend_execute_data *execute_data) php_printf("%*s%s()\n", indent, "", ZSTR_VAL(fbc->common.function_name)); } } else { - php_printf("%*s{main} %s\n", indent, "", ZSTR_VAL(fbc->op_array.filename)); + php_printf("%*s{main} %s\n", indent, "", fbc->op_array.filename ? ZSTR_VAL(fbc->op_array.filename) : "[no active file]"); } } while ((ex = ex->prev_execute_data) != NULL); php_printf("%*s-->\n", 2 * ZT_G(observer_nesting_depth), ""); diff --git a/ext/zend_test/tests/observer_fiber_backtrace_crash.phpt b/ext/zend_test/tests/observer_fiber_backtrace_crash.phpt new file mode 100644 index 000000000000..f19005179ac2 --- /dev/null +++ b/ext/zend_test/tests/observer_fiber_backtrace_crash.phpt @@ -0,0 +1,48 @@ +--TEST-- +GH-16319 (Fiber backtrace with null filename should not crash) +--EXTENSIONS-- +zend_test +--INI-- +zend_test.observer.enabled=1 +zend_test.observer.show_init_backtrace=1 +zend_test.observer.show_output=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_opcode=0 +opcache.jit=0 +--FILE-- +start(); +echo "Test completed without crash\n"; +?> +--EXPECTF-- + + + + + + + + + + + + + <{closure}> + + +Test completed without crash + From 0ffa337a5405906b680677aadc5b63eb5cde4606 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 29 Jun 2025 01:01:45 +0200 Subject: [PATCH 43/64] Fix GH-17345: Bug #35916 was not completely fixed Change the reproducer code in `bug35916.phpt` from `stream_bucket_append` to `stream_bucket_prepend` and you have the same bug. Furthermore, even in the append case the check is incorrect because the bucket can already be in the brigade at a position other than the tail. To solve this properly, unlink the brigade first and also use that as a condition to manage the refcount. Closes GH-18973. --- NEWS | 1 + ext/standard/tests/filters/gh17345.phpt | 49 +++++++++++++++++++++++++ ext/standard/user_filters.c | 14 ++++--- main/streams/filter.c | 1 + 4 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 ext/standard/tests/filters/gh17345.phpt diff --git a/NEWS b/NEWS index e60af85379c8..952d122fb917 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,7 @@ PHP NEWS - Streams: . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). (Jakub Zelenka) + . Fixed bug GH-17345 (Bug #35916 was not completely fixed). (nielsdos) - XMLReader: . Fixed bug GH-20009 (XMLReader leak on RelaxNG schema failure). (nielsdos) diff --git a/ext/standard/tests/filters/gh17345.phpt b/ext/standard/tests/filters/gh17345.phpt new file mode 100644 index 000000000000..f64659390a14 --- /dev/null +++ b/ext/standard/tests/filters/gh17345.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-17345 (Bug #35916 was not completely fixed) +--FILE-- +data = strtoupper($bucket->data); + $consumed += $bucket->datalen; + stream_bucket_prepend($out, $bucket); + // Interleave new bucket + stream_bucket_prepend($out, clone $bucket); + stream_bucket_prepend($out, $bucket); + } + return PSFS_PASS_ON; + } + + function onCreate(): bool + { + echo "fffffffffff\n"; + return true; + } + + function onClose(): void + { + echo "hello\n"; + } +} + +stream_filter_register("strtoupper", "strtoupper_filter"); +$fp=fopen($file, "w"); +stream_filter_append($fp, "strtoupper"); +fread($fp, 1024); +fwrite($fp, "Thank you\n"); +fclose($fp); +readfile($file); +unlink($file); +?> +--EXPECTF-- +fffffffffff + +Notice: fread(): Read of 8192 bytes failed with errno=9 Bad file descriptor in %s on line %d +hello +THANK YOU diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index acef5146fa25..962eaaba7d6b 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -404,17 +404,19 @@ static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS) memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen); } + /* If the bucket is already on a brigade we have to unlink it first to keep the + * linked list consistent. Furthermore, we can transfer the refcount in that case. */ + if (bucket->brigade) { + php_stream_bucket_unlink(bucket); + } else { + bucket->refcount++; + } + if (append) { php_stream_bucket_append(brigade, bucket); } else { php_stream_bucket_prepend(brigade, bucket); } - /* This is a hack necessary to accommodate situations where bucket is appended to the stream - * multiple times. See bug35916.phpt for reference. - */ - if (bucket->refcount == 1) { - bucket->refcount++; - } } /* }}} */ diff --git a/main/streams/filter.c b/main/streams/filter.c index a1d63c15f0a5..1ce03d41513c 100644 --- a/main/streams/filter.c +++ b/main/streams/filter.c @@ -173,6 +173,7 @@ PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_st PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket) { + /* TODO: this was added as a bad workaround for bug #35916 and should be removed in the future. */ if (brigade->tail == bucket) { return; } From 26ca363a1357e63d6aa70dffab0e699fffbbef83 Mon Sep 17 00:00:00 2001 From: Guillaume Outters Date: Wed, 1 Oct 2025 16:18:20 +0200 Subject: [PATCH 44/64] Fix broken build on *BSD with MSAN The #if to declare instrumented versions of strlcpy and strlcat was too inclusive on *BSD systems where Clang already provides instrumented strong symbols, resulting in "duplicate symbol" at link-time. Fix GH-20002 Closes GH-20032 --- NEWS | 1 + Zend/zend_string.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 952d122fb917..36da15cf32b7 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ PHP NEWS array). (ilutov) . Fixed bug GH-19480 (error_log php.ini cannot be unset when open_basedir is configured). (nielsdos) + . Fixed bug GH-20002 (Broken build on *BSD with MSAN). (outtersg) - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead diff --git a/Zend/zend_string.c b/Zend/zend_string.c index dfe059359aa5..e9ebee08f439 100644 --- a/Zend/zend_string.c +++ b/Zend/zend_string.c @@ -505,8 +505,10 @@ ZEND_API zend_string *zend_string_concat3( return res; } -/* strlcpy and strlcat are not intercepted by msan, so we need to do it ourselves. */ -#if __has_feature(memory_sanitizer) +/* strlcpy and strlcat are not always intercepted by msan, so we need to do it + * ourselves. Apply a simple heuristic to determine the platforms that need it. + * See https://github.com/php/php-src/issues/20002. */ +#if __has_feature(memory_sanitizer) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) static size_t (*libc_strlcpy)(char *__restrict, const char *__restrict, size_t); size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t n) { From 175afc408543c06f8933cc1b1b7f1d5f327a22de Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 4 Sep 2025 18:38:38 +0100 Subject: [PATCH 45/64] Fix GH-19705: do not flush/write buffer on non writeable stream. Co-authored-by: Jakub Zelenka close GH-19708 --- NEWS | 2 ++ ext/standard/tests/streams/gh19705.phpt | 11 +++++++++++ main/streams/streams.c | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/streams/gh19705.phpt diff --git a/NEWS b/NEWS index 36da15cf32b7..0e2726e14b5d 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,8 @@ PHP NEWS . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). (Jakub Zelenka) . Fixed bug GH-17345 (Bug #35916 was not completely fixed). (nielsdos) + . Fixed bug GH-19705 (segmentation when attempting to flush on non seekable + stream. (bukka/David Carlier) - XMLReader: . Fixed bug GH-20009 (XMLReader leak on RelaxNG schema failure). (nielsdos) diff --git a/ext/standard/tests/streams/gh19705.phpt b/ext/standard/tests/streams/gh19705.phpt new file mode 100644 index 000000000000..d34cfc700596 --- /dev/null +++ b/ext/standard/tests/streams/gh19705.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-19705 segmentation fault with non writable stream at stream_filter_append call. +--EXTENSIONS-- +zlib +--FILE-- + +--EXPECTF-- +resource(%d) of type (stream filter) diff --git a/main/streams/streams.c b/main/streams/streams.c index 46fd85e05e35..11eed3e80c61 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1295,7 +1295,7 @@ PHPAPI int _php_stream_flush(php_stream *stream, int closing) { int ret = 0; - if (stream->writefilters.head) { + if (stream->writefilters.head && stream->ops->write) { _php_stream_write_filtered(stream, NULL, 0, closing ? PSFS_FLAG_FLUSH_CLOSE : PSFS_FLAG_FLUSH_INC ); } From a3c14d6ab403246ebe310f763bd7d8c7a7fe45cb Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 2 Oct 2025 13:42:11 +0200 Subject: [PATCH 46/64] Do not use errno_t as it is not defined on musl (#20037) --- main/network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/network.c b/main/network.c index 7102dad20798..fecec0545e8f 100644 --- a/main/network.c +++ b/main/network.c @@ -1090,7 +1090,7 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize) char *errstr = strerror_r(err, ebuf, sizeof(ebuf)); buf = estrdup(errstr); # else - errno_t res = strerror_r(err, ebuf, sizeof(ebuf)); + int res = (int) strerror_r(err, ebuf, sizeof(ebuf)); if (res == 0) { buf = estrdup(ebuf); } else { @@ -1101,7 +1101,7 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize) # ifdef STRERROR_R_CHAR_P buf = strerror_r(err, buf, bufsize); # else - errno_t res = strerror_r(err, buf, bufsize); + int res = (int) strerror_r(err, buf, bufsize); if (res != 0) { strncpy(buf, "Unknown error", bufsize); buf[bufsize?(bufsize-1):0] = 0; @@ -1146,7 +1146,7 @@ PHPAPI zend_string *php_socket_error_str(long err) char *errstr = strerror_r(err, ebuf, sizeof(ebuf)); # else const char *errstr; - errno_t res = strerror_r(err, ebuf, sizeof(ebuf)); + int res = (int) strerror_r(err, ebuf, sizeof(ebuf)); if (res == 0) { errstr = ebuf; } else { From 288d698ce4cc9d73300e757382c250a1ea1876eb Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 2 Oct 2025 19:20:49 +0200 Subject: [PATCH 47/64] Prevent use after stack scope in stream strerr code (#20040) --- main/streams/streams.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/streams/streams.c b/main/streams/streams.c index 11eed3e80c61..372ed6635c3f 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -154,6 +154,7 @@ static void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const { char *tmp; char *msg; + char errstr[256]; int free_msg = 0; if (EG(exception)) { @@ -203,7 +204,6 @@ static void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const free_msg = 1; } else { if (wrapper == &php_plain_files_wrapper) { - char errstr[256]; msg = php_socket_strerror_s(errno, errstr, sizeof(errstr)); } else { msg = "operation failed"; From eab2c2007bbb7f73e82eab6db3af40990723893a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:22:38 +0200 Subject: [PATCH 48/64] Fix GH-20011: Array of SoapVar of unknown type causes crash We "guess" the type in this case, consistent with what a SoapVar would do outside of an array. Closes GH-20030. --- NEWS | 2 ++ ext/soap/php_encoding.c | 5 +++++ ext/soap/tests/bugs/gh20011.phpt | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 ext/soap/tests/bugs/gh20011.phpt diff --git a/NEWS b/NEWS index 0e2726e14b5d..2789d02634c9 100644 --- a/NEWS +++ b/NEWS @@ -45,6 +45,8 @@ PHP NEWS - Soap: . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) + . Fixed bug GH-20011 (Array of SoapVar of unknown type causes crash). + (nielsdos) - Standard: . Fixed bug GH-12265 (Cloning an object breaks serialization recursion). diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 0b4b553d8754..2e03eac0f1b2 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -3584,6 +3584,11 @@ static encodePtr get_array_type(xmlNodePtr node, zval *array, smart_str *type) soap_error0(E_ERROR, "Encoding: SoapVar has no 'enc_type' property"); } cur_type = Z_LVAL_P(ztype); + if (cur_type == UNKNOWN_TYPE) { + /* Mimic guess_xml_convert() where we use the type of the data. + * UNDEFs are handled transparently as it will error out upon encoding the data. */ + cur_type = Z_TYPE_P(Z_VAR_ENC_VALUE_P(tmp)); + } zval *zstype = Z_VAR_ENC_STYPE_P(tmp); if (Z_TYPE_P(zstype) == IS_STRING) { diff --git a/ext/soap/tests/bugs/gh20011.phpt b/ext/soap/tests/bugs/gh20011.phpt new file mode 100644 index 000000000000..cf40d813e617 --- /dev/null +++ b/ext/soap/tests/bugs/gh20011.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-20011 (Array of SoapVar of unknown type causes crash) +--EXTENSIONS-- +soap +--FILE-- + 'test://', 'uri' => 'http://soapinterop.org/']); +$client->echoStringArray($array); +?> +--EXPECT-- + +test string From 831597748ba812d0c0d2bc7909be7ee0804b3ce5 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 30 Sep 2025 16:35:52 +0200 Subject: [PATCH 49/64] Automatically skip tty tests if not on tty See GH-19975 Closes GH-20013 --- run-tests.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/run-tests.php b/run-tests.php index d51ab99a205a..8fb638ed3e80 100755 --- a/run-tests.php +++ b/run-tests.php @@ -651,6 +651,12 @@ function main(): void } } + if (!defined('STDIN') || !stream_isatty(STDIN) + || !defined('STDOUT') || !stream_isatty(STDOUT) + || !defined('STDERR') || !stream_isatty(STDERR)) { + $environment['SKIP_IO_CAPTURE_TESTS'] = '1'; + } + if ($selected_tests && count($test_files) === 0) { echo "No tests found.\n"; return; From db65d22ce2129f409694e674384181b24e643d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 4 Oct 2025 20:00:50 +0200 Subject: [PATCH 50/64] CI: Do not save ccache for PRs for LINUX_X32 see #14168 which added this for all other builds see 69dbfadd1eebc2e99f349b6fd617cda1d5cad448 which added the LINUX_X32 build --- .github/workflows/push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 21903f63df5f..d97736cc46a6 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -140,6 +140,7 @@ jobs: with: key: "${{github.job}}-${{hashFiles('main/php_version.h')}}" append-timestamp: false + save: ${{ github.event_name != 'pull_request' }} - name: ./configure uses: ./.github/actions/configure-x32 with: From 4fed57e7464cb4bcbf7ee2acf515156b3ab53d8f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 4 Oct 2025 14:59:27 +0200 Subject: [PATCH 51/64] Fix GH-20043: array_unique assertion failure with RC1 array causing an exception on sort The reason this happens is because the array_unique operation happens in-place because the input array is RC1. At one point during comparison an exception is thrown which will capture the arguments in the backtrace, which will increment the refcount of the RC1 array to 2. Then a modification happens after the throw on the RC2 array causing the assertion failure. We shouldn't try continue work after an exception happened during the sort. Closes GH-20059. --- NEWS | 2 ++ ext/standard/array.c | 7 +++++++ ext/standard/tests/array/gh20043.phpt | 12 ++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 ext/standard/tests/array/gh20043.phpt diff --git a/NEWS b/NEWS index 2789d02634c9..c25c1922f8b0 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,8 @@ PHP NEWS . Fixed bug GH-19701 (Serialize/deserialize loses some data). (nielsdos) . Fixed bug GH-19801 (leaks in var_dump() and debug_zval_dump()). (alexandre-daubois) + . Fixed bug GH-20043 (array_unique assertion failure with RC1 array + causing an exception on sort). (nielsdos) - Streams: . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). diff --git a/ext/standard/array.c b/ext/standard/array.c index f0a81b5ba895..b7b5f82d61c5 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -4900,6 +4900,11 @@ PHP_FUNCTION(array_unique) ZVAL_UNDEF(&arTmp[i].b.val); zend_sort((void *) arTmp, i, sizeof(struct bucketindex), (compare_func_t) cmp, (swap_func_t) array_bucketindex_swap); + + if (UNEXPECTED(EG(exception))) { + goto out; + } + /* go through the sorted array and delete duplicates from the copy */ lastkept = arTmp; for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) { @@ -4919,6 +4924,8 @@ PHP_FUNCTION(array_unique) } } } + +out: pefree(arTmp, GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT); if (in_place) { diff --git a/ext/standard/tests/array/gh20043.phpt b/ext/standard/tests/array/gh20043.phpt new file mode 100644 index 000000000000..d5c7e06417f1 --- /dev/null +++ b/ext/standard/tests/array/gh20043.phpt @@ -0,0 +1,12 @@ +--TEST-- +GH-20043 (array_unique assertion failure with RC1 array causing an exception on sort) +--FILE-- +getMessage(); +} +?> +--EXPECT-- +Object of class stdClass could not be converted to string From 66c833444cf9a52a2e95656d1116efdb8495d507 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 4 Oct 2025 12:20:49 +0200 Subject: [PATCH 52/64] phar: Fix memory leaks when creating temp file fails when applying zip signature Also fixes up the error propagation at the call site which jumped to the wrong place in the error handling code. Closes GH-20057. --- NEWS | 2 ++ ext/phar/zip.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index c25c1922f8b0..82b1cd77d7c3 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,8 @@ PHP NEWS - Phar: . Fix memory leak and invalid continuation after tar header writing fails. (nielsdos) + . Fix memory leaks when creating temp file fails when applying zip signature. + (nielsdos) - SimpleXML: . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 87681c69959a..dff170dc29b4 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -1192,7 +1192,9 @@ static int phar_zip_applysignature(phar_archive_data *phar, struct _phar_zip_pas entry.fp_type = PHAR_MOD; entry.is_modified = 1; if (entry.fp == NULL) { + efree(signature); spprintf(pass->error, 0, "phar error: unable to create temporary file for signature"); + php_stream_close(newfile); return FAILURE; } @@ -1456,11 +1458,12 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, zend_long len, int phar_metadata_tracker_try_ensure_has_serialized_data(&phar->metadata_tracker, phar->is_persistent); if (temperr) { +temperror: if (error) { spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr); } efree(temperr); -temperror: +notemperror: php_stream_close(pass.centralfp); nocentralerror: php_stream_close(pass.filefp); @@ -1488,7 +1491,7 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, zend_long len, int if (error) { spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname); } - goto temperror; + goto notemperror; } } From 7e7d6d6380e992d6acd61e8e18cb96ee2d98941c Mon Sep 17 00:00:00 2001 From: Leo Gaskin Date: Sat, 6 Sep 2025 14:06:23 +0200 Subject: [PATCH 53/64] Treat accept failing with SOCK_EAGAIN as success in CLI web server This ensures that no useless "Failed to poll event" error messages are logged during normal server operation, as the SOCK_EAGAIN error simply indicates another worker is already serving the request. Closes GH-19964 --- NEWS | 4 ++++ sapi/cli/php_cli_server.c | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 82b1cd77d7c3..2edaf09ce70e 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,10 @@ PHP NEWS configured). (nielsdos) . Fixed bug GH-20002 (Broken build on *BSD with MSAN). (outtersg) +- CLI: + . Fix useless "Failed to poll event" error logs due to EAGAIN in CLI server + with PHP_CLI_SERVER_WORKERS. (leotaku) + - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead of the curl_copy_handle() function to clone a CurlHandle. (timwolla) diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index 9eaeb4779f42..8d67fb2864c6 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -2721,14 +2721,16 @@ static zend_result php_cli_server_do_event_for_each_fd_callback(void *_params, p struct sockaddr *sa = pemalloc(server->socklen, 1); client_sock = accept(server->server_sock, sa, &socklen); if (!ZEND_VALID_SOCKET(client_sock)) { - int err = php_socket_errno(); - if (err != SOCK_EAGAIN && php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) { + pefree(sa, 1); + if (php_socket_errno() == SOCK_EAGAIN) { + return SUCCESS; + } + if (php_cli_server_log_level >= PHP_CLI_SERVER_LOG_ERROR) { char *errstr = php_socket_strerror(php_socket_errno(), NULL, 0); php_cli_server_logf(PHP_CLI_SERVER_LOG_ERROR, "Failed to accept a client (reason: %s)", errstr); efree(errstr); } - pefree(sa, 1); return FAILURE; } if (SUCCESS != php_set_sock_blocking(client_sock, 0)) { From 64c1d43b68dd812ce4d3dec0a9b469fd4c060f30 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:51:23 +0200 Subject: [PATCH 54/64] Fix GH-19926: reset internal pointer earlier while splicing array while COW violation flag is still set (#19929) --- NEWS | 2 ++ ext/standard/array.c | 8 ++++++-- ext/standard/tests/array/gh19926.phpt | 20 +++++++++++++++++++ ext/standard/tests/array/gh19926_pointer.phpt | 19 ++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/array/gh19926.phpt create mode 100644 ext/standard/tests/array/gh19926_pointer.phpt diff --git a/NEWS b/NEWS index 2edaf09ce70e..c2db743c84e0 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,8 @@ PHP NEWS (alexandre-daubois) . Fixed bug GH-20043 (array_unique assertion failure with RC1 array causing an exception on sort). (nielsdos) + . Fixed bug GH-19926 (reset internal pointer earlier while splicing array + while COW violation flag is still set). (alexandre-daubois) - Streams: . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). diff --git a/ext/standard/array.c b/ext/standard/array.c index b7b5f82d61c5..4896ac44a727 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -3376,6 +3376,12 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H HT_SET_ITERATORS_COUNT(in_hash, 0); in_hash->pDestructor = NULL; + /* Set internal pointer to 0 directly instead of calling zend_hash_internal_pointer_reset(). + * This avoids the COW violation assertion and delays advancing to the first valid position + * until after we've switched to the new array structure (out_hash). The iterator will be + * advanced when actually accessed, at which point it will find valid indexes in the new array. */ + in_hash->nInternalPointer = 0; + if (UNEXPECTED(GC_DELREF(in_hash) == 0)) { /* Array was completely deallocated during the operation */ zend_array_destroy(in_hash); @@ -3394,8 +3400,6 @@ static void php_splice(HashTable *in_hash, zend_long offset, zend_long length, H in_hash->nNextFreeElement = out_hash.nNextFreeElement; in_hash->arData = out_hash.arData; in_hash->pDestructor = out_hash.pDestructor; - - zend_hash_internal_pointer_reset(in_hash); } /* }}} */ diff --git a/ext/standard/tests/array/gh19926.phpt b/ext/standard/tests/array/gh19926.phpt new file mode 100644 index 000000000000..b714db9eb2b3 --- /dev/null +++ b/ext/standard/tests/array/gh19926.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-19926 (Assertion failure zend_hash_internal_pointer_reset_ex) +--FILE-- + +--EXPECT-- +Exception caught, no assertion failure diff --git a/ext/standard/tests/array/gh19926_pointer.phpt b/ext/standard/tests/array/gh19926_pointer.phpt new file mode 100644 index 000000000000..c134f3b594b3 --- /dev/null +++ b/ext/standard/tests/array/gh19926_pointer.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-19926 (internal pointer behavior after array_splice) +--FILE-- + +--EXPECT-- +Before array_splice: int(3) +After array_splice: int(999) From b7aeb0a69f94aeaa983c6dbba2c01b584fdfeabe Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 6 Sep 2025 14:20:24 +0200 Subject: [PATCH 55/64] Fix GH-19570: unable to fseek in /dev/zero and /dev/null On Linux, these two character devices are exceptions in that they can be seeked. Check their major/minor device number. Co-authored-by: divinity76 --- NEWS | 2 ++ ext/standard/tests/streams/gh19570.phpt | 22 ++++++++++++++++++++++ main/streams/plain_wrapper.c | 25 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 ext/standard/tests/streams/gh19570.phpt diff --git a/NEWS b/NEWS index c2db743c84e0..7a42307caec4 100644 --- a/NEWS +++ b/NEWS @@ -64,6 +64,8 @@ PHP NEWS causing an exception on sort). (nielsdos) . Fixed bug GH-19926 (reset internal pointer earlier while splicing array while COW violation flag is still set). (alexandre-daubois) + . Fixed bug GH-19570 (unable to fseek in /dev/zero and /dev/null). + (nielsdos, divinity76) - Streams: . Fixed bug GH-19248 (Use strerror_r instead of strerror in main). diff --git a/ext/standard/tests/streams/gh19570.phpt b/ext/standard/tests/streams/gh19570.phpt new file mode 100644 index 000000000000..e3d486ea83cf --- /dev/null +++ b/ext/standard/tests/streams/gh19570.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-19570 (unable to fseek in /dev/zero and /dev/null) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(0) +int(0) +int(0) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index 9ac049f74684..09528e926f72 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -43,6 +43,10 @@ # include #endif +#ifdef __linux__ +# include +#endif + #define php_stream_fopen_from_fd_int(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_CC) #define php_stream_fopen_from_fd_int_rel(fd, mode, persistent_id) _php_stream_fopen_from_fd_int((fd), (mode), (persistent_id) STREAMS_REL_CC) #define php_stream_fopen_from_file_int(file, mode) _php_stream_fopen_from_file_int((file), (mode) STREAMS_CC) @@ -255,7 +259,28 @@ PHPAPI php_stream *_php_stream_fopen_tmpfile(int dummy STREAMS_DC) static void detect_is_seekable(php_stdio_stream_data *self) { #if defined(S_ISFIFO) && defined(S_ISCHR) if (self->fd >= 0 && do_fstat(self, 0) == 0) { +#ifdef __linux__ + if (S_ISCHR(self->sb.st_mode)) { + /* Some character devices are exceptions, check their major/minor ID + * https://www.kernel.org/doc/Documentation/admin-guide/devices.txt */ + if (major(self->sb.st_rdev) == 1) { + unsigned m = minor(self->sb.st_rdev); + self->is_seekable = + m == 1 || /* /dev/mem */ + m == 2 || /* /dev/kmem */ + m == 3 || /* /dev/null */ + m == 4 || /* /dev/port (seekable, offset = I/O port) */ + m == 5 || /* /dev/zero */ + m == 7; /* /dev/full */ + } else { + self->is_seekable = false; + } + } else { + self->is_seekable = !S_ISFIFO(self->sb.st_mode); + } +#else self->is_seekable = !(S_ISFIFO(self->sb.st_mode) || S_ISCHR(self->sb.st_mode)); +#endif self->is_pipe = S_ISFIFO(self->sb.st_mode); } #elif defined(PHP_WIN32) From 9d9b73a3f0d2fbfb60eee8e943e4135a73012f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 6 Oct 2025 20:17:53 +0200 Subject: [PATCH 56/64] .gdbinit: Fix printing of variable names in `print_cvs` (#20077) Previously only the first character of each variable was printed. --- .gdbinit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gdbinit b/.gdbinit index c4705b2f59a9..4477828265e0 100644 --- a/.gdbinit +++ b/.gdbinit @@ -42,7 +42,7 @@ define print_cvs printf "Compiled variables count: %d\n\n", $cv_count while $cv_idx < $cv_count - printf "[%d] '%s'\n", $cv_idx, $cv[$cv_idx].val + printf "[%d] '$%s'\n", $cv_idx, $cv[$cv_idx].val@$cv[$cv_idx].len set $zvalue = ((zval *) $cv_ex_ptr) + $callFrameSize + $cv_idx printzv $zvalue set $cv_idx = $cv_idx + 1 From 66708de8417d743aba4f542ee6476b646cdb918b Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 2 Oct 2025 15:53:53 +0200 Subject: [PATCH 57/64] Upgrade Alpine in nightly job Closes GH-20044 --- .github/workflows/nightly.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a8c8c80d7d50..e0322e3b1be2 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -93,9 +93,9 @@ jobs: ALPINE: if: inputs.run_alpine name: ALPINE_X64_ASAN_UBSAN_DEBUG_ZTS - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: - image: 'alpine:3.20.1' + image: 'alpine:3.22' steps: - name: git checkout uses: actions/checkout@v5 @@ -103,11 +103,6 @@ jobs: ref: ${{ inputs.branch }} - name: apk uses: ./.github/actions/apk - - name: LLVM 17 (ASAN-only) - # libclang_rt.asan-x86_64.a is provided by compiler-rt, and only for clang17: - # https://pkgs.alpinelinux.org/contents?file=libclang_rt.asan-x86_64.a&path=&name=&branch=v3.20 - run: | - apk add clang17 compiler-rt - name: System info run: | echo "::group::Show host CPU info" @@ -122,8 +117,8 @@ jobs: configurationParameters: >- CFLAGS="-fsanitize=undefined,address -fno-sanitize=function -DZEND_TRACK_ARENA_ALLOC" LDFLAGS="-fsanitize=undefined,address -fno-sanitize=function" - CC=clang-17 - CXX=clang++-17 + CC=clang-20 + CXX=clang++-20 --enable-debug --enable-zts skipSlow: true # FIXME: This should likely include slow extensions From 1c8363d2bfe214c142b3e17bf7303b6c338ac41a Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 13 Sep 2025 00:15:01 +0200 Subject: [PATCH 58/64] Fix curl build failure on macOS+curl 8.16 --- ext/curl/interface.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 807b27cb78c9..4df24cff1b5b 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1453,11 +1453,11 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string) /* }}} */ /* {{{ curl_progress */ -static size_t curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) +static int curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) { php_curl *ch = (php_curl *)clientp; php_curl_callback *t = ch->handlers.progress; - size_t rval = 0; + int rval = 0; #if PHP_CURL_DEBUG fprintf(stderr, "curl_progress() called\n"); @@ -1818,8 +1818,8 @@ static void _php_curl_set_default_options(php_curl *ch) { char *cainfo; - curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS, 1); - curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0); + curl_easy_setopt(ch->cp, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0L); curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER, ch->err.str); curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write); curl_easy_setopt(ch->cp, CURLOPT_FILE, (void *) ch); @@ -1828,10 +1828,10 @@ static void _php_curl_set_default_options(php_curl *ch) curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_header); curl_easy_setopt(ch->cp, CURLOPT_WRITEHEADER, (void *) ch); #ifndef ZTS - curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1); + curl_easy_setopt(ch->cp, CURLOPT_DNS_USE_GLOBAL_CACHE, 1L); #endif - curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120); - curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20); /* prevent infinite redirects */ + curl_easy_setopt(ch->cp, CURLOPT_DNS_CACHE_TIMEOUT, 120L); + curl_easy_setopt(ch->cp, CURLOPT_MAXREDIRS, 20L); /* prevent infinite redirects */ cainfo = INI_STR("openssl.cafile"); if (!(cainfo && cainfo[0] != '\0')) { @@ -2807,7 +2807,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i /* no need to build the mime structure for empty hashtables; also works around https://github.com/curl/curl/issues/6455 */ curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDS, ""); - error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0); + error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, 0L); } else { return build_mime_structure_from_hash(ch, zvalue); } @@ -2871,7 +2871,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i case CURLOPT_POSTREDIR: lval = zval_get_long(zvalue); - error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, lval & CURL_REDIR_POST_ALL); + error = curl_easy_setopt(ch->cp, CURLOPT_POSTREDIR, (long) (lval & CURL_REDIR_POST_ALL)); break; /* the following options deal with files, therefore the open_basedir check @@ -2906,11 +2906,11 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i if (zend_is_true(zvalue)) { curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, curl_debug); curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, (void *)ch); - curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1); + curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 1L); } else { curl_easy_setopt(ch->cp, CURLOPT_DEBUGFUNCTION, NULL); curl_easy_setopt(ch->cp, CURLOPT_DEBUGDATA, NULL); - curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0); + curl_easy_setopt(ch->cp, CURLOPT_VERBOSE, 0L); } break; From da75e41a6f7e1d64904e45612eaafe4a636fe502 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 22 Sep 2025 10:55:59 +0200 Subject: [PATCH 59/64] Fix curl 8.16.0 compilation with zts --- ext/curl/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 4df24cff1b5b..f8f0d1cec358 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1842,7 +1842,7 @@ static void _php_curl_set_default_options(php_curl *ch) } #ifdef ZTS - curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(ch->cp, CURLOPT_NOSIGNAL, 1L); #endif } /* }}} */ From b810a235870f7fbb377fa50470970eaf16d796ce Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Tue, 23 Sep 2025 14:14:09 +0200 Subject: [PATCH 60/64] Fix more curl 8.16 issues The CURLOPT_FOLLOWLOCATION seems like a gcc bug, where the integer extension of bool to long is lost, but I was unable to reproduce on godbolt.org. --- ext/curl/interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index f8f0d1cec358..c56a1b01f2fa 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -2289,7 +2289,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i lval = zval_get_long(zvalue); if (lval == 1) { php_error_docref(NULL, E_NOTICE, "CURLOPT_SSL_VERIFYHOST no longer accepts the value 1, value 2 will be used instead"); - error = curl_easy_setopt(ch->cp, option, 2); + error = curl_easy_setopt(ch->cp, option, 2L); break; } ZEND_FALLTHROUGH; @@ -2789,7 +2789,7 @@ static int _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue, bool i case CURLOPT_FOLLOWLOCATION: lval = zend_is_true(zvalue); - error = curl_easy_setopt(ch->cp, option, lval); + error = curl_easy_setopt(ch->cp, option, (long) lval); break; case CURLOPT_HEADERFUNCTION: From 36859ad97753f6d2e550d57823111d91f0ad0ce9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 7 Oct 2025 12:33:26 +0200 Subject: [PATCH 61/64] Fix curl_setopt_ssl test for curl 8.16 --- ext/curl/tests/curl_setopt_ssl.phpt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ext/curl/tests/curl_setopt_ssl.phpt b/ext/curl/tests/curl_setopt_ssl.phpt index 11d8fff702a8..ff08528321a0 100644 --- a/ext/curl/tests/curl_setopt_ssl.phpt +++ b/ext/curl/tests/curl_setopt_ssl.phpt @@ -18,9 +18,13 @@ if ($curl_version['version_number'] < 0x074700) { --FILE-- Date: Tue, 7 Oct 2025 14:25:08 +0200 Subject: [PATCH 62/64] Update NEWS with info about curl 8.16 compat fixes --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index a05b577d101b..998b5d97d635 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.1.34 +- Curl: + . Fix curl build and test failures with version 8.16. + (nielsdos, ilutov, Jakub Zelenka) + - Opcache: . Reset global pointers to prevent use-after-free in zend_jit_status(). (Florian Engelhardt) From 78a24ffc032804755e31bb308c0e754cbc049051 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Tue, 7 Oct 2025 14:39:53 +0200 Subject: [PATCH 63/64] Update NEWS entry for curl 8.16 update --- NEWS | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index cd793b71c9cb..884ccd0855d7 100644 --- a/NEWS +++ b/NEWS @@ -23,7 +23,8 @@ PHP NEWS - Curl: . Fix cloning of CURLOPT_POSTFIELDS when using the clone operator instead of the curl_copy_handle() function to clone a CurlHandle. (timwolla) - . Fix curl build failure on macOS+curl 8.16. (nielsdos) + . Fix curl build and test failures with version 8.16. + (nielsdos, ilutov, Jakub Zelenka) - Date: . Fixed GH-17159: "P" format for ::createFromFormat swallows string literals. @@ -208,10 +209,6 @@ PHP NEWS . Fixed bug GH-19397 (mb_list_encodings() can cause crashes on shutdown). (nielsdos) -- Curl: - . Fix curl build and test failures with version 8.16. - (nielsdos, ilutov, Jakub Zelenka) - - Opcache: . Reset global pointers to prevent use-after-free in zend_jit_status(). (Florian Engelhardt) From 0103a13e5a48dcbfcd16e4f7b7b70e57b2d21856 Mon Sep 17 00:00:00 2001 From: Eric Mann Date: Tue, 7 Oct 2025 06:55:19 -0700 Subject: [PATCH 64/64] Update versions for PHP 8.3.27RC1 --- 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 884ccd0855d7..b20a4fe61695 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.3.27 +09 Oct 2025, PHP 8.3.27RC1 - Core: . Fixed bug GH-19765 (object_properties_load() bypasses readonly property diff --git a/Zend/zend.h b/Zend/zend.h index f0925298413f..26902cbddfa6 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.3.27-dev" +#define ZEND_VERSION "4.3.27RC1" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index 1e39e16644b1..48f19717e8ec 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.3.27-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.3.27RC1],[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 bf1b95c63193..640e83444d3c 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 3 #define PHP_RELEASE_VERSION 27 -#define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.3.27-dev" +#define PHP_EXTRA_VERSION "RC1" +#define PHP_VERSION "8.3.27RC1" #define PHP_VERSION_ID 80327