Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ PHP NEWS
. Fixed bug GH-11020 (exif_read_data() emits a spurious "Illegal IFD size"
warning when an IFD is not followed by a next-IFD offset). (Eyüp Can Akman)

- GMP:
. Fixed bug GH-22549 (Assertion failure / UB on a compound GMP power or shift
assignment with a negative exponent). (iliaal)

- Intl:
. Fixed NumberFormatter::parse() and NumberFormatter::parseCurrency() to
reject offset values outside the 32-bit range instead of silently
Expand Down Expand Up @@ -51,6 +55,10 @@ PHP NEWS
. Fixed bug GH-22585 (OOM on bailout with uninitialized
do_request() parameters). (David Carlier)

- Standard:
. Fixed sleep() and usleep() to reject values that overflow the underlying
unsigned int timeout. (Weilin Du)

- Streams:
. Fixed bug GH-21468 (Segfault in file_get_contents w/ a https URL
and a proxy set). (CVE-2026-12184) (ndossche)
Expand Down
11 changes: 5 additions & 6 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,10 @@ static int zend_add_const_name_literal(zend_string *name, bool unqualified) /* {

int ret = zend_add_literal_string(&name);

size_t ns_len = 0, after_ns_len = ZSTR_LEN(name);
const char *after_ns = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (after_ns) {
after_ns += 1;
ns_len = after_ns - ZSTR_VAL(name) - 1;
after_ns_len = ZSTR_LEN(name) - ns_len - 1;
const char *after_ns;
size_t after_ns_len;
if (zend_get_unqualified_name(name, &after_ns, &after_ns_len)) {
size_t ns_len = after_ns - ZSTR_VAL(name) - 1;

/* lowercased namespace name & original constant name */
tmp_name = zend_string_init(ZSTR_VAL(name), ZSTR_LEN(name), 0);
Expand All @@ -690,6 +688,7 @@ static int zend_add_const_name_literal(zend_string *name, bool unqualified) /* {
}
} else {
after_ns = ZSTR_VAL(name);
after_ns_len = ZSTR_LEN(name);
}

/* original unqualified constant name */
Expand Down
8 changes: 4 additions & 4 deletions build/gen_stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function processDirectory(string $dir, Context $context): array {
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($it as $file) {
$pathName = $file->getPathName();
$pathName = $file->getPathname();
if (str_ends_with($pathName, '.stub.php')) {
$pathNames[] = $pathName;
}
Expand Down Expand Up @@ -5561,7 +5561,7 @@ function replacePredefinedConstants(string $targetDirectory, array $constMap, ar
);

foreach ($it as $file) {
$pathName = $file->getPathName();
$pathName = $file->getPathname();
if (!preg_match('/(?:[\w\.]*constants[\w\._]*|tokens).xml$/i', basename($pathName))) {
continue;
}
Expand Down Expand Up @@ -5742,7 +5742,7 @@ function replaceClassSynopses(
);

foreach ($it as $file) {
$pathName = $file->getPathName();
$pathName = $file->getPathname();
if (!preg_match('/\.xml$/i', $pathName)) {
continue;
}
Expand Down Expand Up @@ -5959,7 +5959,7 @@ function replaceMethodSynopses(
);

foreach ($it as $file) {
$pathName = $file->getPathName();
$pathName = $file->getPathname();
if (!preg_match('/\.xml$/i', $pathName)) {
continue;
}
Expand Down
1 change: 0 additions & 1 deletion ext/gmp/gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@ static zend_result shift_operator_helper(gmp_binary_ui_op_t op, zval *return_val
zend_ce_value_error, "%s must be between 0 and %lu",
opcode == ZEND_POW ? "Exponent" : "Shift", ULONG_MAX
);
ZVAL_UNDEF(return_value);
return FAILURE;
} else {
mpz_ptr gmpnum_op, gmpnum_result;
Expand Down
55 changes: 55 additions & 0 deletions ext/gmp/tests/gh22549.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
--TEST--
GH-22549 (Assertion failure in _zendi_try_convert_scalar_to_number with compound GMP shift/pow)
--EXTENSIONS--
gmp
--FILE--
<?php
// Compound assignment aliases result and op1. A negative GMP shift/exponent
// must throw a ValueError, not clobber op1 into IS_UNDEF and abort.
$cases = [
'int ** gmp' => [2, fn(&$x) => $x **= gmp_init(-5)],
'gmp ** gmp' => [gmp_init(2), fn(&$x) => $x **= gmp_init(-5)],
'array ** gmp' => [[0], fn(&$x) => $x **= gmp_init(-5)],
'int << gmp' => [8, fn(&$x) => $x <<= gmp_init(-2)],
'int >> gmp' => [8, fn(&$x) => $x >>= gmp_init(-2)],
'gmp << gmp' => [gmp_init(8), fn(&$x) => $x <<= gmp_init(-2)],
];

foreach ($cases as $label => [$x, $op]) {
try {
$op($x);
echo "$label: no exception\n";
} catch (\Throwable $e) {
echo "$label: ", $e::class, ": ", $e->getMessage(), "\n";
}
var_dump($x);
}

// Valid operations must still succeed (guard against an over-broad regression).
$p = 2; $p **= gmp_init(3); echo "valid pow: ", gmp_strval($p), "\n";
$s = 1; $s <<= gmp_init(4); echo "valid shift: ", gmp_strval($s), "\n";
?>
--EXPECTF--
int ** gmp: ValueError: Exponent must be between 0 and %d
int(2)
gmp ** gmp: ValueError: Exponent must be between 0 and %d
object(GMP)#%d (1) {
["num"]=>
string(1) "2"
}
array ** gmp: ValueError: Exponent must be between 0 and %d
array(1) {
[0]=>
int(0)
}
int << gmp: ValueError: Shift must be between 0 and %d
int(8)
int >> gmp: ValueError: Shift must be between 0 and %d
int(8)
gmp << gmp: ValueError: Shift must be between 0 and %d
object(GMP)#%d (1) {
["num"]=>
string(1) "8"
}
valid pow: 8
valid shift: 16
4 changes: 0 additions & 4 deletions ext/random/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@
# include <sys/time.h>
#endif

#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif

#include "random_arginfo.h"

PHPAPI ZEND_DECLARE_MODULE_GLOBALS(random)
Expand Down
2 changes: 2 additions & 0 deletions ext/session/tests/bug80774.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Bug #80774 (session_name() problem with backslash)
session
--INI--
session.use_strict_mode=0
session.cookie_samesite=Lax
session.cookie_httponly=1
--FILE--
<?php
session_name("foo\\bar");
Expand Down
2 changes: 2 additions & 0 deletions ext/session/tests/gh9200.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ GH-9200: setcookie has an obsolete expires date format
--INI--
session.cookie_lifetime=3600
session.use_strict_mode=0
session.cookie_samesite=Lax
session.cookie_httponly=1
--EXTENSIONS--
session
--CGI--
Expand Down
2 changes: 2 additions & 0 deletions ext/session/tests/session_regenerate_id_cookie.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Test session_regenerate_id() function : basic functionality
session
--INI--
session.sid_length = 32
session.cookie_samesite=Lax
session.cookie_httponly=1
--SKIPIF--
<?php

Expand Down
2 changes: 2 additions & 0 deletions ext/session/tests/session_start_partitioned_headers.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ session_start() with partitioned cookies - header test
session
--INI--
session.use_strict_mode=0
session.cookie_samesite=Lax
session.cookie_httponly=1
--FILE--
<?php
session_id('12345');
Expand Down
13 changes: 9 additions & 4 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1123,13 +1123,18 @@ PHP_FUNCTION(flush)
PHP_FUNCTION(sleep)
{
zend_long num;
#ifdef PHP_WIN32
const unsigned int max = UINT_MAX / 1000;
#else
const unsigned int max = UINT_MAX;
#endif

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_LONG(num)
ZEND_PARSE_PARAMETERS_END();

if (num < 0) {
zend_argument_value_error(1, "must be greater than or equal to 0");
if (num < 0 || (zend_ulong) num > max) {
zend_argument_value_error(1, "must be between 0 and %u", max);
RETURN_THROWS();
}

Expand All @@ -1146,8 +1151,8 @@ PHP_FUNCTION(usleep)
Z_PARAM_LONG(num)
ZEND_PARSE_PARAMETERS_END();

if (num < 0) {
zend_argument_value_error(1, "must be greater than or equal to 0");
if (num < 0 || (zend_ulong) num > UINT_MAX) {
zend_argument_value_error(1, "must be between 0 and %u", UINT_MAX);
RETURN_THROWS();
}

Expand Down
1 change: 0 additions & 1 deletion ext/standard/crypt_sha256.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#ifdef PHP_WIN32
# include <string.h>
#else
# include <sys/param.h>
# include <sys/types.h>
# include <string.h>
#endif
Expand Down
1 change: 0 additions & 1 deletion ext/standard/crypt_sha512.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#ifdef PHP_WIN32
# include <string.h>
#else
# include <sys/param.h>
# include <sys/types.h>
# include <string.h>
#endif
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/tests/general_functions/sleep_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ sleep(-10);

?>
--EXPECTF--
Fatal error: Uncaught ValueError: sleep(): Argument #1 ($seconds) must be greater than or equal to 0 in %s:%d
Fatal error: Uncaught ValueError: sleep(): Argument #1 ($seconds) must be between 0 and %d in %s:%d
Stack trace:
#0 %s(%d): sleep(-10)
#1 {main}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
sleep() and usleep() reject values above their unsigned int limits
--SKIPIF--
<?php
if (PHP_INT_SIZE < 8) die('skip 64-bit only');
?>
--FILE--
<?php
var_dump(sleep(0));
usleep(0);
echo "usleep(0) ok\n";

foreach (['sleep', 'usleep'] as $function) {
try {
$function(4294967296);
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
}
?>
--EXPECTF--
int(0)
usleep(0) ok
sleep(): Argument #1 ($seconds) must be between 0 and %d
usleep(): Argument #1 ($microseconds) must be between 0 and 4294967295
2 changes: 1 addition & 1 deletion ext/standard/tests/general_functions/usleep_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ usleep(-10);

?>
--EXPECTF--
Fatal error: Uncaught ValueError: usleep(): Argument #1 ($microseconds) must be greater than or equal to 0 in %s:%d
Fatal error: Uncaught ValueError: usleep(): Argument #1 ($microseconds) must be between 0 and 4294967295 in %s:%d
Stack trace:
#0 %s(%d): usleep(-10)
#1 {main}
Expand Down
2 changes: 1 addition & 1 deletion ext/uri/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ if test "$PHP_EXTERNAL_URIPARSER" = "no"; then
$URIPARSER_DIR/src/UriSetScheme.c $URIPARSER_DIR/src/UriSetUserInfo.c $URIPARSER_DIR/src/UriShorten.c $URIPARSER_DIR/src/UriVersion.c"
URI_CFLAGS="-DURI_STATIC_BUILD"
else
PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 1.0.0])
PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 1.0.3])
PHP_EVAL_LIBLINE([$LIBURIPARSER_LIBS])
PHP_EVAL_INCLINE([$LIBURIPARSER_CFLAGS])
fi
Expand Down