Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
19fc6ed
soap: Switch to new XML parser option setting API (#20020)
nielsdos Oct 1, 2025
7c85926
Fix memory leak and invalid continuation after tar header writing fails
nielsdos Sep 30, 2025
c3d17d9
Merge branch 'PHP-8.3' into PHP-8.4
nielsdos Oct 1, 2025
fced2d8
Merge branch 'PHP-8.4' into PHP-8.5
nielsdos Oct 1, 2025
49a5331
Merge branch 'PHP-8.5'
nielsdos Oct 1, 2025
9bd9e3a
Fix build
nielsdos Oct 1, 2025
64d2a3f
Merge branch 'PHP-8.4' into PHP-8.5
nielsdos Oct 1, 2025
f65dcb9
Merge branch 'PHP-8.5'
nielsdos Oct 1, 2025
d79baba
Fix typos and grammar in UPGRADING
theodorejb Sep 30, 2025
75b87b1
Merge branch 'PHP-8.5'
nielsdos 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
nielsdos Jun 28, 2025
7dd7ad8
Merge branch 'PHP-8.3' into PHP-8.4
nielsdos Oct 1, 2025
31fefe0
Merge branch 'PHP-8.4' into PHP-8.5
nielsdos Oct 1, 2025
1a0f955
Merge branch 'PHP-8.5'
nielsdos Oct 1, 2025
71f8c39
Fix test
nielsdos Oct 1, 2025
466ca9f
Merge branch 'PHP-8.4' into PHP-8.5
nielsdos Oct 1, 2025
07e176c
Merge branch 'PHP-8.5'
nielsdos Oct 1, 2025
b1d487a
Fix GH-20022: docker-php-ext-install DOM failed
nielsdos Oct 1, 2025
52e1c9f
Merge branch 'PHP-8.4' into PHP-8.5
nielsdos Oct 1, 2025
3ac2788
Merge branch 'PHP-8.5'
nielsdos 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
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 "lexbor/selectors-adapted/selectors.h"
#include "../../namespace_compat.h"
#include "../../domexception.h"
#include "../../php_dom.h"
Expand Down
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
5 changes: 4 additions & 1 deletion ext/soap/php_xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,15 @@ static xmlDocPtr soap_xmlParse_ex(xmlParserCtxtPtr ctxt)
{
xmlDocPtr ret;
if (ctxt) {
#if LIBXML_VERSION >= 21300
xmlCtxtSetOptions(ctxt, XML_PARSE_HUGE | XML_PARSE_NO_XXE | XML_PARSE_NONET | XML_PARSE_NOBLANKS);
#else
php_libxml_sanitize_parse_ctxt_options(ctxt);
/* TODO: In libxml2 2.14.0 change this to the new options API so we don't rely on deprecated APIs. */
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
ctxt->keepBlanks = 0;
ctxt->options |= XML_PARSE_HUGE;
ZEND_DIAGNOSTIC_IGNORED_END
#endif
ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
ctxt->sax->comment = soap_Comment;
ctxt->sax->warning = NULL;
Expand Down
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>
76 changes: 67 additions & 9 deletions main/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,28 @@ PHPAPI socklen_t php_sockaddr_size(php_sockaddr_storage *addr)
}
/* }}} */

#ifdef PHP_WIN32
char *php_socket_strerror_s(long err, char *buf, size_t bufsize)
{
if (buf == NULL) {
char ebuf[1024];
errno_t res = strerror_s(ebuf, sizeof(ebuf), err);
if (res == 0) {
buf = estrdup(ebuf);
} else {
buf = estrdup("Unknown error");
}
} else {
errno_t res = strerror_s(buf, bufsize, err);
if (res != 0) {
strncpy(buf, "Unknown error", bufsize);
buf[bufsize?(bufsize-1):0] = 0;
}
}
return buf;
}
#endif

/* Given a socket error code, if buf == NULL:
* emallocs storage for the error message and returns
* else
Expand All @@ -1045,16 +1067,40 @@ PHPAPI socklen_t php_sockaddr_size(php_sockaddr_storage *addr)
PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
{
#ifndef PHP_WIN32
char *errstr;

errstr = strerror(err);
# ifdef HAVE_STRERROR_R
if (buf == NULL) {
char ebuf[1024];
# ifdef STRERROR_R_CHAR_P
char *errstr = strerror_r(err, ebuf, sizeof(ebuf));
buf = estrdup(errstr);
# else
errno_t res = strerror_r(err, ebuf, sizeof(ebuf));
if (res == 0) {
buf = estrdup(ebuf);
} else {
buf = estrdup("Unknown error");
}
# endif
} else {
# ifdef STRERROR_R_CHAR_P
buf = strerror_r(err, buf, bufsize);
# else
errno_t res = strerror_r(err, buf, bufsize);
if (res != 0) {
strncpy(buf, "Unknown error", bufsize);
buf[bufsize?(bufsize-1):0] = 0;
}
# endif
}
# else
char *errstr = strerror(err);
if (buf == NULL) {
buf = estrdup(errstr);
} else {
strncpy(buf, errstr, bufsize);
buf[bufsize?(bufsize-1):0] = 0;
}
return buf;
# endif
#else
char *sysbuf = php_win32_error_to_msg(err);
if (!sysbuf[0]) {
Expand All @@ -1069,19 +1115,31 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
}

php_win32_error_msg_free(sysbuf);

return buf;
#endif
return buf;
}
/* }}} */

/* {{{ php_socket_error_str */
PHPAPI zend_string *php_socket_error_str(long err)
{
#ifndef PHP_WIN32
char *errstr;

errstr = strerror(err);
# ifdef HAVE_STRERROR_R
char ebuf[1024];
# ifdef STRERROR_R_CHAR_P
char *errstr = strerror_r(err, ebuf, sizeof(ebuf));
# else
const char *errstr;
errno_t res = strerror_r(err, ebuf, sizeof(ebuf));
if (res == 0) {
errstr = ebuf;
} else {
errstr = "Unknown error";
}
# endif
# else
char *errstr = strerror(err);
# endif
return zend_string_init(errstr, strlen(errstr), 0);
#else
zend_string *ret;
Expand Down
5 changes: 5 additions & 0 deletions main/php_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@
* unless buf is not NULL.
* Also works sensibly for win32 */
BEGIN_EXTERN_C()
#ifdef PHP_WIN32
char *php_socket_strerror_s(long err, char *buf, size_t bufsize);
#else
#define php_socket_strerror_s php_socket_strerror
#endif
PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize);
PHPAPI zend_string *php_socket_error_str(long err);
END_EXTERN_C()
Expand Down
3 changes: 2 additions & 1 deletion main/rfc1867.c
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,8 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)
if (wlen == (size_t)-1) {
/* write failed */
#if DEBUG_FILE_UPLOAD
sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
char errstr[256];
sapi_module.sapi_error(E_NOTICE, "write() failed - %s", php_socket_strerror_s(errno, errstr, sizeof(errstr)));
#endif
cancel_upload = PHP_UPLOAD_ERROR_F;
} else if (wlen < blen) {
Expand Down
1 change: 1 addition & 0 deletions main/streams/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ PHPAPI void php_stream_bucket_prepend(php_stream_bucket_brigade *brigade, php_st

PHPAPI void php_stream_bucket_append(php_stream_bucket_brigade *brigade, php_stream_bucket *bucket)
{
/* TODO: this was added as a bad workaround for bug #35916 and should be removed in the future. */
if (brigade->tail == bucket) {
return;
}
Expand Down
Loading
Loading