diff --git a/NEWS b/NEWS index 8663f30c99dab..171a437f53c06 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,10 @@ PHP NEWS . Fixed crypt() tests on musl when using --with-external-libcrypt (Michael Orlitzky). +- Streams: + . Fixed bug GH-16889 (stream_select() timeout useless for pipes on Windows). + (cmb) + - Windows: . Fixed bug GH-10992 (Improper long path support for relative paths). (cmb, nielsdos) diff --git a/UPGRADING b/UPGRADING index c319d7299a4c0..37538739d6af6 100644 --- a/UPGRADING +++ b/UPGRADING @@ -166,6 +166,9 @@ PHP 8.5 UPGRADE NOTES PHP_RELEASE_VERSION are now always numbers. Previously, they have been strings for buildconf builds. +* --enable-sanitzer is now supported for MSVC builds. This enables ASan and + debug assertions, and is supported as of MSVC 16.10 and Windows 10. + * COM: . The extension is now build shared by default; previously it defaulted to a static extension, although the official Windows binaries built a shared diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 index f3c3e2cffd76a..17b577327bbb9 100644 --- a/ext/intl/config.w32 +++ b/ext/intl/config.w32 @@ -3,7 +3,10 @@ ARG_ENABLE("intl", "Enable internationalization support", "no"); if (PHP_INTL != "no") { - if (CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && + if (CHECK_LIB("icudt.lib", "intl", PHP_INTL) && + CHECK_LIB("icuin.lib", "intl", PHP_INTL) && + CHECK_LIB("icuio.lib", "intl", PHP_INTL) && + CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && CHECK_HEADER_ADD_INCLUDE("unicode/utf.h", "CFLAGS_INTL")) { // always build as shared - zend_strtod.c/ICU type conflict EXTENSION("intl", "php_intl.c intl_convert.c intl_convertcpp.cpp intl_error.c ", true, @@ -116,16 +119,9 @@ if (PHP_INTL != "no") { codepointiterator_methods.cpp ", "intl"); - ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib"); - /* Compat for ICU before 58.1.*/ - if (CHECK_LIB("icule.lib", "intl", PHP_INTL)) { - ADD_FLAG("LIBS_INTL", "icule.lib"); - } - if (CHECK_LIB("iculx.lib", "intl", PHP_INTL)) { - ADD_FLAG("LIBS_INTL", "iculx.lib"); - } - + CHECK_LIB("icule.lib", "intl", PHP_INTL); + CHECK_LIB("iculx.lib", "intl", PHP_INTL); ADD_FLAG("CFLAGS_INTL", "/std:c++17 /EHsc /DUNISTR_FROM_CHAR_EXPLICIT=explicit /DUNISTR_FROM_STRING_EXPLICIT=explicit /DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 /DU_HIDE_OBSOLETE_UTF_OLD_H=1"); } else { WARNING("intl not enabled; libraries and/or headers not found"); diff --git a/ext/standard/tests/streams/bug49936_win32.phpt b/ext/standard/tests/streams/bug49936_win32.phpt index 6984d61b36aef..30189c3d589fe 100644 --- a/ext/standard/tests/streams/bug49936_win32.phpt +++ b/ext/standard/tests/streams/bug49936_win32.phpt @@ -12,17 +12,10 @@ default_socket_timeout=2 $dir = 'ftp://your:self@localhost/'; -var_dump(opendir($dir)); -var_dump(opendir($dir)); +var_dump(@opendir($dir)); +var_dump(@opendir($dir)); ?> --EXPECTF-- -Warning: opendir(): connect() failed: %s in %s on line %d - -Warning: opendir(ftp://...@localhost/): Failed to open directory: operation failed in %s on line %d bool(false) - -Warning: opendir(): connect() failed: %s in %s on line %d - -Warning: opendir(ftp://...@localhost/): Failed to open directory: operation failed in %s on line %d bool(false) diff --git a/ext/standard/tests/streams/bug60602.phpt b/ext/standard/tests/streams/bug60602.phpt index b97f6f877a42d..b3795414e4f19 100644 --- a/ext/standard/tests/streams/bug60602.phpt +++ b/ext/standard/tests/streams/bug60602.phpt @@ -18,8 +18,9 @@ if (is_resource($p)) { $data = ''; while (1) { + $r = [$pipes[1]]; $w = $e = NULL; - $n = stream_select($pipes, $w, $e, 300); + $n = stream_select($r, $w, $e, 300); if ($n === false) { echo "no streams \n"; @@ -29,7 +30,7 @@ if (is_resource($p)) { proc_terminate($p, 9); break; } else if ($n > 0) { - $line = fread($pipes[1], 8192); + $line = fread($r[0], 8192); if (strlen($line) == 0) { /* EOF */ break; diff --git a/ext/standard/tests/streams/bug64770.phpt b/ext/standard/tests/streams/bug64770.phpt index ba39bb5f84f68..46c1ffa3061d8 100644 --- a/ext/standard/tests/streams/bug64770.phpt +++ b/ext/standard/tests/streams/bug64770.phpt @@ -18,8 +18,9 @@ if (is_resource($p)) { $data = ''; while (1) { + $r = [$pipes[1]]; $w = $e = NULL; - $n = stream_select($pipes, $w, $e, 300); + $n = stream_select($r, $w, $e, 300); if ($n === false) { echo "no streams \n"; @@ -29,7 +30,7 @@ if (is_resource($p)) { proc_terminate($p, 9); break; } else if ($n > 0) { - $line = fread($pipes[1], 8192); + $line = fread($r[0], 8192); if (strlen($line) == 0) { /* EOF */ break; diff --git a/ext/standard/tests/streams/gh16889.phpt b/ext/standard/tests/streams/gh16889.phpt new file mode 100644 index 0000000000000..2788db52bbcdf --- /dev/null +++ b/ext/standard/tests/streams/gh16889.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-16889 (stream_select() timeout useless for pipes on Windows) +--FILE-- + +--EXPECT-- +bool(true) diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 2214b7341afa1..70e50891964b0 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -356,8 +356,20 @@ if (PHP_SECURITY_FLAGS == "yes") { } ARG_WITH("uncritical-warn-choke", "Disable some uncritical warnings", "yes"); -ARG_ENABLE("sanitizer", "Enable ASan and UBSan extensions", "no"); -if (CLANG_TOOLSET) { +ARG_ENABLE("sanitizer", "Enable ASan (and UBSan) extensions", "no"); +if (PHP_SANITIZER == "yes" && PHP_DEBUG == "yes") { + ERROR("Use of both --enable-sanitizer and --enable-debug not allowed."); +} +if (PHP_SANITIZER == "yes" && PHP_DEBUG_PACK == "no") { + ERROR("--enable-sanitizer requires --enable-debug-pack"); +} +if (VS_TOOLSET) { + if (PHP_SANITIZER == "yes") { + if (COMPILER_NUMERIC_VERSION < 1929) { + ERROR("MSVC at least 16.10 required for sanitation plugins"); + } + } +} else if (CLANG_TOOLSET) { if (PHP_UNCRITICAL_WARN_CHOKE != "no") { ADD_FLAG("CFLAGS", "-Wno-ignored-attributes -Wno-deprecated-declarations -Wno-missing-braces " + "-Wno-logical-op-parentheses -Wno-msvc-include -Wno-invalid-source-encoding -Wno-unknown-pragmas " + diff --git a/win32/build/confutils.js b/win32/build/confutils.js index e2b3f5dcb0472..c44a607af1c0b 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -1246,6 +1246,8 @@ function SAPI(sapiname, file_list, makefiletarget, cflags, obj_dir) if (PHP_SANITIZER == "yes") { if (CLANG_TOOLSET) { add_asan_opts("CFLAGS_" + SAPI, "LIBS_" + SAPI, (is_lib ? "ARFLAGS_" : "LDFLAGS_") + SAPI); + } else if (VS_TOOLSET) { + ADD_FLAG("CFLAGS", "/fsanitize=address"); } } @@ -3442,8 +3444,12 @@ function toolset_setup_build_mode() ADD_FLAG("LDFLAGS", "/incremental:no /debug /opt:ref,icf"); } ADD_FLAG("CFLAGS", "/LD /MD"); - if (PHP_SANITIZER == "yes" && CLANG_TOOLSET) { - ADD_FLAG("CFLAGS", "/Od /D NDebug /D NDEBUG /D ZEND_WIN32_NEVER_INLINE /D ZEND_DEBUG=0"); + if (PHP_SANITIZER == "yes") { + if (VS_TOOLSET) { + ADD_FLAG("CFLAGS", "/Ox /U NDebug /U NDEBUG /D ZEND_DEBUG=1"); + } else if (CLANG_TOOLSET) { + ADD_FLAG("CFLAGS", "/Od /D NDebug /D NDEBUG /D ZEND_WIN32_NEVER_INLINE /D ZEND_DEBUG=0"); + } } else { // Equivalent to Release_TSInline build -> best optimization ADD_FLAG("CFLAGS", "/Ox /D NDebug /D NDEBUG /GF /D ZEND_DEBUG=0"); diff --git a/win32/select.c b/win32/select.c index f443325cf0456..76d5ef1ee5be9 100644 --- a/win32/select.c +++ b/win32/select.c @@ -21,7 +21,7 @@ * - If you supply only sockets, this simply passes through to winsock select(). * - If you supply file handles, there is no way to distinguish between * ready for read/write or OOB, so any set in which the handle is found will - * be marked as ready. + * be marked as ready. Pipes will be checked if they are ready for read, though. * - If you supply a mixture of handles and sockets, the system will interleave * calls between select() and WaitForMultipleObjects(). The time slicing may * cause this function call to take up to 100 ms longer than you specified. @@ -135,15 +135,23 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e for (i = 0; i < n_handles; i++) { if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) { if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) { - FD_SET((uint32_t)handle_slot_to_fd[i], &aread); + DWORD avail_read = 0; + if (GetFileType(handles[i]) != FILE_TYPE_PIPE + || !PeekNamedPipe(handles[i], NULL, 0, NULL, &avail_read, NULL) + || avail_read > 0 + ) { + FD_SET((uint32_t)handle_slot_to_fd[i], &aread); + retcode++; + } } if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) { FD_SET((uint32_t)handle_slot_to_fd[i], &awrite); + retcode++; } if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) { FD_SET((uint32_t)handle_slot_to_fd[i], &aexcept); + retcode++; } - retcode++; } } }