Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c82acef
main: convert unserialize_callback_func global to zend_string*
Girgias Jul 19, 2026
6877f77
main: convert last_error_lineno global to type uint32_t
Girgias Jul 19, 2026
1de8f4f
main: group Windows globals together
Girgias Jul 19, 2026
1b20462
main: convert doc_root global to zend_string*
Girgias Jul 19, 2026
9362fc7
main: convert error_log global to zend_string*
Girgias Jul 19, 2026
e0221be
main: convert output_handler global to zend_string*
Girgias Jul 19, 2026
d75f79e
streams: refactor _php_stream_open_wrapper_ex() to use early returns
Girgias Jul 20, 2026
f9ac6c1
streams: use php_stream_wrapper_warn() in _php_stream_open_wrapper_ex()
Girgias Jul 20, 2026
605ff6e
streams: use common cleanup code in _php_stream_open_wrapper_ex()
Girgias Jul 20, 2026
28d3216
[skip ci] Mark another preloading test as opcache.file_cache_only=0
iluuu1994 Jul 30, 2026
f12f1b4
ext/mysqli: applied fixers to improve test robustness (#22929)
NickSdot Jul 30, 2026
d3c95d1
ext/standard: Throw ValueError for filenames with null bytes
Girgias Jul 17, 2025
732243f
ext/standard: Refactor php_stat() API
Girgias Jul 17, 2025
c35253d
Free the hooked property value when json_encode() sees an exception
iliaal Jul 29, 2026
8c5e258
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Jul 30, 2026
3462275
Zend: reuse zend_parse_arg_func() in zend_parse_arg_impl() (#22937)
Girgias Jul 30, 2026
5795e33
sapi: convert current_user field to zend_string* (#22902)
Girgias Jul 30, 2026
4a42b03
Merge branch 'PHP-8.5'
iliaal Jul 30, 2026
955e2ea
Run scandir overflow test on Windows only (#22934)
NickSdot Jul 30, 2026
61a190c
Prevents tests from leaking System V IPC objects (#22912)
NickSdot Jul 30, 2026
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
7 changes: 7 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ PHP NEWS
error handler instead of emitting a warning and continuing with an empty
string. (Weilin Du)

- Standard:
. The following functions now raise a ValueError when the $filename argument
contains NUL bytes: fileperms(), fileinode(), filesize(), fileowner(),
filegroup(), fileatime(), filemtime(), filectime(), filetype(),
is_writable(), is_readable(), is_executable(), is_file(), is_dir(),
is_link(), file_exists(), lstat(), stat(). (Girgias)

30 Jul 2026, PHP 8.6.0alpha3

- Core:
Expand Down
20 changes: 20 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,26 @@ PHP 8.6 UPGRADE NOTES
bytes.
. base_convert(), bindex(), hexdec() and octdec() now raise a notice when
they cannot precisely convert the given number.
. The following functions now raise a ValueError when the $filename argument
contains NUL bytes:
- fileperms()
- fileinode()
- filesize()
- fileowner()
- filegroup()
- fileatime()
- filemtime()
- filectime()
- filetype()
- is_writable()
- is_readable()
- is_executable()
- is_file()
- is_dir()
- is_link()
- file_exists()
- lstat()
- stat()

- Sysvshm:
. shm_attach() now raises a ValueError when the $key argument is outside the
Expand Down
1 change: 0 additions & 1 deletion Zend/Optimizer/zend_func_infos.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,6 @@ static const func_info_t func_infos[] = {
#if defined(HAVE_NANOSLEEP)
F1("time_nanosleep", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_BOOL),
#endif
F1("get_current_user", MAY_BE_STRING),
FN("get_cfg_var", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE),
F1("error_get_last", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_NULL),
F1("highlight_file", MAY_BE_STRING|MAY_BE_BOOL),
Expand Down
34 changes: 34 additions & 0 deletions Zend/tests/arginfo_zpp_mismatch.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@ if (getenv('SKIP_MSAN')) die("skip msan misses interceptors for some functions")

require __DIR__ . "/arginfo_zpp_mismatch.inc";

function testWeakSysvIpcFunction($function): bool {
if (!in_array($function, ['msg_queue_exists', 'msg_get_queue', 'sem_get', 'shm_attach'], true)) {
return false;
}

for ($argumentCount = 0; $argumentCount <= 8; $argumentCount++) {
$arguments = array_fill(0, $argumentCount, null);
if ($function === 'msg_queue_exists' && $argumentCount >= 1) {
$arguments[0] = 1;
}
if (($function === 'sem_get' || $function === 'shm_attach') && $argumentCount >= 3) {
$arguments[2] = 0600;
}

try {
$result = @$function(...$arguments);
if ($result instanceof SysvMessageQueue) {
msg_remove_queue($result);
} elseif ($result instanceof SysvSemaphore) {
sem_remove($result);
} elseif ($result instanceof SysvSharedMemory) {
shm_remove($result);
}
} catch (Throwable) {
}
}

return true;
}

function test($function) {
if (skipFunction($function)) {
return;
Expand All @@ -21,6 +51,10 @@ function test($function) {
} else {
echo "Testing " . get_class($function[0]) . "::$function[1]\n";
}
if (testWeakSysvIpcFunction($function)) {
ob_end_clean();
return;
}
try {
@$function();
} catch (Throwable) {
Expand Down
1 change: 1 addition & 0 deletions Zend/tests/partial_application/constexpr_015.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
opcache.preload={PWD}/constexpr_015.inc
opcache.file_cache_only=0
--SKIPIF--
<?php
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
Expand Down
15 changes: 1 addition & 14 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -1058,21 +1058,8 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec
zend_fcall_info *fci = va_arg(*va, zend_fcall_info *);
zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
char *is_callable_error = NULL;

if (check_null && Z_TYPE_P(arg) == IS_NULL) {
fci->size = 0;
fcc->function_handler = 0;
break;
}

if (zend_fcall_info_init(arg, 0, fci, fcc, NULL, &is_callable_error) == SUCCESS) {
if (EXPECTED(zend_parse_arg_func(arg, fci, fcc, check_null, &is_callable_error, c == 'f'))) {
ZEND_ASSERT(!is_callable_error);
if (c == 'f') {
/* Release call trampolines: The function may not get called, in which case
* the trampoline will leak. Force it to be refetched during
* zend_call_function instead. */
zend_release_fcall_info_cache(fcc);
}
break;
}

Expand Down
1 change: 1 addition & 0 deletions ext/json/json_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
if (EG(exception)) {
PHP_JSON_HASH_UNPROTECT_RECURSION(recursion_rc);
zend_release_properties(prop_ht);
zval_ptr_dtor(&tmp);
return FAILURE;
}
}
Expand Down
44 changes: 44 additions & 0 deletions ext/json/tests/json_encode_hooked_property_throwing_getter.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--TEST--
json_encode() releases the hooked property value when the get hook throws
--FILE--
<?php

class Value
{
public function __destruct()
{
echo "Value::__destruct\n";
}
}

class ThrowOnFree
{
public function __destruct()
{
throw new Exception('thrown while freeing the get hook frame');
}
}

class Container
{
public $hooked {
get {
$local = new ThrowOnFree();
return new Value();
}
}
}

try {
json_encode(new Container());
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}

echo "done\n";

?>
--EXPECT--
Value::__destruct
Exception: thrown while freeing the get hook frame
done
8 changes: 4 additions & 4 deletions ext/mysqli/tests/bug36802.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mysqli
try {
$mysql->set_charset('utf8');
} catch (Error $exception) {
echo $exception->getMessage() . "\n";
echo $exception::class, ': ', $exception->getMessage(), "\n";
}
} else {
$x[0] = false;
Expand All @@ -27,7 +27,7 @@ mysqli
try {
$mysql->query("SELECT 'foo' FROM DUAL");
} catch (Error $exception) {
echo $exception->getMessage() . "\n";
echo $exception::class, ': ', $exception->getMessage(), "\n";
}

/* following operations should work */
Expand All @@ -39,8 +39,8 @@ mysqli
var_dump($x);
?>
--EXPECT--
mysqli object is not fully initialized
mysqli object is not fully initialized
Error: mysqli object is not fully initialized
Error: mysqli object is not fully initialized
array(2) {
[1]=>
string(0) ""
Expand Down
6 changes: 3 additions & 3 deletions ext/mysqli/tests/bug62885.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ $tablica = array();
try {
$test1 = mysqli_poll($test2, $test3, $tablica, 0);
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

$test2 = array();
try {
$test1 = mysqli_poll($test2, $test3, $tablica, 0);
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
echo "okey";
?>
--EXPECTF--
No stream arrays were passed
ValueError: No stream arrays were passed

Warning: mysqli_poll(): No stream arrays were passed in %s on line %d
okey
4 changes: 2 additions & 2 deletions ext/mysqli/tests/gh17900.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ $mysqli = new mysqli();
try {
$mysqli->__construct('doesnotexist');
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e::class, ': ', $e->getMessage(), "\n";
}
?>
--EXPECT--
Cannot call constructor twice
Error: Cannot call constructor twice
4 changes: 2 additions & 2 deletions ext/mysqli/tests/ghsa-h35g-vwh6-m678-auth-message.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ try {
$info = mysqli_info($conn);
var_dump($info);
} catch (Exception $e) {
echo $e->getMessage() . PHP_EOL;
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

$process->terminate();
Expand All @@ -33,5 +33,5 @@ print "done!";
[*] Sending - Malicious OK Auth Response [Extract heap through buffer over-read]: 0900000200000002000000fcff

Warning: mysqli::__construct(): OK packet message length is past the packet size in %s on line %d
Unknown error while trying to connect via tcp://127.0.0.1:%d
mysqli_sql_exception: Unknown error while trying to connect via tcp://127.0.0.1:%d
done!
8 changes: 4 additions & 4 deletions ext/mysqli/tests/mysqli_driver/write_property.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ try {
/* Read-only property */
$driver->client_info = 'test';
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e::class, ': ', $e->getMessage(), "\n";
}

$driver->report_mode = "1";
var_dump($driver->report_mode);
try {
$driver->report_mode = [];
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e::class, ': ', $e->getMessage(), "\n";
}

?>
--EXPECT--
Cannot write read-only property mysqli_driver::$client_info
Error: Cannot write read-only property mysqli_driver::$client_info
int(1)
Cannot assign array to property mysqli_driver::$report_mode of type int
TypeError: Cannot assign array to property mysqli_driver::$report_mode of type int
8 changes: 4 additions & 4 deletions ext/mysqli/tests/mysqli_driver/write_property_strict.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ try {
/* Read-only property */
$driver->client_info = 42;
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e::class, ': ', $e->getMessage(), "\n";
}

try {
$driver->report_mode = "1";
} catch (Error $e) {
echo $e->getMessage(), "\n";
echo $e::class, ': ', $e->getMessage(), "\n";
}

?>
--EXPECT--
Cannot write read-only property mysqli_driver::$client_info
Cannot assign string to property mysqli_driver::$report_mode of type int
Error: Cannot write read-only property mysqli_driver::$client_info
TypeError: Cannot assign string to property mysqli_driver::$report_mode of type int
2 changes: 1 addition & 1 deletion ext/mysqli/tests/mysqli_driver_unclonable.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ try {
$driver = new mysqli_driver;
$driver_clone = clone $driver;
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

?>
Expand Down
11 changes: 5 additions & 6 deletions ext/soap/php_sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3179,8 +3179,7 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl)
unsigned char digest[16];
size_t len = strlen(SOAP_GLOBAL(cache_dir));
time_t cached;
char *user = php_get_current_user();
size_t user_len = user ? strlen(user) + 1 : 0;
zend_string *user = php_get_current_user();

/* System architecture identification (see bug #70951) */
static const char ids[] = {SIZEOF_ZEND_LONG, SOAP_BIG_ENDIAN};
Expand All @@ -3191,13 +3190,13 @@ sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl)
PHP_MD5Update(&md5_context, ids, sizeof(ids));
PHP_MD5Final(digest, &md5_context);
make_digest(md5str, digest);
key = emalloc(len+sizeof("/wsdl-")-1+user_len+2+sizeof(md5str));
key = emalloc(len+sizeof("/wsdl-")-1+ZSTR_LEN(user)+1+2+sizeof(md5str));
memcpy(key,SOAP_GLOBAL(cache_dir),len);
memcpy(key+len,"/wsdl-",sizeof("/wsdl-")-1);
len += sizeof("/wsdl-")-1;
if (user_len) {
memcpy(key+len, user, user_len-1);
len += user_len-1;
if (ZSTR_LEN(user)) {
memcpy(key+len, ZSTR_VAL(user), ZSTR_LEN(user));
len += ZSTR_LEN(user);
key[len++] = '-';
}
if (WSDL_CACHE_VERSION <= 0x9f) {
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ PHP_FUNCTION(get_current_user)
{
ZEND_PARSE_PARAMETERS_NONE();

RETURN_STRING(php_get_current_user());
RETURN_STR_COPY(php_get_current_user());
}
/* }}} */

Expand Down Expand Up @@ -1434,7 +1434,7 @@ PHP_FUNCTION(error_get_last)
ZVAL_STR_COPY(&tmp, PG(last_error_file));
zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_FILE), &tmp);

ZVAL_LONG(&tmp, PG(last_error_lineno));
ZVAL_LONG(&tmp, (zend_long)PG(last_error_lineno));
zend_hash_update(Z_ARR_P(return_value), ZSTR_KNOWN(ZEND_STR_LINE), &tmp);

if (!Z_ISUNDEF(EG(last_fatal_error_backtrace))) {
Expand Down
1 change: 0 additions & 1 deletion ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,6 @@ function time_nanosleep(int $seconds, int $nanoseconds): array|bool {}
function time_sleep_until(float $timestamp): bool {}
#endif

/** @refcount 1 */
function get_current_user(): string {}

/** @return string|array<int|string, string|array>|false */
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions ext/standard/basic_functions_decl.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading