From 6ab188f4be04b5b7203bc1b8c2f66ac302f26256 Mon Sep 17 00:00:00 2001 From: Marc Bennewitz Date: Tue, 27 Oct 2026 10:15:42 +0100 Subject: [PATCH 1/2] Fix ZEND_LONG_UINT_OVFL() accepting negative values on 32-bit platforms Where zend_long is not wider than an int, ZEND_LONG_UINT_OVFL() was defined as 0, so a negative value passed the check there, while it is rejected where zend_long is wider. Keep checking the lower bound on these platforms too. This affects mbstring.regex_stack_limit, mbstring.regex_retry_limit and the codepage of sapi_windows_cp_set() and sapi_windows_cp_conv(). --- NEWS | 8 ++++ Zend/zend_range_check.h | 2 +- ext/mbstring/tests/retry_limit_negative.phpt | 25 +++++++++++++ .../sapi_windows_cp_negative_codepage.phpt | 37 +++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 ext/mbstring/tests/retry_limit_negative.phpt create mode 100644 ext/standard/tests/strings/sapi_windows_cp_negative_codepage.phpt diff --git a/NEWS b/NEWS index 06c1c76dba02..af282e837716 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,10 @@ PHP NEWS - Hash: . Fix GOST and Snefru digests of 512 MiB or more. (Martin Mirchev) +- MBString: + . Fixed negative mbstring.regex_stack_limit and mbstring.regex_retry_limit + on 32bit platforms. (Marc Bennewitz) + - Opcache: . Fixed tracing JIT returning a wrapped integer instead of a float on integer overflow after an integer was compared with a float or @@ -72,6 +76,10 @@ PHP NEWS . Fixed bug GH-24509 (HTTP wrapper leaks Location buffer on empty Location header). (bercedev) +- Windows: + . Fixed sapi_windows_cp_set() and sapi_windows_cp_conv() accepting a negative + codepage on 32bit platforms. (Marc Bennewitz) + - Zip: . Reject broken libzip versions 1.3.1, 1.7.0 and 1.12.0 during Windows configuration. (Weilin Du) diff --git a/Zend/zend_range_check.h b/Zend/zend_range_check.h index 8db867434399..ed61097419f2 100644 --- a/Zend/zend_range_check.h +++ b/Zend/zend_range_check.h @@ -46,7 +46,7 @@ # define ZEND_LONG_INT_OVFL(zl) (0) # define ZEND_LONG_INT_UDFL(zl) (0) # define ZEND_LONG_EXCEEDS_INT(zlong) (0) -# define ZEND_LONG_UINT_OVFL(zl) (0) +# define ZEND_LONG_UINT_OVFL(zl) UNEXPECTED((zl) < 0) #endif /* size_t vs (unsigned) int checks. */ diff --git a/ext/mbstring/tests/retry_limit_negative.phpt b/ext/mbstring/tests/retry_limit_negative.phpt new file mode 100644 index 000000000000..b498a7463d28 --- /dev/null +++ b/ext/mbstring/tests/retry_limit_negative.phpt @@ -0,0 +1,25 @@ +--TEST-- +Oniguruma retry limit is not set from a negative mbstring.regex_retry_limit +--EXTENSIONS-- +mbstring +--SKIPIF-- += 6.9.3'); +} +?> +--INI-- +error_reporting=E_ALL & ~E_DEPRECATED +mbstring.regex_retry_limit=-1 +--FILE-- + +--EXPECT-- +bool(false) diff --git a/ext/standard/tests/strings/sapi_windows_cp_negative_codepage.phpt b/ext/standard/tests/strings/sapi_windows_cp_negative_codepage.phpt new file mode 100644 index 000000000000..997685f34ef3 --- /dev/null +++ b/ext/standard/tests/strings/sapi_windows_cp_negative_codepage.phpt @@ -0,0 +1,37 @@ +--TEST-- +sapi_windows_cp_set() and sapi_windows_cp_conv() must reject a negative codepage +--SKIPIF-- + +--FILE-- +getMessage(), "\n"; +} + +try { + sapi_windows_cp_set(PHP_INT_MIN); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + sapi_windows_cp_conv(-1, 65001, 'php'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +try { + sapi_windows_cp_conv(65001, -1, 'php'); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} +?> +--EXPECT-- +ValueError: sapi_windows_cp_set(): Argument #1 ($codepage) must be between 0 and 4294967295 +ValueError: sapi_windows_cp_set(): Argument #1 ($codepage) must be between 0 and 4294967295 +ValueError: sapi_windows_cp_conv(): Argument #1 ($in_codepage) must be between 0 and 4294967295 +ValueError: sapi_windows_cp_conv(): Argument #2 ($out_codepage) must be between 0 and 4294967295 From 214d53575eb893ef78dc5c9ca9407fc380cffbed Mon Sep 17 00:00:00 2001 From: Marc Bennewitz Date: Tue, 27 Oct 2026 10:16:45 +0100 Subject: [PATCH 2/2] Add test for Phar::buildFromIterator() with a negative getMTime() The fix of ZEND_LONG_UINT_OVFL() on 32-bit platforms also makes Phar::buildFromIterator() reject a negative timestamp there. --- NEWS | 4 ++ .../getMTime_negative.phpt | 53 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 ext/phar/tests/buildFromIterator_user_overrides/getMTime_negative.phpt diff --git a/NEWS b/NEWS index af282e837716..77c2e799feb1 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,10 @@ PHP NEWS . Fixed bug GH-24461 (DISCARD ALL on persistent connection cleanup drops PgBouncer's prepared statements). (David Carlier, Artem Ukrainskiy) +- Phar: + . Fixed Phar::buildFromIterator() accepting a negative getMTime() on 32bit + platforms. (Marc Bennewitz) + - SAPI: . Fixed infinite loop in sapi_header_op() for headers of 4 GiB or more. (Martin Mirchev) diff --git a/ext/phar/tests/buildFromIterator_user_overrides/getMTime_negative.phpt b/ext/phar/tests/buildFromIterator_user_overrides/getMTime_negative.phpt new file mode 100644 index 000000000000..315705781647 --- /dev/null +++ b/ext/phar/tests/buildFromIterator_user_overrides/getMTime_negative.phpt @@ -0,0 +1,53 @@ +--TEST-- +buildFromIterator with user overrides - negative getMTime() +--EXTENSIONS-- +phar +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +getPathname()); + } +} + +$workdir = __DIR__.'/getMTime_negative'; +mkdir($workdir . '/content', recursive: true); +file_put_contents($workdir . '/content/hello.txt', "Hello world."); + +try { + $phar = new \Phar($workdir . "/test.phar"); + $phar->startBuffering(); + $phar->buildFromIterator( + new RecursiveIteratorIterator( + new MyIterator($workdir . '/content', FilesystemIterator::SKIP_DOTS) + ), + $workdir + ); + $phar->stopBuffering(); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +?> +--CLEAN-- + +--EXPECTF-- +[MTime] +BadMethodCallException: Entry content%chello.txt cannot be created: timestamp is limited to 32-bit