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
b7c524a
Free unbound arguments when partial application construction throws (…
iliaal Jul 17, 2026
74145e9
UPGRADING.INTERNALS: remove extra 's' [skip ci]
DanielEScherzer Jul 17, 2026
c191020
Fix double-free of closure run_time_cache in partial application (#22…
iliaal Jul 17, 2026
d79a32d
run-tests: Clean the file cache directory in --file-cache-prime (#22784)
arnaud-lb Jul 17, 2026
2fc1912
Fix inline documentation of `ReflectionParameter::isPassedByReference()`
DanielEScherzer Jul 9, 2026
8ddd6e3
Reflection: optimize closure checking
DanielEScherzer Jul 9, 2026
d0d7951
Reflection: remove unused indentation support from `_parameter_string()`
DanielEScherzer Jul 9, 2026
5457092
`ReflectionFunctionAbstract::getDocComment()`: use `zend_function.com…
DanielEScherzer Jul 9, 2026
de36957
Reflection: improve handling of dynamic properties in `_property_stri…
DanielEScherzer Jul 9, 2026
767f31a
Reflection: start cleaning up variable declarations
DanielEScherzer Jul 9, 2026
009bedb
Reflection: clean up variables for hash iteration
DanielEScherzer Jul 9, 2026
48af536
Reflection: unhoist more variable declarations
DanielEScherzer Jul 9, 2026
44608b0
Reflection: layout and indentation cleanup
DanielEScherzer Jul 9, 2026
121d19f
Reflection: use early returns to reduce indentation
DanielEScherzer Jul 9, 2026
009a0c2
ext/sockets: bound interface name copy in from_zval_write_ifindex()
iliaal Jun 21, 2026
e7df639
Merge branch 'PHP-8.5'
iliaal Jul 17, 2026
c1773a1
ext/ftp: apply the connect timeout ceiling to the remaining entry points
iliaal Jul 16, 2026
e193897
Merge branch 'PHP-8.4' into PHP-8.5
iliaal Jul 17, 2026
9046987
[skip ci] Fix typo in writing-tests.rst
LamentXU123 Jul 17, 2026
46a35ff
Merge branch 'PHP-8.5'
iliaal Jul 17, 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
2 changes: 1 addition & 1 deletion UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
zend_reflection_property_set_raw_value() to expose the functionality of
ReflectionProperty::setRawValueWithoutLazyInitialization() and
ReflectionProperty::setRawValue() to C extensions.
. zend_argument_error_variadic() now takes a new 'function' parameters.
. zend_argument_error_variadic() now takes a new 'function' parameter.
. Added zend_argument_error_ex(), zend_argument_type_error_ex(),
zend_argument_value_error_ex().
. Added zend_ast_dup().
Expand Down
19 changes: 19 additions & 0 deletions Zend/tests/partial_application/closure_rt_cache_lifetime.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Partial application over a Closure::fromCallable() must not double-free the run_time_cache
--FILE--
<?php
class C {
public function m($x, $y) { return $x + $y; }
}

$cl = Closure::fromCallable([new C, 'm']);
$partial = $cl(10, ?);
var_dump($partial(5));
unset($partial);
unset($cl);
gc_collect_cycles();
echo "OK\n";
?>
--EXPECT--
int(15)
OK
34 changes: 34 additions & 0 deletions Zend/tests/partial_application/construct_throw_arg_leak.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
Partial application must not leak bound arguments when construction throws
--FILE--
<?php
class Obj {}

function typed(int $a, $b, $c) {}
try {
typed([1, 2, 3], new Obj(), ?);
} catch (\TypeError $e) {
echo $e::class, "\n";
}

function typed2($a, int $b, $c, $d) {}
try {
typed2(new Obj(), [1, 2], new Obj(), ?);
} catch (\TypeError $e) {
echo $e::class, "\n";
}

function one($a) {}
try {
one(new Obj(), new Obj(), ?);
} catch (\ArgumentCountError $e) {
echo $e::class, "\n";
}

echo "OK\n";
?>
--EXPECT--
TypeError
TypeError
ArgumentCountError
OK
9 changes: 9 additions & 0 deletions Zend/zend_partial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,13 @@ static const zend_op_array *zp_get_op_array(zval *this_ptr, zend_function *funct
return op_array;
}

static void zp_free_unbound_args(uint32_t start, uint32_t argc, zval *argv)
{
for (uint32_t offset = start; offset < argc; offset++) {
zval_ptr_dtor_nogc(&argv[offset]);
}
}

/* Bind pre-bound arguments as lexical vars */
static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *argv,
zend_array *extra_named_params) {
Expand Down Expand Up @@ -1102,6 +1109,7 @@ static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *
zend_verify_arg_error(function, arg_info, offset+1, var);
zval_ptr_dtor(result);
ZVAL_NULL(result);
zp_free_unbound_args(offset, argc, argv);
return;
}
ZEND_ASSERT(zp_arg_must_be_sent_by_ref(function, offset+1) ? Z_ISREF_P(var) : !Z_ISREF_P(var));
Expand Down Expand Up @@ -1131,6 +1139,7 @@ void zend_partial_create(zval *result, zval *this_ptr, zend_function *function,

if (UNEXPECTED(!op_array)) {
ZEND_ASSERT(EG(exception));
zp_free_unbound_args(0, argc, argv);
ZVAL_NULL(result);
return;
}
Expand Down
2 changes: 1 addition & 1 deletion docs/source/miscellaneous/writing-tests.rst
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ and not in the INI section. This is because of the order in which settings are c
If a TZ environmental variable is found the INI setting will be ignored.

Tests that run, or only have have matching EXPECT output, on 32bit platforms can use a SKIPIF
Tests that run, or only have matching EXPECT output, on 32bit platforms can use a SKIPIF
section like:

.. code:: php
Expand Down
17 changes: 13 additions & 4 deletions ext/ftp/php_ftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include "ftp.h"
#include "ftp_arginfo.h"

#define PHP_FTP_TIMEOUT_SEC_MAX ((uint64_t)((double) PHP_TIMEOUT_ULL_MAX / 1000000.0))

static zend_class_entry *php_ftp_ce = NULL;
static zend_object_handlers ftp_object_handlers;

Expand Down Expand Up @@ -143,15 +145,13 @@ PHP_FUNCTION(ftp_connect)
RETURN_THROWS();
}

const uint64_t timeoutmax = (uint64_t)((double) PHP_TIMEOUT_ULL_MAX / 1000000.0);

if (timeout_sec <= 0) {
zend_argument_value_error(3, "must be greater than 0");
RETURN_THROWS();
}

if (timeout_sec >= timeoutmax) {
zend_argument_value_error(3, "must be less than " ZEND_ULONG_FMT, timeoutmax);
if (timeout_sec >= PHP_FTP_TIMEOUT_SEC_MAX) {
zend_argument_value_error(3, "must be less than " ZEND_ULONG_FMT, PHP_FTP_TIMEOUT_SEC_MAX);
RETURN_THROWS();
}

Expand Down Expand Up @@ -192,6 +192,11 @@ PHP_FUNCTION(ftp_ssl_connect)
RETURN_THROWS();
}

if (timeout_sec >= PHP_FTP_TIMEOUT_SEC_MAX) {
zend_argument_value_error(3, "must be less than " ZEND_ULONG_FMT, PHP_FTP_TIMEOUT_SEC_MAX);
RETURN_THROWS();
}

/* connect */
if (!(ftp = ftp_open(host, (short)port, timeout_sec))) {
RETURN_FALSE;
Expand Down Expand Up @@ -1284,6 +1289,10 @@ PHP_FUNCTION(ftp_set_option)
zend_argument_value_error(3, "must be greater than 0 for the FTP_TIMEOUT_SEC option");
RETURN_THROWS();
}
if ((uint64_t) Z_LVAL_P(z_value) >= PHP_FTP_TIMEOUT_SEC_MAX) {
zend_argument_value_error(3, "must be less than " ZEND_ULONG_FMT " for the FTP_TIMEOUT_SEC option", PHP_FTP_TIMEOUT_SEC_MAX);
RETURN_THROWS();
}
ftp->timeout_sec = Z_LVAL_P(z_value);
RETURN_TRUE;
case PHP_FTP_OPT_AUTOSEEK:
Expand Down
26 changes: 26 additions & 0 deletions ext/ftp/tests/gh20601_set_option.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-20601 (ftp_set_option FTP_TIMEOUT_SEC timeout overflow)
--EXTENSIONS--
ftp
pcntl
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die("skip: 64-bit only");
if (PHP_OS_FAMILY === 'Windows') die("skip not for windows");
?>
--FILE--
<?php
require 'server.inc';

$ftp = ftp_connect('127.0.0.1', $port);
$ftp or die("Couldn't connect to the server");
ftp_login($ftp, 'user', 'pass');

try {
ftp_set_option($ftp, FTP_TIMEOUT_SEC, PHP_INT_MAX);
} catch (\ValueError $e) {
echo $e->getMessage();
}
?>
--EXPECTF--
ftp_set_option(): Argument #3 ($value) must be less than %d for the FTP_TIMEOUT_SEC option
21 changes: 21 additions & 0 deletions ext/ftp/tests/gh20601_ssl.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
GH-20601 (ftp_ssl_connect timeout overflow)
--EXTENSIONS--
ftp
openssl
--SKIPIF--
<?php
if (!function_exists("ftp_ssl_connect")) die("skip ftp_ssl is disabled");
if (PHP_INT_SIZE != 8) die("skip: 64-bit only");
if (PHP_OS_FAMILY === 'Windows') die("skip not for windows");
?>
--FILE--
<?php
try {
ftp_ssl_connect('127.0.0.1', 1024, PHP_INT_MAX);
} catch (\ValueError $e) {
echo $e->getMessage();
}
?>
--EXPECTF--
ftp_ssl_connect(): Argument #3 ($timeout) must be less than %d
3 changes: 1 addition & 2 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -2146,8 +2146,7 @@ zend_op_array *zend_accel_compile_pfa(zend_ast *ast,
* See comment in zend_accel_pfa_key(). */
zend_op_array *copy = zend_arena_alloc(&CG(arena), sizeof(*copy));
memcpy(copy, called_function, sizeof(*copy));
zend_string_addref(copy->function_name);
(*copy->refcount)++;
function_add_ref((zend_function *) copy);
/* Reference the copy in op_array->dynamic_func_defs so that it's
* destroyed when op_array is destroyed. */
ZEND_ASSERT(!op_array->dynamic_func_defs && !op_array->num_dynamic_func_defs);
Expand Down
Loading