From a8e7901b8dfcfd2fe7c89e06a8790e9b5a7e2244 Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 29 Sep 2026 13:24:08 +0200 Subject: [PATCH 01/12] windows: support PGO with clang --- win32/build/config.w32 | 24 ++++++++++++---- win32/build/confutils.js | 62 ++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/win32/build/config.w32 b/win32/build/config.w32 index f352d4c794aa..e6a4eef19c33 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -41,9 +41,15 @@ if (PHP_DEBUG == "yes") { ARG_ENABLE('pgi', 'Generate PGO instrumented binaries', 'no'); ARG_WITH('pgo', 'Compile optimized binaries using training data from folder', 'no'); if (PHP_PGI == "yes" || PHP_PGO != "no") { - PGOMGR = PATH_PROG('pgomgr', WshShell.Environment("Process").Item("PATH")); - if (!PGOMGR) { - ERROR("--enable-pgi and --with-pgo options can only be used if PGO capable compiler is present."); + if (VS_TOOLSET || ICC_TOOLSET) { + PGOMGR = PATH_PROG('pgomgr', WshShell.Environment("Process").Item("PATH")); + if (!PGOMGR) { + ERROR("--enable-pgi and --with-pgo options can only be used if PGO capable compiler is present."); + } + } else if (CLANG_TOOLSET) { + if (!PATH_PROG('llvm-profdata', WshShell.Environment("Process").Item("PATH"))) { + ERROR("--enable-pgi and --with-pgo options can only be used if a PGO capable toolchain is present."); + } } if (PHP_PGI == "yes" && PHP_PGO != "no") { ERROR("Use of both --enable-pgi and --with-pgo not allowed."); @@ -106,11 +112,19 @@ setup_zts_stuff(); // CFLAGS, LDFLAGS and BUILD_DIR are defined // Add compiler and link flags if PGO options are selected if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { - ADD_FLAG("STATIC_EXT_CFLAGS", "/GL /O2"); + if (VS_TOOLSET || ICC_TOOLSET) { + ADD_FLAG("STATIC_EXT_CFLAGS", "/GL /O2"); + } else if (CLANG_TOOLSET) { + ADD_FLAG("CFLAGS", "-fprofile-generate"); + } DEFINE("PGOPGD_DIR", "$(BUILD_DIR)"); } else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { - ADD_FLAG("STATIC_EXT_CFLAGS", "/GL /O2"); + if (VS_TOOLSET || ICC_TOOLSET) { + ADD_FLAG("STATIC_EXT_CFLAGS", "/GL /O2"); + } else if (CLANG_TOOLSET) { + ADD_FLAG("CFLAGS", "-fprofile-use=" + ((PHP_PGO.length == 0 || PHP_PGO == "yes") ? "$(BUILD_DIR)" : PHP_PGO) + "/php.profdata"); + } DEFINE("PGOPGD_DIR", ((PHP_PGO.length == 0 || PHP_PGO == "yes") ? "$(BUILD_DIR)" : PHP_PGO)); } diff --git a/win32/build/confutils.js b/win32/build/confutils.js index 1e6604875ff1..ae7556c99cce 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -1309,18 +1309,20 @@ function SAPI(sapiname, file_list, makefiletarget, cflags, obj_dir, duplicate_so if(is_pgo_desired(sapiname) && (PHP_PGI == "yes" || PHP_PGO != "no")) { // Add compiler and link flags if PGO options are selected - if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { - ADD_FLAG('CFLAGS_' + SAPI, "/GL /O2"); - ADD_FLAG('LDFLAGS_' + SAPI, "/LTCG /GENPROFILE"); - ADD_FLAG('LDFLAGS_' + SAPI, "/d2:-FuncCache1"); - } - else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { - ADD_FLAG('CFLAGS_' + SAPI, "/GL /O2"); - ADD_FLAG('LDFLAGS_' + SAPI, "/LTCG /USEPROFILE"); - ADD_FLAG('LDFLAGS_' + SAPI, "/d2:-FuncCache1"); - } + if (VS_TOOLSET || ICC_TOOLSET) { + if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { + ADD_FLAG('CFLAGS_' + SAPI, "/GL /O2"); + ADD_FLAG('LDFLAGS_' + SAPI, "/LTCG /GENPROFILE"); + ADD_FLAG('LDFLAGS_' + SAPI, "/d2:-FuncCache1"); + } + else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { + ADD_FLAG('CFLAGS_' + SAPI, "/GL /O2"); + ADD_FLAG('LDFLAGS_' + SAPI, "/LTCG /USEPROFILE"); + ADD_FLAG('LDFLAGS_' + SAPI, "/d2:-FuncCache1"); + } - ldflags += " /PGD:$(PGOPGD_DIR)\\" + makefiletarget.substring(0, makefiletarget.indexOf(".")) + ".pgd"; + ldflags += " /PGD:$(PGOPGD_DIR)\\" + makefiletarget.substring(0, makefiletarget.indexOf(".")) + ".pgd"; + } } if (MODE_PHPIZE) { @@ -1525,18 +1527,20 @@ function EXTENSION(extname, file_list, shared, cflags, dllname, obj_dir, cxx_mod ldflags = ""; if (is_pgo_desired(extname) && (PHP_PGI == "yes" || PHP_PGO != "no")) { // Add compiler and link flags if PGO options are selected - if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { - ADD_FLAG('LDFLAGS_' + EXT, "/LTCG /GENPROFILE"); - ADD_FLAG('LDFLAGS_' + EXT, "/d2:-FuncCache1"); - } - else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { - ADD_FLAG('LDFLAGS_' + EXT, "/LTCG /USEPROFILE"); - ADD_FLAG('LDFLAGS_' + EXT, "/d2:-FuncCache1"); - } + if (VS_TOOLSET || ICC_TOOLSET) { + if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { + ADD_FLAG('LDFLAGS_' + EXT, "/LTCG /GENPROFILE"); + ADD_FLAG('LDFLAGS_' + EXT, "/d2:-FuncCache1"); + } + else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { + ADD_FLAG('LDFLAGS_' + EXT, "/LTCG /USEPROFILE"); + ADD_FLAG('LDFLAGS_' + EXT, "/d2:-FuncCache1"); + } - ADD_FLAG('CFLAGS_' + EXT, "/GL /O2"); + ADD_FLAG('CFLAGS_' + EXT, "/GL /O2"); - ldflags = " /PGD:$(PGOPGD_DIR)\\" + dllname.substring(0, dllname.indexOf(".")) + ".pgd"; + ldflags = " /PGD:$(PGOPGD_DIR)\\" + dllname.substring(0, dllname.indexOf(".")) + ".pgd"; + } } MFO.WriteLine("$(BUILD_DIR)\\" + libname + ": $(BUILD_DIR)\\" + dllname); @@ -1569,14 +1573,16 @@ function EXTENSION(extname, file_list, shared, cflags, dllname, obj_dir, cxx_mod ADD_FLAG("STATIC_EXT_CFLAGS", "$(CFLAGS_" + EXT + ")"); if (is_pgo_desired(extname) && (PHP_PGI == "yes" || PHP_PGO != "no")) { if (!static_pgo_enabled) { - if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { - ADD_FLAG('STATIC_EXT_LDFLAGS', "/LTCG:PGINSTRUMENT"); - } - else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { - ADD_FLAG('STATIC_EXT_LDFLAGS', "/LTCG:PGUPDATE"); - } + if (VS_TOOLSET || ICC_TOOLSET) { + if (PHP_DEBUG != "yes" && PHP_PGI == "yes") { + ADD_FLAG('STATIC_EXT_LDFLAGS', "/LTCG:PGINSTRUMENT"); + } + else if (PHP_DEBUG != "yes" && PHP_PGO != "no") { + ADD_FLAG('STATIC_EXT_LDFLAGS', "/LTCG:PGUPDATE"); + } - ADD_FLAG("STATIC_EXT_CFLAGS", "/GL /O2"); + ADD_FLAG("STATIC_EXT_CFLAGS", "/GL /O2"); + } static_pgo_enabled = true; } } From cc965ee21f66ca1ee588a43b4d48926e70798456 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 30 Sep 2026 14:21:28 +0200 Subject: [PATCH 02/12] fix LLVM_PROFDATA macro name --- win32/build/config.w32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/build/config.w32 b/win32/build/config.w32 index e6a4eef19c33..e4d83cb70349 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -47,7 +47,7 @@ if (PHP_PGI == "yes" || PHP_PGO != "no") { ERROR("--enable-pgi and --with-pgo options can only be used if PGO capable compiler is present."); } } else if (CLANG_TOOLSET) { - if (!PATH_PROG('llvm-profdata', WshShell.Environment("Process").Item("PATH"))) { + if (!PATH_PROG('llvm-profdata', WshShell.Environment("Process").Item("PATH"), 'LLVM_PROFDATA')) { ERROR("--enable-pgi and --with-pgo options can only be used if a PGO capable toolchain is present."); } } From 0e18d29c5910e544c44dc560ea47eced7e2d9ab9 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 30 Sep 2026 14:40:32 +0200 Subject: [PATCH 03/12] fix x86 time --- win32/build/confutils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/build/confutils.js b/win32/build/confutils.js index ae7556c99cce..a05162e2af74 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -3395,7 +3395,7 @@ function toolset_setup_common_cflags() } else if (CLANG_TOOLSET) { ADD_FLAG("CFLAGS", "-Wno-deprecated-declarations -Wno-microsoft-enum-forward-reference"); if (TARGET_ARCH == 'x86') { - ADD_FLAG('CFLAGS', '-m32'); + ADD_FLAG('CFLAGS', '-m32 /D_USE_32BIT_TIME_T=1'); } else { ADD_FLAG('CFLAGS', '-m64'); } From 939d6c5beba1564072c0be55e47053a28da8b0db Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 30 Sep 2026 15:35:04 +0200 Subject: [PATCH 04/12] set target arch when compiling jit --- ext/opcache/config.w32 | 1 + ext/opcache/jit/Makefile.frag.w32 | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32 index cd22b363db0b..832d2c27c874 100644 --- a/ext/opcache/config.w32 +++ b/ext/opcache/config.w32 @@ -29,6 +29,7 @@ if (PHP_OPCACHE_JIT == "yes") { ir_dump.c ir_check.c ir_patch.c"; DEFINE("IR_TARGET", ir_target); + DEFINE("JIT_BUILD_CFLAGS", CLANG_TOOLSET ? (X64 ? "-m64" : "-m32") : ""); DEFINE("DASM_FLAGS", dasm_flags); DEFINE("DASM_ARCH", "x86"); DEFINE("TLS_TARGET", "win"); diff --git a/ext/opcache/jit/Makefile.frag.w32 b/ext/opcache/jit/Makefile.frag.w32 index 7caf81458870..2192aea9afd0 100644 --- a/ext/opcache/jit/Makefile.frag.w32 +++ b/ext/opcache/jit/Makefile.frag.w32 @@ -1,6 +1,6 @@ $(BUILD_DIR)\\minilua.exe: ext\opcache\jit\ir\dynasm\minilua.c @if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe - $(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c + $(PHP_CL) $(JIT_BUILD_CFLAGS) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c ext\opcache\jit\ir\ir_emit_x86.h: ext\opcache\jit\ir\ir_x86.dasc $(BUILD_DIR)\\minilua.exe @if exist ext\opcache\jit\ir\ir_emit_x86.h del ext\opcache\jit\ir\ir_emit_x86.h @@ -8,7 +8,7 @@ ext\opcache\jit\ir\ir_emit_x86.h: ext\opcache\jit\ir\ir_x86.dasc $(BUILD_DIR)\\m $(BUILD_DIR)\\gen_ir_fold_hash.exe: ext\opcache\jit\ir\gen_ir_fold_hash.c ext\opcache\jit\ir\ir_strtab.c @if exist $(BUILD_DIR)\\gen_ir_fold_hash.exe del $(BUILD_DIR)\\gen_ir_fold_hash.exe - $(PHP_CL) /D $(IR_TARGET) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /Fe$(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\gen_ir_fold_hash.c + $(PHP_CL) $(JIT_BUILD_CFLAGS) /D $(IR_TARGET) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /Fe$(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\gen_ir_fold_hash.c ext\opcache\jit\ir\ir_fold_hash.h: $(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\ir_fold.h ext\opcache\jit\ir\ir.h @if exist ext\opcache\jit\ir\ir_fold_hash.h del ext\opcache\jit\ir\ir_fold_hash.h From 0be8b4b63f4c2c18287bbdfcb6c850d1168b30f0 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 30 Sep 2026 23:17:30 +0200 Subject: [PATCH 05/12] set target arch for build helpers --- ext/opcache/config.w32 | 1 - ext/opcache/jit/Makefile.frag.w32 | 4 ++-- win32/build/Makefile | 2 +- win32/build/config.w32 | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32 index 832d2c27c874..cd22b363db0b 100644 --- a/ext/opcache/config.w32 +++ b/ext/opcache/config.w32 @@ -29,7 +29,6 @@ if (PHP_OPCACHE_JIT == "yes") { ir_dump.c ir_check.c ir_patch.c"; DEFINE("IR_TARGET", ir_target); - DEFINE("JIT_BUILD_CFLAGS", CLANG_TOOLSET ? (X64 ? "-m64" : "-m32") : ""); DEFINE("DASM_FLAGS", dasm_flags); DEFINE("DASM_ARCH", "x86"); DEFINE("TLS_TARGET", "win"); diff --git a/ext/opcache/jit/Makefile.frag.w32 b/ext/opcache/jit/Makefile.frag.w32 index 2192aea9afd0..cd47c71960e9 100644 --- a/ext/opcache/jit/Makefile.frag.w32 +++ b/ext/opcache/jit/Makefile.frag.w32 @@ -1,6 +1,6 @@ $(BUILD_DIR)\\minilua.exe: ext\opcache\jit\ir\dynasm\minilua.c @if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe - $(PHP_CL) $(JIT_BUILD_CFLAGS) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c + $(PHP_CL) $(BUILD_CFLAGS) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c ext\opcache\jit\ir\ir_emit_x86.h: ext\opcache\jit\ir\ir_x86.dasc $(BUILD_DIR)\\minilua.exe @if exist ext\opcache\jit\ir\ir_emit_x86.h del ext\opcache\jit\ir\ir_emit_x86.h @@ -8,7 +8,7 @@ ext\opcache\jit\ir\ir_emit_x86.h: ext\opcache\jit\ir\ir_x86.dasc $(BUILD_DIR)\\m $(BUILD_DIR)\\gen_ir_fold_hash.exe: ext\opcache\jit\ir\gen_ir_fold_hash.c ext\opcache\jit\ir\ir_strtab.c @if exist $(BUILD_DIR)\\gen_ir_fold_hash.exe del $(BUILD_DIR)\\gen_ir_fold_hash.exe - $(PHP_CL) $(JIT_BUILD_CFLAGS) /D $(IR_TARGET) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /Fe$(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\gen_ir_fold_hash.c + $(PHP_CL) $(BUILD_CFLAGS) /D $(IR_TARGET) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /Fe$(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\gen_ir_fold_hash.c ext\opcache\jit\ir\ir_fold_hash.h: $(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\ir_fold.h ext\opcache\jit\ir\ir.h @if exist ext\opcache\jit\ir\ir_fold_hash.h del ext\opcache\jit\ir\ir_fold_hash.h diff --git a/win32/build/Makefile b/win32/build/Makefile index e9308bc43cdb..e3540bc8b705 100644 --- a/win32/build/Makefile +++ b/win32/build/Makefile @@ -226,7 +226,7 @@ dist: all build-dist snap: build-snap build-devel build-dist $(BUILD_DIR)\deplister.exe: win32\build\deplister.c - $(CC) /nologo /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\deplister.exe win32\build\deplister.c imagehlp.lib + $(CC) $(BUILD_CFLAGS) /nologo /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\deplister.exe win32\build\deplister.c imagehlp.lib install: really-install install-sdk diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 5f59e2976779..c7c6288d3455 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -69,6 +69,7 @@ DEFINE('PHP_PREFIX', PHP_PREFIX); DEFINE("BASE_INCLUDES", "/I . /I main /I Zend /I TSRM /I ext "); toolset_setup_common_cflags(); +DEFINE("BUILD_CFLAGS", CLANG_TOOLSET ? (X64 ? "-m64" : "-m32") : ""); if (VS_TOOLSET) { ARG_WITH('mp', 'Tell Visual Studio use up to [n,auto,disable] processes for compilation', 'auto'); From 1c8d7211fd57d461df6056a05421f98ac77bbd42 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 30 Sep 2026 23:17:30 +0200 Subject: [PATCH 06/12] fix firebird header include order --- ext/pdo_firebird/pdo_firebird_utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/pdo_firebird/pdo_firebird_utils.h b/ext/pdo_firebird/pdo_firebird_utils.h index 3a3ee4ab7c41..e2b2502e20fa 100644 --- a/ext/pdo_firebird/pdo_firebird_utils.h +++ b/ext/pdo_firebird/pdo_firebird_utils.h @@ -15,6 +15,7 @@ #ifndef PDO_FIREBIRD_UTILS_H #define PDO_FIREBIRD_UTILS_H +#include #include #ifdef __cplusplus From 141cc5585c2b7383c21ae9b160cbbedb48db3ba4 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Oct 2026 10:39:02 +0200 Subject: [PATCH 07/12] pass BUILD_CFLAGS to test helpers too --- ext/com_dotnet/Makefile.frag.w32 | 4 ++-- ext/standard/Makefile.frag.w32 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/com_dotnet/Makefile.frag.w32 b/ext/com_dotnet/Makefile.frag.w32 index ec16dfc2974e..404482ad4d3c 100644 --- a/ext/com_dotnet/Makefile.frag.w32 +++ b/ext/com_dotnet/Makefile.frag.w32 @@ -3,8 +3,8 @@ $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.c: ext\com_dotnet\tests\comt midl /nologo /h $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.h /iid $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.c /tlb $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.tlb ext\com_dotnet\tests\comtest\comtest.idl $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.obj $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.obj: ext\com_dotnet\tests\comtest\comtest.cpp $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.c - $(PHP_CL) /nologo /c /Fo$(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.obj /I $(BUILD_DIR)\ext\com_dotnet\tests\comtest ext\com_dotnet\tests\comtest\comtest.cpp - $(PHP_CL) /nologo /c /Fo$(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.obj $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.c + $(PHP_CL) $(BUILD_CFLAGS) /nologo /c /Fo$(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.obj /I $(BUILD_DIR)\ext\com_dotnet\tests\comtest ext\com_dotnet\tests\comtest\comtest.cpp + $(PHP_CL) $(BUILD_CFLAGS) /nologo /c /Fo$(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.obj $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.c $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.dll: $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.obj $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.obj ext\com_dotnet\tests\comtest\comtest.def "$(LINK)" /nologo /dll /out:$(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.dll $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest.obj $(BUILD_DIR)\ext\com_dotnet\tests\comtest\comtest_i.obj /def:ext\com_dotnet\tests\comtest\comtest.def OleAut32.lib diff --git a/ext/standard/Makefile.frag.w32 b/ext/standard/Makefile.frag.w32 index d1003fb2b23c..123aee39ec95 100644 --- a/ext/standard/Makefile.frag.w32 +++ b/ext/standard/Makefile.frag.w32 @@ -10,4 +10,4 @@ $(BUILD_DIR)\ext\standard\basic_functions.obj: $(PHP_SRC_DIR)\Zend\zend_language $(PHP_SRC_DIR)\ext\standard\tests\helpers\bad_cmd.exe: $(PHP_SRC_DIR)\ext\standard\tests\helpers\bad_cmd.c cd $(PHP_SRC_DIR)\ext\standard\tests\helpers - $(PHP_CL) /nologo bad_cmd.c + $(PHP_CL) $(BUILD_CFLAGS) /nologo bad_cmd.c From f844d65a7c97de30b09772bc22abfa6a8d2a7e62 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Oct 2026 12:48:57 +0200 Subject: [PATCH 08/12] tsrm issue on windows --- TSRM/TSRM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h index 6a72dd3c02f3..84833cf163f3 100644 --- a/TSRM/TSRM.h +++ b/TSRM/TSRM.h @@ -162,7 +162,7 @@ TSRM_API bool tsrm_is_managed_thread(void); # define __has_attribute(x) 0 #endif -#if !__has_attribute(tls_model) || defined(__FreeBSD__) || defined(__NetBSD__) \ +#if defined(TSRM_WIN32) || !__has_attribute(tls_model) || defined(__FreeBSD__) || defined(__NetBSD__) \ || defined(__MUSL__) || defined(__HAIKU__) || defined(_AIX) # define TSRM_TLS_MODEL_ATTR # define TSRM_TLS_MODEL_DEFAULT From 73730b1774be01a56e915fcfb7b3506f2460231e Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Oct 2026 13:12:26 +0200 Subject: [PATCH 09/12] let ICU destroy parsed arrays --- ext/intl/msgformat/msgformat_helpers.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/intl/msgformat/msgformat_helpers.cpp b/ext/intl/msgformat/msgformat_helpers.cpp index da18527591d0..8f5c36df8fe8 100644 --- a/ext/intl/msgformat/msgformat_helpers.cpp +++ b/ext/intl/msgformat/msgformat_helpers.cpp @@ -623,6 +623,10 @@ U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval **args, UCh return; } + /* Let ICU destroy the array with the same ABI that allocated it. */ + Formattable parsed; + parsed.adoptArray(fargs, *count); + *args = (zval *)safe_emalloc(*count, sizeof(zval), 0); // assign formattables to varargs @@ -672,5 +676,4 @@ U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval **args, UCh break; } } - delete[] fargs; } From d05673c77b622af42f3776d373d64b32cb9619b7 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Oct 2026 13:19:30 +0200 Subject: [PATCH 10/12] embed manifests for clang builds --- win32/build/confutils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/build/confutils.js b/win32/build/confutils.js index a05162e2af74..fc022b21916b 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -3136,7 +3136,7 @@ function toolset_setup_project_tools() } // Try locating the manifest tool - if (VS_TOOLSET) { + if (VS_TOOLSET || CLANG_TOOLSET) { if (!PATH_PROG('mt', WshShell.Environment("Process").Item("PATH"))) { ERROR('mt is required') } From e9e28f9a261a2d9ff41b06d386188e165ab8ca2b Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Oct 2026 21:26:00 +0200 Subject: [PATCH 11/12] last fixes? --- ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt | 2 ++ ext/standard/tests/file/windows_mb_path/test_long_path_1.phpt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt b/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt index daabfaad17fe..fd18a9235350 100644 --- a/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt +++ b/ext/standard/tests/file/windows_mb_path/test_long_path_0.phpt @@ -7,6 +7,8 @@ mbstring if (PHP_OS_FAMILY !== 'Windows') die('skip windows only test'); if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); ?> +--CONFLICTS-- +file --FILE-- +--CONFLICTS-- +file --FILE-- Date: Fri, 2 Oct 2026 23:56:20 +0200 Subject: [PATCH 12/12] Fix Windows environment block conversion overflow --- .../proc_open_large_environment_win32.phpt | 32 +++++++++++++ win32/codepage.c | 45 +++++++++++-------- 2 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 ext/standard/tests/general_functions/proc_open_large_environment_win32.phpt diff --git a/ext/standard/tests/general_functions/proc_open_large_environment_win32.phpt b/ext/standard/tests/general_functions/proc_open_large_environment_win32.phpt new file mode 100644 index 000000000000..9857432487b1 --- /dev/null +++ b/ext/standard/tests/general_functions/proc_open_large_environment_win32.phpt @@ -0,0 +1,32 @@ +--TEST-- +proc_open() accepts a Windows environment block larger than 32760 characters +--SKIPIF-- + +--FILE-- + getenv('PATH'), + 'SystemRoot' => getenv('SystemRoot'), +]; +for ($index = 0; $index < 8; $index++) { + $env["PHP_TEST_ENV_$index"] = str_repeat(chr(65 + $index), 5000); +} + +$process = proc_open( + [PHP_BINARY, '-n', '-r', 'echo strlen(getenv("PHP_TEST_ENV_0")), " ", strlen(getenv("PHP_TEST_ENV_7")), "\n";'], + [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], + $pipes, + null, + $env +); +echo stream_get_contents($pipes[1]); +fclose($pipes[1]); +fclose($pipes[2]); +var_dump(proc_close($process)); +?> +--EXPECT-- +5000 5000 +int(0) diff --git a/win32/codepage.c b/win32/codepage.c index 1a723efa4496..ffabdf68c00c 100644 --- a/win32/codepage.c +++ b/win32/codepage.c @@ -425,8 +425,8 @@ PW32CP BOOL php_win32_cp_use_unicode(void) PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env) {/*{{{*/ - wchar_t *envw = NULL, ew[32760]; - char *cur = (char *)env, *prev; + wchar_t *envw = NULL; + const char *cur = env; size_t bin_len = 0; if (!env) { @@ -436,29 +436,38 @@ PW32CP wchar_t *php_win32_cp_env_any_to_w(const char* env) do { wchar_t *tmp; + wchar_t *new_envw; + size_t tmp_len; tmp = php_win32_cp_any_to_w(cur); - if (tmp) { - size_t tmp_len = wcslen(tmp) + 1; - memmove(ew + bin_len, tmp, tmp_len * sizeof(wchar_t)); - free(tmp); - - bin_len += tmp_len; + if (!tmp) { + free(envw); + return NULL; } - prev = cur; - - } while (NULL != (cur = strchr(prev, '\0')) && cur++ && *cur && bin_len + (cur - prev) < 32760); + tmp_len = wcslen(tmp) + 1; + if (tmp_len > SIZE_MAX / sizeof(wchar_t) - bin_len - 2) { + free(tmp); + free(envw); + SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); + return NULL; + } + new_envw = realloc(envw, (bin_len + tmp_len + 2) * sizeof(wchar_t)); + if (!new_envw) { + free(tmp); + free(envw); + SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); + return NULL; + } + envw = new_envw; + memcpy(envw + bin_len, tmp, tmp_len * sizeof(wchar_t)); + bin_len += tmp_len; + free(tmp); + cur += strlen(cur) + 1; + } while (*cur); - envw = (wchar_t *) malloc((bin_len + 3) * sizeof(wchar_t)); - if (!envw) { - SET_ERRNO_FROM_WIN32_CODE(ERROR_OUTOFMEMORY); - return NULL; - } - memmove(envw, ew, bin_len * sizeof(wchar_t)); envw[bin_len] = L'\0'; envw[bin_len + 1] = L'\0'; - envw[bin_len + 2] = L'\0'; return envw; }/*}}}*/