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 ba1b3081a8c5a913f02b36f7b1dc11ca10245347 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Fri, 17 Jul 2026 09:43:26 -0400 Subject: [PATCH 5/5] Check partial-application bound arguments in the creating scope Bound-argument type checks in zp_bind() resolved strict_types from ZEND_ARG_USES_STRICT_TYPES(), which reads the caller of the frame creating the partial rather than the file where the partial is written, so the same f("3", ?) threw at one call depth and silently coerced at another, and the TypeError named the enclosing function instead of the target. Pass the creating frame's strict_types explicitly and attribute the error to the target function. --- .../bound_arg_strict_types.phpt | 26 +++++++++++++++ Zend/zend_execute.c | 32 +++++++++++++++---- Zend/zend_execute.h | 2 +- Zend/zend_partial.c | 10 ++++-- 4 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/partial_application/bound_arg_strict_types.phpt diff --git a/Zend/tests/partial_application/bound_arg_strict_types.phpt b/Zend/tests/partial_application/bound_arg_strict_types.phpt new file mode 100644 index 000000000000..d7e2ddcae5c4 --- /dev/null +++ b/Zend/tests/partial_application/bound_arg_strict_types.phpt @@ -0,0 +1,26 @@ +--TEST-- +Partial application checks bound arguments with the creating scope's strict_types +--FILE-- +getMessage(), "\n"; +} + +function make() { + try { + f("3", ?); + } catch (\TypeError $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; + } +} +make(); +?> +--EXPECT-- +TypeError: f(): Argument #1 ($a) must be of type int, string given +TypeError: f(): Argument #1 ($a) must be of type int, string given diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c51a55bac4c9..4fd67f53f0f4 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1151,9 +1151,9 @@ static bool zend_check_intersection_type_from_list( return true; } -static zend_always_inline bool zend_check_type_slow( +static zend_always_inline bool zend_check_type_slow_ex( const zend_type *type, zval *arg, const zend_reference *ref, - bool is_return_type, bool is_internal) + bool is_return_type, bool is_internal, bool strict) { if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { zend_class_entry *ce; @@ -1206,14 +1206,20 @@ static zend_always_inline bool zend_check_type_slow( return 0; } - return zend_verify_scalar_type_hint(type_mask, arg, - is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES(), - is_internal); + return zend_verify_scalar_type_hint(type_mask, arg, strict, is_internal); /* Special handling for IS_VOID is not necessary (for return types), * because this case is already checked at compile-time. */ } +static zend_always_inline bool zend_check_type_slow( + const zend_type *type, zval *arg, const zend_reference *ref, + bool is_return_type, bool is_internal) +{ + return zend_check_type_slow_ex(type, arg, ref, is_return_type, is_internal, + is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES()); +} + static zend_always_inline bool zend_check_type( const zend_type *type, zval *arg, bool is_return_type, bool is_internal) { @@ -1234,9 +1240,21 @@ static zend_always_inline bool zend_check_type( /* We can not expose zend_check_type() directly because it's inline and uses static functions */ ZEND_API bool zend_check_type_ex( - const zend_type *type, zval *arg, bool is_return_type, bool is_internal) + const zend_type *type, zval *arg, bool is_return_type, bool is_internal, bool strict) { - return zend_check_type(type, arg, is_return_type, is_internal); + const zend_reference *ref = NULL; + ZEND_ASSERT(ZEND_TYPE_IS_SET(*type)); + + if (UNEXPECTED(Z_ISREF_P(arg))) { + ref = Z_REF_P(arg); + arg = Z_REFVAL_P(arg); + } + + if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(*type, Z_TYPE_P(arg)))) { + return 1; + } + + return zend_check_type_slow_ex(type, arg, ref, is_return_type, is_internal, strict); } ZEND_API bool zend_check_user_type_slow( diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 48f7e7a72530..f824432ad956 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -110,7 +110,7 @@ ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref); ZEND_API bool zend_check_user_type_slow( const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type); ZEND_API bool zend_check_type_ex( - const zend_type *type, zval *arg, bool is_return_type, bool is_internal); + const zend_type *type, zval *arg, bool is_return_type, bool is_internal, bool strict); #if ZEND_DEBUG ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call); diff --git a/Zend/zend_partial.c b/Zend/zend_partial.c index 4095daa1f1a3..b314c03b912a 100644 --- a/Zend/zend_partial.c +++ b/Zend/zend_partial.c @@ -1098,8 +1098,14 @@ static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval * arg_info = NULL; } if (arg_info && ZEND_TYPE_IS_SET(arg_info->type) - && UNEXPECTED(!zend_check_type_ex(&arg_info->type, var, 0, 0))) { - zend_verify_arg_error(function, arg_info, offset+1, var); + && UNEXPECTED(!zend_check_type_ex(&arg_info->type, var, 0, 0, + ZEND_FLF_ARG_USES_STRICT_TYPES()))) { + zend_string *need_msg = zend_type_to_string_resolved(arg_info->type, + function->common.scope); + zend_argument_type_error_ex(function, offset + 1, + "must be of type %s, %s given", + ZSTR_VAL(need_msg), zend_zval_value_name(var)); + zend_string_release(need_msg); zval_ptr_dtor(result); ZVAL_NULL(result); return;