Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7c85926
Fix memory leak and invalid continuation after tar header writing fails
ndossche Sep 30, 2025
c3d17d9
Merge branch 'PHP-8.3' into PHP-8.4
ndossche Oct 1, 2025
fced2d8
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Oct 1, 2025
49a5331
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
9bd9e3a
Fix build
ndossche Oct 1, 2025
64d2a3f
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Oct 1, 2025
f65dcb9
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
d79baba
Fix typos and grammar in UPGRADING
theodorejb Sep 30, 2025
75b87b1
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
b7fdfb7
Fix GH-19248: Use strerror_r instead of strerror in main
bukka Jul 26, 2025
152dfa8
Merge branch 'PHP-8.3' into PHP-8.4
bukka Oct 1, 2025
879d5e9
Merge branch 'PHP-8.4' into PHP-8.5
bukka Oct 1, 2025
7b46ec6
Merge branch 'PHP-8.5'
bukka Oct 1, 2025
9fc14a9
Fix GH-16319: protect fiber backtrace with null filename from crashin…
alexandre-daubois Oct 1, 2025
0cf500e
Merge branch 'PHP-8.3' into PHP-8.4
alexandre-daubois Oct 1, 2025
fe97b5a
Merge branch 'PHP-8.4' into PHP-8.5
alexandre-daubois Oct 1, 2025
dc79609
Merge branch 'PHP-8.5'
alexandre-daubois Oct 1, 2025
0ffa337
Fix GH-17345: Bug #35916 was not completely fixed
ndossche Jun 28, 2025
7dd7ad8
Merge branch 'PHP-8.3' into PHP-8.4
ndossche Oct 1, 2025
31fefe0
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Oct 1, 2025
1a0f955
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
71f8c39
Fix test
ndossche Oct 1, 2025
466ca9f
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Oct 1, 2025
07e176c
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
b1d487a
Fix GH-20022: docker-php-ext-install DOM failed
ndossche Oct 1, 2025
52e1c9f
Merge branch 'PHP-8.4' into PHP-8.5
ndossche Oct 1, 2025
3ac2788
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
39dda72
ext/mysqli: internal updates (#19072)
devnexen Oct 1, 2025
4dc291c
[ci skip] UPGRADING
devnexen Oct 1, 2025
3a8e6a7
DOM Windows build fix (#20026)
ndossche Oct 1, 2025
fdd3762
Merge branch 'PHP-8.5'
ndossche Oct 1, 2025
9731507
[ci skip] UPGRADING typo
devnexen Oct 1, 2025
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
4 changes: 4 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ PHP 8.6 UPGRADE NOTES
11. Changes to INI File Handling
========================================

- Mysqli:
. mysqli.default_port now checks the validity of the value which should be
between 0 and 65535 included.

- Opcache:
. opcache.jit_debug accepts a new flag: ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC.
When used along with ZEND_JIT_DEBUG_TRACE_EXIT_INFO, the source of exit
Expand Down
2 changes: 1 addition & 1 deletion ext/dom/lexbor/selectors-adapted/selectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include <Zend/zend_API.h>
#include <php.h>

#include "ext/dom/lexbor/selectors-adapted/selectors.h"
#include "selectors.h"
#include "../../namespace_compat.h"
#include "../../domexception.h"
#include "../../php_dom.h"
Expand Down
15 changes: 14 additions & 1 deletion ext/mysqli/mysqli.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,19 @@ static const MYSQLND_REVERSE_API mysqli_reverse_api = {
mysqli_convert_zv_to_mysqlnd
};

static PHP_INI_MH(OnUpdateDefaultPort)
{
zend_long value = ZEND_ATOL(ZSTR_VAL(new_value));

if (value < 0 || value > USHRT_MAX) {
return FAILURE;
}

MyG(default_port) = (unsigned short)value;

return SUCCESS;
}

/* {{{ PHP_INI_BEGIN */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY_EX("mysqli.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_mysqli_globals, mysqli_globals, display_link_numbers)
Expand All @@ -433,7 +446,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("mysqli.default_host", NULL, PHP_INI_ALL, OnUpdateString, default_host, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_user", NULL, PHP_INI_ALL, OnUpdateString, default_user, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_pw", NULL, PHP_INI_ALL, OnUpdateString, default_pw, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_port", "3306", PHP_INI_ALL, OnUpdateLong, default_port, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_port", "3306", PHP_INI_ALL, OnUpdateDefaultPort, default_port, zend_mysqli_globals, mysqli_globals)
#ifdef PHP_MYSQL_UNIX_SOCK_ADDR
STD_PHP_INI_ENTRY("mysqli.default_socket", MYSQL_UNIX_ADDR,PHP_INI_ALL,OnUpdateStringUnempty, default_socket, zend_mysqli_globals, mysqli_globals)
#else
Expand Down
16 changes: 8 additions & 8 deletions ext/mysqli/php_mysqli_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,21 +236,21 @@ extern void php_mysqli_fetch_into_hash_aux(zval *return_value, MYSQL_RES * resul


ZEND_BEGIN_MODULE_GLOBALS(mysqli)
zend_long num_links;
zend_long max_links;
zend_long num_active_persistent;
zend_long num_inactive_persistent;
zend_long max_persistent;
unsigned short default_port;
bool allow_persistent;
zend_ulong default_port;
bool allow_local_infile;
char *default_host;
char *default_user;
char *default_pw;
char *default_socket;
bool allow_local_infile;
char *local_infile_directory;
zend_long error_no;
char *error_msg;
zend_long num_links;
zend_long max_links;
zend_long num_active_persistent;
zend_long num_inactive_persistent;
zend_long max_persistent;
zend_long error_no;
zend_long report_mode;
bool rollback_on_cached_plink;
ZEND_END_MODULE_GLOBALS(mysqli)
Expand Down
21 changes: 21 additions & 0 deletions ext/mysqli/tests/mysqli_default_port_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
default_port ini setting
--EXTENSIONS--
mysqli
--FILE--
<?php
$orig_port = ini_get("mysqli.default_port");
ini_set('mysqli.default_port', 65536);
$new_port = ini_get("mysqli.default_port");
var_dump($orig_port === $new_port);
ini_set('mysqli.default_port', -1);
$new_port = ini_get("mysqli.default_port");
var_dump($orig_port === $new_port);
ini_set('mysqli.default_port', $orig_port - 1);
$new_port = ini_get("mysqli.default_port");
var_dump($orig_port === $new_port);
?>
--EXPECT--
bool(true)
bool(true)
bool(false)
11 changes: 10 additions & 1 deletion ext/phar/tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,16 @@ void phar_tar_flush(phar_archive_data *phar, zend_string *user_stub, bool is_def
}

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 (must_close_old_file) {
php_stream_close(oldfile);
}

/* on error in the hash iterator above, error is set */
php_stream_close(newfile);
return;
}

/* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
if (!phar->is_data || phar->sig_flags) {
Expand Down
41 changes: 41 additions & 0 deletions ext/phar/tests/tar_flush_too_long_filename.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
Tar flush with too long file name
--EXTENSIONS--
phar
--SKIPIF--
<?php
if (getenv('SKIP_SLOW_TESTS')) die('skip');
if (function_exists('openssl_sign')) die('skip requires openssl disabled for mocking purposes');
?>
--INI--
phar.require_hash=0
--FILE--
<?php
$fname = __DIR__ . '/' . basename(__FILE__, '.php') . '.tar';

// Mock sign to fail at second invocation, tricks failure in phar_create_signature()
function openssl_sign() {
static $counter = 0;
$counter++;
if ($counter === 2) {
return false;
}
return true;
}

$phar = new PharData($fname);
$phar->addEmptyDir('blah1/');
$phar->setSignatureAlgorithm(Phar::OPENSSL, "randomcrap");
try {
$phar->addEmptyDir('blah2/' . str_repeat('X', 1000));
} catch (PharException $e) {
echo $e->getMessage();
}

?>
--CLEAN--
<?php
unlink(__DIR__ . '/' . basename(__FILE__, '.clean.php') . '.tar');
?>
--EXPECTF--
tar-based phar "%s" cannot be created, filename "%s" is too long for tar file format
49 changes: 49 additions & 0 deletions ext/standard/tests/filters/gh17345.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--TEST--
GH-17345 (Bug #35916 was not completely fixed)
--FILE--
<?php
$file = __DIR__ . "/gh17345.txt";
@unlink($file);

class strtoupper_filter extends php_user_filter
{
function filter($in, $out, &$consumed, $closing): int
{
while ($bucket=stream_bucket_make_writeable($in)) {
$bucket->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
14 changes: 8 additions & 6 deletions ext/standard/user_filters.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
}
}
/* }}} */

Expand Down
4 changes: 2 additions & 2 deletions ext/zend_test/observer.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ static void observer_show_init(zend_function *fbc)
php_printf("%*s<!-- init %s() -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->common.function_name));
}
} else {
php_printf("%*s<!-- init '%s' -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->op_array.filename));
php_printf("%*s<!-- init '%s' -->\n", 2 * ZT_G(observer_nesting_depth), "", fbc->op_array.filename ? ZSTR_VAL(fbc->op_array.filename) : "[no active file]");
}
}

Expand All @@ -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), "");
Expand Down
48 changes: 48 additions & 0 deletions ext/zend_test/tests/observer_fiber_backtrace_crash.phpt
Original file line number Diff line number Diff line change
@@ -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--
<?php
$fiber = new Fiber(function() {});
$fiber->start();
echo "Test completed without crash\n";
?>
--EXPECTF--
<!-- init %s -->
<!--
{main} %s
-->
<file %s>
<!-- init Fiber::__construct() -->
<!--
Fiber::__construct()
{main} %s
-->
<Fiber::__construct>
</Fiber::__construct>
<!-- init Fiber::start() -->
<!--
Fiber::start()
{main} %s
-->
<Fiber::start>
<!-- init {closure:%s:%d}() -->
<!--
{closure:%s:%d}()
{main} [no active file]
Fiber::start()
{main} %s
-->
<{closure:%s:%d}>
</{closure:%s:%d}>
</Fiber::start>
Test completed without crash
</file %s>
Loading