From ff23286266fb84dc342dc7bb8a6dd0ca970dcf58 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Fri, 17 Jul 2026 15:30:43 +0200 Subject: [PATCH 1/5] Size is always one in curl functions (#22733) Assert and take advantage of that size is always 1. This is also documented in [the curl docs](https://curl.se/libcurl/c/CURLOPT_READFUNCTION.html). So there is no need to multiply with size, so this can be removed. I started this to see whether size * nmemb can overflow. This makes it clear that it cannot. --- ext/curl/interface.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index c0286069776e..2571eb60e42d 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -522,9 +522,11 @@ PHP_MSHUTDOWN_FUNCTION(curl) /* {{{ curl_write */ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) { + ZEND_ASSERT(size == 1); + php_curl *ch = (php_curl *) ctx; php_curl_write *write_handler = ch->handlers.write; - size_t length = size * nmemb; + size_t length = nmemb; #if PHP_CURL_DEBUG fprintf(stderr, "curl_write() called\n"); @@ -786,6 +788,8 @@ static int curl_ssh_hostkeyfunction(void *clientp, int keytype, const char *key, /* {{{ curl_read */ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) { + ZEND_ASSERT(size == 1); + php_curl *ch = (php_curl *)ctx; php_curl_read *read_handler = ch->handlers.read; size_t length = 0; @@ -808,7 +812,7 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) } else { ZVAL_NULL(&argv[1]); } - ZVAL_LONG(&argv[2], (int)size * nmemb); + ZVAL_LONG(&argv[2], (zend_long) nmemb); ch->in_callback = true; zend_call_known_fcc(&read_handler->fcc, &retval, /* param_count */ 3, argv, /* named_params */ NULL); @@ -816,7 +820,7 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx) if (!Z_ISUNDEF(retval)) { _php_curl_verify_handlers(ch, /* reporterror */ true); if (Z_TYPE(retval) == IS_STRING) { - length = MIN(size * nmemb, Z_STRLEN(retval)); + length = MIN(nmemb, Z_STRLEN(retval)); memcpy(data, Z_STRVAL(retval), length); } else if (Z_TYPE(retval) == IS_LONG) { length = Z_LVAL_P(&retval); @@ -884,9 +888,11 @@ static int curl_seek(void *clientp, curl_off_t offset, int origin) /* {{{ curl_write_header */ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx) { + ZEND_ASSERT(size == 1); + php_curl *ch = (php_curl *) ctx; php_curl_write *write_handler = ch->handlers.write_header; - size_t length = size * nmemb; + size_t length = nmemb; switch (write_handler->method) { case PHP_CURL_STDOUT: From 1f7abed78993fb0ae780eff2fa489a851bc90fd6 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Jul 2026 17:43:49 +0100 Subject: [PATCH 2/5] streams: remove php_stream_wrapper_warn_param() functions And instead let the normal docref error handling code handle arguments --- Zend/tests/display_error_function_args.phpt | 2 +- .../session_set_save_handler_variation4.phpt | 2 +- .../session_set_save_handler_variation5.phpt | 2 +- ext/standard/tests/file/copy_variation4.phpt | 8 ++-- .../tests/file/copy_variation5-win32.phpt | 4 +- .../tests/file/mkdir_rmdir_error.phpt | 2 +- .../file/mkdir_rmdir_variation-win32-mb.phpt | 2 +- .../file/mkdir_rmdir_variation-win32.phpt | 2 +- .../tests/file/mkdir_rmdir_variation2.phpt | 2 +- .../readlink_realpath_variation2-win32.phpt | 4 +- .../file/readlink_realpath_variation2.phpt | 4 +- .../tests/file/rename_variation-win32.phpt | 2 +- ext/standard/tests/file/rename_variation.phpt | 2 +- .../tests/file/rmdir_variation3-win32.phpt | 6 +-- ext/standard/tests/file/rmdir_variation3.phpt | 6 +-- .../tests/file/unlink_error-win32-mb.phpt | 4 +- .../tests/file/unlink_error-win32.phpt | 4 +- ext/standard/tests/file/unlink_error.phpt | 4 +- .../file/unlink_variation1-win32-mb.phpt | 2 +- .../tests/file/unlink_variation1-win32.phpt | 2 +- .../tests/file/unlink_variation1.phpt | 2 +- .../tests/file/unlink_variation10.phpt | 2 +- .../tests/file/unlink_variation4.phpt | 2 +- .../tests/file/unlink_variation8-win32.phpt | 10 ++--- .../tests/file/unlink_variation8.phpt | 30 +++++++------- .../tests/file/unlink_variation9-win32.phpt | 10 ++--- ext/zlib/tests/gh19922.phpt | 3 +- main/streams/php_stream_errors.h | 20 ---------- main/streams/plain_wrapper.c | 40 +++++++++---------- main/streams/stream_errors.c | 32 --------------- main/streams/streams.c | 15 +++---- .../open_basedir_copy_variation1.phpt | 2 +- 32 files changed, 88 insertions(+), 146 deletions(-) diff --git a/Zend/tests/display_error_function_args.phpt b/Zend/tests/display_error_function_args.phpt index c28a4a2808b4..03530eb98189 100644 --- a/Zend/tests/display_error_function_args.phpt +++ b/Zend/tests/display_error_function_args.phpt @@ -25,6 +25,6 @@ Warning: unlink('/'): %s in %s on line %d Warning: password_hash(Object(SensitiveParameterValue), '2y', Array): The "salt" option has been ignored, since providing a custom salt is no longer supported in %s on line %d -Warning: unlink(/): %s in %s on line %d +Warning: unlink(): %s in %s on line %d Warning: password_hash(): The "salt" option has been ignored, since providing a custom salt is no longer supported in %s on line %d diff --git a/ext/session/tests/user_session_module/session_set_save_handler_variation4.phpt b/ext/session/tests/user_session_module/session_set_save_handler_variation4.phpt index cb708e33f52b..84e49f26d122 100644 --- a/ext/session/tests/user_session_module/session_set_save_handler_variation4.phpt +++ b/ext/session/tests/user_session_module/session_set_save_handler_variation4.phpt @@ -83,6 +83,6 @@ array(3) { } Destroy [%s,%s] -Warning: unlink(%s): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d Close [%s,PHPSESSID] bool(true) diff --git a/ext/session/tests/user_session_module/session_set_save_handler_variation5.phpt b/ext/session/tests/user_session_module/session_set_save_handler_variation5.phpt index a3e21c35e49d..7354f90f28ca 100644 --- a/ext/session/tests/user_session_module/session_set_save_handler_variation5.phpt +++ b/ext/session/tests/user_session_module/session_set_save_handler_variation5.phpt @@ -97,6 +97,6 @@ GC [0] bool(true) Destroy [%s,PHPT-%d] -Warning: unlink(%s): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d Close [%s,PHPSESSID] bool(true) diff --git a/ext/standard/tests/file/copy_variation4.phpt b/ext/standard/tests/file/copy_variation4.phpt index d467cb4ce9ab..4dc318789488 100644 --- a/ext/standard/tests/file/copy_variation4.phpt +++ b/ext/standard/tests/file/copy_variation4.phpt @@ -91,7 +91,7 @@ Destination file name => %s/ Size of source file => int(1500) Size of destination file => int(%d) -Warning: unlink(%s): %s +Warning: unlink(): %s -- Iteration 2 -- Existence of destination file before copy => bool(true) @@ -103,7 +103,7 @@ Destination file name => %s/ Size of source file => int(1500) Size of destination file => int(%d) -Warning: unlink(%s): %s +Warning: unlink(): %s -- Iteration 3 -- Existence of destination file before copy => bool(true) @@ -115,7 +115,7 @@ Destination file name => %s/ Size of source file => int(1500) Size of destination file => int(%d) -Warning: unlink(%s): %s +Warning: unlink(): %s -- Iteration 4 -- Existence of destination file before copy => bool(true) @@ -127,7 +127,7 @@ Destination file name => %s/ Size of source file => int(1500) Size of destination file => int(%d) -Warning: unlink(%s): %s +Warning: unlink(): %s -- Iteration 5 -- Existence of destination file before copy => bool(false) diff --git a/ext/standard/tests/file/copy_variation5-win32.phpt b/ext/standard/tests/file/copy_variation5-win32.phpt index af352dbe0732..e4c42e2f9322 100644 --- a/ext/standard/tests/file/copy_variation5-win32.phpt +++ b/ext/standard/tests/file/copy_variation5-win32.phpt @@ -98,7 +98,7 @@ Destination file name => %s/CopY5.TMP Size of source file => int(1500) Size of destination file => int(1500) -Warning: unlink(%s/COPY5.TMP): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -Warning: unlink(%s/CopY5.TMP): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d *** Done *** diff --git a/ext/standard/tests/file/mkdir_rmdir_error.phpt b/ext/standard/tests/file/mkdir_rmdir_error.phpt index 4500de027668..44dc68f6da47 100644 --- a/ext/standard/tests/file/mkdir_rmdir_error.phpt +++ b/ext/standard/tests/file/mkdir_rmdir_error.phpt @@ -11,6 +11,6 @@ echo "Done\n"; --EXPECTF-- *** Testing rmdir() on non-existent directory *** -Warning: rmdir(temp): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d bool(false) Done diff --git a/ext/standard/tests/file/mkdir_rmdir_variation-win32-mb.phpt b/ext/standard/tests/file/mkdir_rmdir_variation-win32-mb.phpt index b6c186ed0b09..4e642cf7ae03 100644 --- a/ext/standard/tests/file/mkdir_rmdir_variation-win32-mb.phpt +++ b/ext/standard/tests/file/mkdir_rmdir_variation-win32-mb.phpt @@ -1596,7 +1596,7 @@ bool(true) *** Testing rmdir() on a non-empty directory *** bool(true) -Warning: rmdir(%s/mkdir私はガラスを食べられます/): Directory not empty in %s on line %d +Warning: rmdir(): Directory not empty in %s on line %d bool(false) *** Testing mkdir() and rmdir() for binary safe functionality *** diff --git a/ext/standard/tests/file/mkdir_rmdir_variation-win32.phpt b/ext/standard/tests/file/mkdir_rmdir_variation-win32.phpt index f4f412e802ff..377de5e6b9fe 100644 --- a/ext/standard/tests/file/mkdir_rmdir_variation-win32.phpt +++ b/ext/standard/tests/file/mkdir_rmdir_variation-win32.phpt @@ -1596,7 +1596,7 @@ bool(true) *** Testing rmdir() on a non-empty directory *** bool(true) -Warning: rmdir(%s/mkdir/): Directory not empty in %s on line %d +Warning: rmdir(): Directory not empty in %s on line %d bool(false) *** Testing mkdir() and rmdir() for binary safe functionality *** diff --git a/ext/standard/tests/file/mkdir_rmdir_variation2.phpt b/ext/standard/tests/file/mkdir_rmdir_variation2.phpt index 4da0b374ba94..831cb0c95662 100644 --- a/ext/standard/tests/file/mkdir_rmdir_variation2.phpt +++ b/ext/standard/tests/file/mkdir_rmdir_variation2.phpt @@ -56,7 +56,7 @@ bool(true) *** Testing rmdir() on a non-empty directory *** bool(true) -Warning: rmdir(%s/mkdir_variation2/): %s on line %d +Warning: rmdir(): %s on line %d bool(false) *** Testing mkdir() and rmdir() for binary safe functionality *** diff --git a/ext/standard/tests/file/readlink_realpath_variation2-win32.phpt b/ext/standard/tests/file/readlink_realpath_variation2-win32.phpt index f1f561538179..8de003eacd77 100644 --- a/ext/standard/tests/file/readlink_realpath_variation2-win32.phpt +++ b/ext/standard/tests/file/readlink_realpath_variation2-win32.phpt @@ -80,7 +80,7 @@ Warning: readlink(): readlink failed to read the symbolic link (%s), error %d in bool(false) bool(false) -Warning: unlink(%s/./readlink_realpath_variation2/home/../home//tests//..//..//..//home//readlink_realpath_variation2_link.tmp/): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- Testing readlink() and realpath() with hardlink, linkname stored inside an array -- bool(true) @@ -94,5 +94,5 @@ Warning: readlink(): readlink failed to read the symbolic link (%s), error %d in bool(false) bool(false) -Warning: unlink(%s/./readlink_realpath_variation2/home/../home//tests//..//..//..//home//readlink_realpath_variation2_link.tmp/): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d Done diff --git a/ext/standard/tests/file/readlink_realpath_variation2.phpt b/ext/standard/tests/file/readlink_realpath_variation2.phpt index e7d681036e26..02d024d5e973 100644 --- a/ext/standard/tests/file/readlink_realpath_variation2.phpt +++ b/ext/standard/tests/file/readlink_realpath_variation2.phpt @@ -77,7 +77,7 @@ Warning: readlink(): No such file or directory in %s on line %d bool(false) bool(false) -Warning: unlink(%s/./readlink_realpath_variation2/home/../home//tests//..//..//..//home//readlink_realpath_variation2_link.tmp/): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- Testing readlink() and realpath() with hardlink, linkname stored inside an array -- bool(true) @@ -93,5 +93,5 @@ Warning: readlink(): No such file or directory in %s on line %d bool(false) bool(false) -Warning: unlink(%s/./readlink_realpath_variation2/home/../home//tests//..//..//..//home//readlink_realpath_variation2_link.tmp/): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d Done diff --git a/ext/standard/tests/file/rename_variation-win32.phpt b/ext/standard/tests/file/rename_variation-win32.phpt index 158a8421ec79..e9614c1f8a4c 100644 --- a/ext/standard/tests/file/rename_variation-win32.phpt +++ b/ext/standard/tests/file/rename_variation-win32.phpt @@ -66,7 +66,7 @@ bool(false) bool(false) bool(false) -Warning: unlink(%s/rename_variation2.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- Iteration 3 -- bool(true) bool(false) diff --git a/ext/standard/tests/file/rename_variation.phpt b/ext/standard/tests/file/rename_variation.phpt index 88ad26080f4a..ce50e98d89f0 100644 --- a/ext/standard/tests/file/rename_variation.phpt +++ b/ext/standard/tests/file/rename_variation.phpt @@ -60,7 +60,7 @@ bool(false) bool(false) bool(false) -Warning: unlink(%s): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- Iteration 3 -- bool(true) bool(false) diff --git a/ext/standard/tests/file/rmdir_variation3-win32.phpt b/ext/standard/tests/file/rmdir_variation3-win32.phpt index 7a478b8a5cfa..4f39ae5caf4d 100644 --- a/ext/standard/tests/file/rmdir_variation3-win32.phpt +++ b/ext/standard/tests/file/rmdir_variation3-win32.phpt @@ -75,10 +75,10 @@ Directory removed Directory removed -- removing rmdirVar3.tmp\..\BADDIR\aSubDir -- -Warning: rmdir(rmdirVar3.tmp\..\BADDIR\aSubDir): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d -- removing BADDIR\aSubDir -- -Warning: rmdir(BADDIR\aSubDir): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d -- removing %s\rmdirVar3.tmp\aSubDir -- Directory removed -- removing %s\.\rmdirVar3.tmp\aSubDir -- @@ -87,7 +87,7 @@ Directory removed Directory removed -- removing %s\BADDIR\aSubDir -- -Warning: rmdir(%s\BADDIR\aSubDir): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d -- removing rmdirVar3.tmp\aSubDir\ -- Directory removed -- removing %s\rmdirVar3.tmp\aSubDir\ -- diff --git a/ext/standard/tests/file/rmdir_variation3.phpt b/ext/standard/tests/file/rmdir_variation3.phpt index efd66c8bdfd4..3e8cea123805 100644 --- a/ext/standard/tests/file/rmdir_variation3.phpt +++ b/ext/standard/tests/file/rmdir_variation3.phpt @@ -65,10 +65,10 @@ Directory removed Directory removed -- removing rmdirVar3.tmp/../BADDIR/aSubDir -- -Warning: rmdir(rmdirVar3.tmp/../BADDIR/aSubDir): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d -- removing BADDIR/aSubDir -- -Warning: rmdir(BADDIR/aSubDir): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d -- removing %s/rmdirVar3.tmp/aSubDir -- Directory removed -- removing %s/./rmdirVar3.tmp/aSubDir -- @@ -77,7 +77,7 @@ Directory removed Directory removed -- removing %s/BADDIR/aSubDir -- -Warning: rmdir(%s/BADDIR/aSubDir): No such file or directory in %s on line %d +Warning: rmdir(): No such file or directory in %s on line %d -- removing rmdirVar3.tmp/aSubDir/ -- Directory removed -- removing %s/rmdirVar3.tmp/aSubDir/ -- diff --git a/ext/standard/tests/file/unlink_error-win32-mb.phpt b/ext/standard/tests/file/unlink_error-win32-mb.phpt index df98e2e36735..a62114fe7dab 100644 --- a/ext/standard/tests/file/unlink_error-win32-mb.phpt +++ b/ext/standard/tests/file/unlink_error-win32-mb.phpt @@ -65,11 +65,11 @@ bool(false) -- Testing unlink() on non-existent file -- -Warning: unlink(%s/non_existent_file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d bool(false) -- Testing unlink() on directory -- -Warning: unlink(%s/unlink_error): Is a directory in %s on line %d +Warning: unlink(): Is a directory in %s on line %d bool(false) Done diff --git a/ext/standard/tests/file/unlink_error-win32.phpt b/ext/standard/tests/file/unlink_error-win32.phpt index 6bce3d4b8060..1e4500d2b7e8 100644 --- a/ext/standard/tests/file/unlink_error-win32.phpt +++ b/ext/standard/tests/file/unlink_error-win32.phpt @@ -62,11 +62,11 @@ bool(false) -- Testing unlink() on non-existent file -- -Warning: unlink(%s/non_existent_file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d bool(false) -- Testing unlink() on directory -- -Warning: unlink(%s/unlink_error): Is a directory in %s on line %d +Warning: unlink(): Is a directory in %s on line %d bool(false) Done diff --git a/ext/standard/tests/file/unlink_error.phpt b/ext/standard/tests/file/unlink_error.phpt index 1dd8ef1a25c9..8174f1b01268 100644 --- a/ext/standard/tests/file/unlink_error.phpt +++ b/ext/standard/tests/file/unlink_error.phpt @@ -61,11 +61,11 @@ bool(false) -- Testing unlink() on non-existent file -- -Warning: unlink(%s/non_existent_file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d bool(false) -- Testing unlink() on directory -- -Warning: unlink(%s/unlink_error): %s in %s on line %d +Warning: unlink(): %s in %s on line %d bool(false) Done diff --git a/ext/standard/tests/file/unlink_variation1-win32-mb.phpt b/ext/standard/tests/file/unlink_variation1-win32-mb.phpt index 8d2a80726a67..37132d13d63a 100644 --- a/ext/standard/tests/file/unlink_variation1-win32-mb.phpt +++ b/ext/standard/tests/file/unlink_variation1-win32-mb.phpt @@ -77,7 +77,7 @@ bool(true) -- Unlinking file without write permission, its dir having default permission -- bool(true) -Warning: unlink(%s/unlink_variation1/unlink_variation1-win32.tmp): Permission denied in %s on line %d +Warning: unlink(): Permission denied in %s on line %d bool(false) bool(true) bool(false) diff --git a/ext/standard/tests/file/unlink_variation1-win32.phpt b/ext/standard/tests/file/unlink_variation1-win32.phpt index 813e4a2e77fc..c6a0f8804a38 100644 --- a/ext/standard/tests/file/unlink_variation1-win32.phpt +++ b/ext/standard/tests/file/unlink_variation1-win32.phpt @@ -75,7 +75,7 @@ bool(true) -- Unlinking file without write permission, its dir having default permission -- bool(true) -Warning: unlink(%s/unlink_variation1/unlink_variation1-win32.tmp): Permission denied in %s on line %d +Warning: unlink(): Permission denied in %s on line %d bool(false) bool(true) bool(false) diff --git a/ext/standard/tests/file/unlink_variation1.phpt b/ext/standard/tests/file/unlink_variation1.phpt index eafdf92f1f06..5f6320b60651 100644 --- a/ext/standard/tests/file/unlink_variation1.phpt +++ b/ext/standard/tests/file/unlink_variation1.phpt @@ -64,7 +64,7 @@ echo "Done\n"; -- Unlink file having default permission and its dir having read only permission -- bool(true) -Warning: unlink(%s): %s in %s on line %d +Warning: unlink(): %s in %s on line %d bool(false) bool(false) bool(true) diff --git a/ext/standard/tests/file/unlink_variation10.phpt b/ext/standard/tests/file/unlink_variation10.phpt index 127b070d23a2..4a3c8de596fc 100644 --- a/ext/standard/tests/file/unlink_variation10.phpt +++ b/ext/standard/tests/file/unlink_variation10.phpt @@ -95,4 +95,4 @@ directory unlinked --- try to unlink a directory --- -Warning: unlink(unlinkVar10.tmp/linkme.tmp): %s in %s on line %d +Warning: unlink(): %s in %s on line %d diff --git a/ext/standard/tests/file/unlink_variation4.phpt b/ext/standard/tests/file/unlink_variation4.phpt index 99dd0c632dbb..193d50821abd 100644 --- a/ext/standard/tests/file/unlink_variation4.phpt +++ b/ext/standard/tests/file/unlink_variation4.phpt @@ -29,6 +29,6 @@ echo "Done\n"; bool(true) bool(false) -Warning: unlink(%s/unlink_variation4.tmp): %s in %s on line %d +Warning: unlink(): %s in %s on line %d bool(false) Done diff --git a/ext/standard/tests/file/unlink_variation8-win32.phpt b/ext/standard/tests/file/unlink_variation8-win32.phpt index 016beddce1c1..1a9afcae7ff2 100644 --- a/ext/standard/tests/file/unlink_variation8-win32.phpt +++ b/ext/standard/tests/file/unlink_variation8-win32.phpt @@ -80,10 +80,10 @@ file removed file removed -- removing unlinkVar8.tmp/../BADDIR/file.tmp -- -Warning: unlink(unlinkVar8.tmp/../BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing BADDIR/file.tmp -- -Warning: unlink(BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing %s/unlinkVar8.tmp/file.tmp -- file removed -- removing %s/./unlinkVar8.tmp/file.tmp -- @@ -92,13 +92,13 @@ file removed file removed -- removing %s/BADDIR/file.tmp -- -Warning: unlink(%s/BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(unlinkVar8.tmp/file.tmp/): %rNo such file or directory|Not a directory%r in %s on line %d +Warning: unlink(): %rNo such file or directory|Not a directory%r in %s on line %d -- removing %s/unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(%s/unlinkVar8.tmp/file.tmp/): %rNo such file or directory|Not a directory%r in %s on line %d +Warning: unlink(): %rNo such file or directory|Not a directory%r in %s on line %d -- removing unlinkVar8.tmp//file.tmp -- file removed -- removing %s//unlinkVar8.tmp//file.tmp -- diff --git a/ext/standard/tests/file/unlink_variation8.phpt b/ext/standard/tests/file/unlink_variation8.phpt index 71eca9199acd..d79d9e805787 100644 --- a/ext/standard/tests/file/unlink_variation8.phpt +++ b/ext/standard/tests/file/unlink_variation8.phpt @@ -123,22 +123,22 @@ file unlinked file unlinked -- removing unlinkVar8.tmp/../BADDIR/file.tmp -- -Warning: unlink(unlinkVar8.tmp/../BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- unlinking soft link unlinkVar8.tmp/../BADDIR/file.tmp -- -Warning: unlink(unlinkVar8.tmp/../BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- unlinking hard link unlinkVar8.tmp/../BADDIR/file.tmp -- -Warning: unlink(unlinkVar8.tmp/../BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing BADDIR/file.tmp -- -Warning: unlink(BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- unlinking soft link BADDIR/file.tmp -- -Warning: unlink(BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- unlinking hard link BADDIR/file.tmp -- -Warning: unlink(BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing /%s/unlinkVar8.tmp/file.tmp -- file removed -- unlinking soft link /%s/unlinkVar8.tmp/file.tmp -- @@ -159,31 +159,31 @@ file unlinked file unlinked -- removing /%s/BADDIR/file.tmp -- -Warning: unlink(/%s/BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- unlinking soft link /%s/BADDIR/file.tmp -- -Warning: unlink(/%s/BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- unlinking hard link /%s/BADDIR/file.tmp -- -Warning: unlink(/%s/BADDIR/file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(unlinkVar8.tmp/file.tmp/): Not a directory in %s on line %d +Warning: unlink(): Not a directory in %s on line %d -- unlinking soft link unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(unlinkVar8.tmp/file.tmp/): %s directory in %s on line %d +Warning: unlink(): %s directory in %s on line %d -- unlinking hard link unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(unlinkVar8.tmp/file.tmp/): Not a directory in %s on line %d +Warning: unlink(): Not a directory in %s on line %d -- removing /%s/unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(/%s/unlinkVar8.tmp/file.tmp/): Not a directory in %s on line %d +Warning: unlink(): Not a directory in %s on line %d -- unlinking soft link /%s/unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(/%s/unlinkVar8.tmp/file.tmp/): %s directory in %s on line %d +Warning: unlink(): %s directory in %s on line %d -- unlinking hard link /%s/unlinkVar8.tmp/file.tmp/ -- -Warning: unlink(/%s/unlinkVar8.tmp/file.tmp/): Not a directory in %s on line %d +Warning: unlink(): Not a directory in %s on line %d -- removing unlinkVar8.tmp//file.tmp -- file removed -- unlinking soft link unlinkVar8.tmp//file.tmp -- diff --git a/ext/standard/tests/file/unlink_variation9-win32.phpt b/ext/standard/tests/file/unlink_variation9-win32.phpt index 68e11be92763..d5406f99d85f 100644 --- a/ext/standard/tests/file/unlink_variation9-win32.phpt +++ b/ext/standard/tests/file/unlink_variation9-win32.phpt @@ -82,10 +82,10 @@ file removed file removed -- removing unlinkVar9.tmp\..\BADDIR\file.tmp -- -Warning: unlink(unlinkVar9.tmp\..\BADDIR\file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing BADDIR\file.tmp -- -Warning: unlink(BADDIR\file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing %s\unlinkVar9.tmp\file.tmp -- file removed -- removing %s\.\unlinkVar9.tmp\file.tmp -- @@ -94,13 +94,13 @@ file removed file removed -- removing %s\BADDIR\file.tmp -- -Warning: unlink(%s\BADDIR\file.tmp): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d -- removing unlinkVar9.tmp\file.tmp\ -- -Warning: unlink(unlinkVar9.tmp\file.tmp\): %rNo such file or directory|Not a directory%r in %s on line %d +Warning: unlink(): %rNo such file or directory|Not a directory%r in %s on line %d -- removing %s\unlinkVar9.tmp\file.tmp\ -- -Warning: unlink(%s\unlinkVar9.tmp\file.tmp\): %rNo such file or directory|Not a directory%r in %s on line %d +Warning: unlink(): %rNo such file or directory|Not a directory%r in %s on line %d -- removing unlinkVar9.tmp\\file.tmp -- file removed -- removing %s\\unlinkVar9.tmp\\file.tmp -- diff --git a/ext/zlib/tests/gh19922.phpt b/ext/zlib/tests/gh19922.phpt index 71644512e665..a9d76a331310 100644 --- a/ext/zlib/tests/gh19922.phpt +++ b/ext/zlib/tests/gh19922.phpt @@ -7,6 +7,5 @@ zlib var_dump(gzopen("php://output", 14)); ?> --EXPECTF-- - -Warning: gzopen(php://output): could not make seekable - php://output in %s on line %d +Warning: gzopen(): could not make seekable - php://output in %s on line %d bool(false) diff --git a/main/streams/php_stream_errors.h b/main/streams/php_stream_errors.h index 239a34ff870f..438397a24ded 100644 --- a/main/streams/php_stream_errors.h +++ b/main/streams/php_stream_errors.h @@ -130,11 +130,6 @@ PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_con zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); -PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) - ZEND_ATTRIBUTE_FORMAT(printf, 9, 10); - PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, bool terminating, zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 6, 7); @@ -145,11 +140,6 @@ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, zend_enum_StreamErrorCode code, const char *fmt, ...) ZEND_ATTRIBUTE_FORMAT(printf, 7, 8); -PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) - ZEND_ATTRIBUTE_FORMAT(printf, 8, 9); - PHPAPI void php_stream_display_wrapper_name_errors(const char *wrapper_name, php_stream_context *context, zend_enum_StreamErrorCode code, const char *path, const char *caption); @@ -179,16 +169,6 @@ PHPAPI void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper); php_stream_wrapper_error(wrapper, context, NULL, options, E_NOTICE, false, \ PHP_STREAM_EC(code), __VA_ARGS__) -#define php_stream_wrapper_warn_param(wrapper, context, options, code, param, ...) \ - php_stream_wrapper_error_param( \ - wrapper, context, NULL, options, E_WARNING, true, \ - PHP_STREAM_EC(code), param, __VA_ARGS__) - -#define php_stream_wrapper_warn_param_nt(wrapper, context, options, code, param, ...) \ - php_stream_wrapper_error_param( \ - wrapper, context, NULL, options, E_WARNING, false, \ - PHP_STREAM_EC(code), param, __VA_ARGS__) - #define php_stream_warn(stream, code, ...) \ php_stream_error(stream, NULL, E_WARNING, true, PHP_STREAM_EC(code), __VA_ARGS__) diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index a95ca0eab768..9289b6b5ec6e 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -1327,9 +1327,9 @@ static int php_plain_files_unlink(php_stream_wrapper *wrapper, const char *url, if (ret == -1) { if (options & REPORT_ERRORS) { char errstr[256]; - php_stream_wrapper_warn_param(wrapper, context, options, - UnlinkFailed, url, - "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn(wrapper, context, options, + UnlinkFailed, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); } return 0; } @@ -1572,17 +1572,17 @@ static int php_plain_files_rmdir(php_stream_wrapper *wrapper, const char *url, i char errstr[256]; #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { - php_stream_wrapper_warn_param(wrapper, context, options, - NotFound, url, - "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); + php_stream_wrapper_warn(wrapper, context, options, + NotFound, "%s", + php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } #endif if (VCWD_RMDIR(url) < 0) { - php_stream_wrapper_warn_param(wrapper, context, options, - RmdirFailed, url, - "%s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); + php_stream_wrapper_warn(wrapper, context, options, + RmdirFailed, "%s", + php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } @@ -1605,9 +1605,9 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url #ifdef PHP_WIN32 if (!php_win32_check_trailing_space(url, strlen(url))) { - php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - NotFound, url, - "%s", php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, + NotFound, "%s", + php_socket_strerror_s(ENOENT, errstr, sizeof(errstr))); return 0; } #endif @@ -1626,8 +1626,8 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url if (VCWD_ACCESS(url, F_OK) != 0) { FILE *file = VCWD_FOPEN(url, "w"); if (file == NULL) { - php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - PermissionDenied, url, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, + PermissionDenied, "Unable to create file %s because %s", url, php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; @@ -1642,8 +1642,8 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url case PHP_STREAM_META_OWNER: if(option == PHP_STREAM_META_OWNER_NAME) { if(php_get_uid_by_name((char *)value, &uid) != SUCCESS) { - php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - MetaFailed, url, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, + MetaFailed, "Unable to find uid for %s", (char *)value); return 0; } @@ -1656,8 +1656,8 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url case PHP_STREAM_META_GROUP_NAME: if(option == PHP_STREAM_META_GROUP_NAME) { if(php_get_gid_by_name((char *)value, &gid) != SUCCESS) { - php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - MetaFailed, url, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, + MetaFailed, "Unable to find gid for %s", (char *)value); return 0; } @@ -1676,8 +1676,8 @@ static int php_plain_files_metadata(php_stream_wrapper *wrapper, const char *url return 0; } if (ret == -1) { - php_stream_wrapper_warn_param(wrapper, context, REPORT_ERRORS, - MetaFailed, url, + php_stream_wrapper_warn(wrapper, context, REPORT_ERRORS, + MetaFailed, "Operation failed: %s", php_socket_strerror_s(errno, errstr, sizeof(errstr))); return 0; } diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index 3b64e6ba39c5..c70b8f3f53b6 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -626,26 +626,6 @@ PHPAPI void php_stream_wrapper_error(php_stream_wrapper *wrapper, php_stream_con wrapper_name, context, docref, options, severity, terminating, code, NULL, message); } -PHPAPI void php_stream_wrapper_error_param(php_stream_wrapper *wrapper, php_stream_context *context, - const char *docref, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) -{ - if (!(options & REPORT_ERRORS)) { - return; - } - - va_list args; - va_start(args, fmt); - zend_string *message = vstrpprintf(0, fmt, args); - va_end(args); - - const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); - char *param_copy = param ? estrdup(param) : NULL; - - php_stream_wrapper_error_internal(wrapper_name, context, docref, options, severity, terminating, - code, param_copy, message); -} - /* Stream error reporting */ PHPAPI void php_stream_error(php_stream *stream, const char *docref, int severity, @@ -743,18 +723,6 @@ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, va_end(args); } -PHPAPI void php_stream_wrapper_log_error_param(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, const char *param, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - char *param_copy = param ? estrdup(param) : NULL; - php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminating, code, param_copy, fmt, args); - va_end(args); -} - static zend_llist *php_stream_get_wrapper_errors_list(const char *wrapper_name) { if (!FG(wrapper_logged_errors)) { diff --git a/main/streams/streams.c b/main/streams/streams.c index 2525e4126e88..c3bde0a8b109 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -2304,16 +2304,11 @@ PHPAPI php_stream *_php_stream_open_wrapper_ex(const char *path, const char *mod default: php_stream_close(stream); stream = NULL; - if (options & REPORT_ERRORS) { - char *tmp = estrdup(path); - php_strip_url_passwd(tmp); - php_stream_wrapper_warn_param(wrapper, context, options, - SeekNotSupported, tmp, - "could not make seekable - %s", tmp); - efree(tmp); - - options &= ~REPORT_ERRORS; - } + php_stream_wrapper_warn(wrapper, context, options, + SeekNotSupported, + "could not make seekable - %s", path); + /* We do not want multiple errors so we negate it */ + options &= ~REPORT_ERRORS; } } diff --git a/tests/security/open_basedir_copy_variation1.phpt b/tests/security/open_basedir_copy_variation1.phpt index e388ad76d782..d6ea27659e85 100644 --- a/tests/security/open_basedir_copy_variation1.phpt +++ b/tests/security/open_basedir_copy_variation1.phpt @@ -28,6 +28,6 @@ bool(true) Warning: copy(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d bool(false) -Warning: unlink(copy.txt): No such file or directory in %s on line %d +Warning: unlink(): No such file or directory in %s on line %d bool(false) *** Finished testing open_basedir configuration [copy] *** From b06eb82fef8de522fb89dada626127c34039499c Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Jul 2026 18:31:27 +0100 Subject: [PATCH 3/5] streams: embed php_stream_wrapper_log_error_internal() As it now only has a single usage --- main/streams/stream_errors.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index c70b8f3f53b6..e7d964e999f3 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -696,30 +696,22 @@ static void php_stream_wrapper_log_store_error(zend_string *message, zend_enum_S zend_llist_add_element(list, &entry); } -static void php_stream_wrapper_log_error_internal(const php_stream_wrapper *wrapper, +PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, php_stream_context *context, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, char *param, const char *fmt, va_list args) + zend_enum_StreamErrorCode code, const char *fmt, ...) { + va_list args; + va_start(args, fmt); zend_string *message = vstrpprintf(0, fmt, args); const char *wrapper_name = PHP_STREAM_ERROR_WRAPPER_NAME(wrapper); if (options & REPORT_ERRORS) { php_stream_wrapper_error_internal( - wrapper_name, context, NULL, options, severity, terminating, code, param, message); + wrapper_name, context, NULL, options, severity, terminating, code, NULL, message); } else { php_stream_wrapper_log_store_error( - message, code, wrapper_name, param, severity, terminating); + message, code, wrapper_name, NULL, severity, terminating); } -} - -PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, - php_stream_context *context, int options, int severity, bool terminating, - zend_enum_StreamErrorCode code, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - php_stream_wrapper_log_error_internal( - wrapper, context, options, severity, terminating, code, NULL, fmt, args); va_end(args); } From dec19edc4badf33e55b1346711efebf789d9fe92 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 16 Jul 2026 18:32:13 +0100 Subject: [PATCH 4/5] streams: remove 'param' parameter of php_stream_wrapper_log_store_error() It's always NULL --- main/streams/stream_errors.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main/streams/stream_errors.c b/main/streams/stream_errors.c index e7d964e999f3..70c06b70182a 100644 --- a/main/streams/stream_errors.c +++ b/main/streams/stream_errors.c @@ -665,15 +665,13 @@ static void php_stream_error_list_dtor(zval *item) } static void php_stream_wrapper_log_store_error(zend_string *message, zend_enum_StreamErrorCode code, - const char *wrapper_name, const char *param, int severity, bool terminating) + const char *wrapper_name, int severity, bool terminating) { - char *param_copy = param ? estrdup(param) : NULL; - php_stream_error_entry *entry = ecalloc(1, sizeof(php_stream_error_entry)); entry->message = message; entry->code = code; entry->wrapper_name = wrapper_name ? estrdup(wrapper_name) : NULL; - entry->param = param_copy; + entry->param = NULL; entry->severity = severity; entry->terminating = terminating; @@ -710,7 +708,7 @@ PHPAPI void php_stream_wrapper_log_error(const php_stream_wrapper *wrapper, wrapper_name, context, NULL, options, severity, terminating, code, NULL, message); } else { php_stream_wrapper_log_store_error( - message, code, wrapper_name, NULL, severity, terminating); + message, code, wrapper_name, severity, terminating); } va_end(args); } From f8e0ffb180643d5cf7723b1a342402b1fd82a4e6 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Fri, 17 Jul 2026 08:59:29 -0400 Subject: [PATCH 5/5] Fix double-free of closure run_time_cache in partial application A partial over a closure whose op_array is not persistent shallow-copies the closure's op_array into the per-request PFA cache as a lifetime anchor. The copy inherited ZEND_ACC_HEAP_RT_CACHE and the run_time_cache pointer, so destroy_op_array() freed the closure's cache twice: once when the closure was released and again at PFA cache teardown. Use function_add_ref() for the copy, which resets the per-request run_time_cache and static_variables_ptr map pointers, so only the live closure owns and frees the cache. --- .../closure_rt_cache_lifetime.phpt | 19 +++++++++++++++++++ ext/opcache/ZendAccelerator.c | 3 +-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/partial_application/closure_rt_cache_lifetime.phpt diff --git a/Zend/tests/partial_application/closure_rt_cache_lifetime.phpt b/Zend/tests/partial_application/closure_rt_cache_lifetime.phpt new file mode 100644 index 000000000000..7eb4810cf00a --- /dev/null +++ b/Zend/tests/partial_application/closure_rt_cache_lifetime.phpt @@ -0,0 +1,19 @@ +--TEST-- +Partial application over a Closure::fromCallable() must not double-free the run_time_cache +--FILE-- + +--EXPECT-- +int(15) +OK diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 2c467dc1fc8a..0a7a62eae9a9 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -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);