From ac709045efcbb6a773781933be446eee0f54e01a Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 03:10:26 -0700 Subject: [PATCH 01/21] Windows Vista support pt.1 and add Windows 2022 support in WinBuild --- build/docs/supported-configurations.rst | 2 ++ mfbt/WindowsVersion.h | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/build/docs/supported-configurations.rst b/build/docs/supported-configurations.rst index cfd1c98264..91a986732f 100644 --- a/build/docs/supported-configurations.rst +++ b/build/docs/supported-configurations.rst @@ -13,6 +13,8 @@ Windows We support building on Windows 7 and newer operating systems using Visual Studio 2015 U3. +The compiled browser will run on Windows Vista and newer operating systems. + The following are not fully supported (but may work): * Building with a *MozillaBuild* Windows development diff --git a/mfbt/WindowsVersion.h b/mfbt/WindowsVersion.h index d5666b1cc8..05d410734f 100644 --- a/mfbt/WindowsVersion.h +++ b/mfbt/WindowsVersion.h @@ -109,6 +109,7 @@ enum class WinBuild : uint32_t { Win10v21H1 = 19043, Win10v21H2 = 19044, Win10v22H2 = 19045, + Win2022 = 20348, Win11RTM = 22000, Win11v22H2 = 22621, Win11v23H2 = 22631, @@ -123,6 +124,13 @@ IsWindowsBuildOrLater(WinBuild aBuild) { return IsWindows10BuildOrLater(build); } +// Windows Vista +MOZ_ALWAYS_INLINE bool +IsWindowsVistaOrLater() +{ + return IsWindowsVersionOrLater(0x06000000ul); +} + // Windows 7 MOZ_ALWAYS_INLINE bool IsWin7SP1OrLater() From 7e07a8ffe58d7de2df9802d9b3fdc37f2b66ec4e Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 04:26:36 -0700 Subject: [PATCH 02/21] Make NT 6.0 the minimum OS for binaries --- js/src/old-configure.in | 4 ++-- old-configure.in | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 2b75a1fe8c..dcab570d16 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -134,7 +134,7 @@ MOZ_TOOL_VARIABLES dnl Special win32 checks dnl ======================================================== -WINVER=601 +WINVER=600 case "$target" in *-mingw*) @@ -715,7 +715,7 @@ case "$target" in IMPORT_LIB_SUFFIX=lib MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' - WIN32_SUBSYSTEM_VERSION=6.01 + WIN32_SUBSYSTEM_VERSION=6.00 WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION diff --git a/old-configure.in b/old-configure.in index 00fd86d097..b4bc48adc0 100644 --- a/old-configure.in +++ b/old-configure.in @@ -148,7 +148,7 @@ dnl ======================================================== dnl Special win32 checks dnl ======================================================== -WINVER=601 +WINVER=600 case "$target" in *-mingw*) @@ -887,7 +887,7 @@ case "$target" in IMPORT_LIB_SUFFIX=lib MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)' - WIN32_SUBSYSTEM_VERSION=6.01 + WIN32_SUBSYSTEM_VERSION=6.00 WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION From 5a3d3b752d87705bc586ade9960c240d9f09e5f1 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 04:33:33 -0700 Subject: [PATCH 03/21] Add fallback for LOCALE_ALLOW_NEUTRAL_NAMES --- dom/media/platforms/wmf/DXVA2Manager.cpp | 3 ++- dom/media/platforms/wmf/WMFAudioMFTManager.cpp | 2 ++ intl/icu/source/common/locmap.cpp | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index fbb659fac7..35a3aff1d0 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -14,6 +14,7 @@ #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/TextureForwarder.h" #include "mfapi.h" +#include #include "gfxPrefs.h" #include "MFTDecoder.h" #include "DriverCrashGuard.h" @@ -625,7 +626,7 @@ IUnknown* D3D11DXVA2Manager::GetDXVADeviceManager() { MutexAutoLock lock(mLock); - return mDXGIDeviceManager; + return mDXGIDeviceManager.get(); } HRESULT diff --git a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp index 4e0c3a8641..826f86fe75 100644 --- a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp @@ -157,8 +157,10 @@ WMFAudioMFTManager::Init() NS_ENSURE_TRUE(SUCCEEDED(hr), false); if (mStreamType == AAC) { +#ifdef MF_MT_AAC_PAYLOAD_TYPE hr = inputType->SetUINT32(MF_MT_AAC_PAYLOAD_TYPE, 0x0); // Raw AAC packet NS_ENSURE_TRUE(SUCCEEDED(hr), false); +#endif hr = inputType->SetBlob(MF_MT_USER_DATA, mUserData.Elements(), diff --git a/intl/icu/source/common/locmap.cpp b/intl/icu/source/common/locmap.cpp index da78c7716a..0af1c4f13f 100644 --- a/intl/icu/source/common/locmap.cpp +++ b/intl/icu/source/common/locmap.cpp @@ -1074,6 +1074,9 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr char16_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {}; // Note: LOCALE_ALLOW_NEUTRAL_NAMES was enabled in Windows7+, prior versions did not handle neutral (no-region) locale names. + #ifndef LOCALE_ALLOW_NEUTRAL_NAMES + #define LOCALE_ALLOW_NEUTRAL_NAMES 0 + #endif tmpLen = LCIDToLocaleName(hostid, (PWSTR)windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName), LOCALE_ALLOW_NEUTRAL_NAMES); if (tmpLen > 1) { int32_t i = 0; From 6be0ff5a108e2b47b10ff0ba61c314bc95d32a8d Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:01:58 -0700 Subject: [PATCH 04/21] Fix 'ResolveLocaleName' for Vista --- intl/icu/source/i18n/windtfmt.cpp | 11 +++++++++-- intl/icu/source/i18n/winnmfmt.cpp | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/intl/icu/source/i18n/windtfmt.cpp b/intl/icu/source/i18n/windtfmt.cpp index f1d5c25f3e..3a2eea9376 100644 --- a/intl/icu/source/i18n/windtfmt.cpp +++ b/intl/icu/source/i18n/windtfmt.cpp @@ -143,10 +143,17 @@ static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeSt // This means that it will fail for locales where ICU has a completely different // name (like ku vs ckb), and it will also not work for alternate sort locale // names like "de-DE-u-co-phonebk". - + // TODO: We could add some sort of exception table for cases like ku vs ckb. - int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName)); +#ifndef LOCALE_ALLOW_NEUTRAL_NAMES +#define LOCALE_ALLOW_NEUTRAL_NAMES 0 +#endif + int length = 0; + LCID lcid = LocaleNameToLCID(bcp47Tag, LOCALE_ALLOW_NEUTRAL_NAMES); + if (lcid != 0) { + length = LCIDToLocaleName(lcid, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName), LOCALE_ALLOW_NEUTRAL_NAMES); + } if (length > 0) { diff --git a/intl/icu/source/i18n/winnmfmt.cpp b/intl/icu/source/i18n/winnmfmt.cpp index a23e3eb8c5..0604d30cab 100644 --- a/intl/icu/source/i18n/winnmfmt.cpp +++ b/intl/icu/source/i18n/winnmfmt.cpp @@ -190,7 +190,14 @@ static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeSt // TODO: We could add some sort of exception table for cases like ku vs ckb. - int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName)); +#ifndef LOCALE_ALLOW_NEUTRAL_NAMES +#define LOCALE_ALLOW_NEUTRAL_NAMES 0 +#endif + int length = 0; + LCID lcid = LocaleNameToLCID(bcp47Tag, LOCALE_ALLOW_NEUTRAL_NAMES); + if (lcid != 0) { + length = LCIDToLocaleName(lcid, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName), LOCALE_ALLOW_NEUTRAL_NAMES); + } if (length > 0) { From 3ba0e620491beed7f95ae219df7a1d95412bb482 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:08:41 -0700 Subject: [PATCH 05/21] Fix type casting for DXGI device manager in D3D11DXVA2Manager --- dom/media/platforms/wmf/DXVA2Manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 35a3aff1d0..c5d3416ed4 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -13,8 +13,8 @@ #include "mozilla/layers/D3D11ShareHandleImage.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/TextureForwarder.h" +#include "WMF.h" #include "mfapi.h" -#include #include "gfxPrefs.h" #include "MFTDecoder.h" #include "DriverCrashGuard.h" @@ -626,7 +626,7 @@ IUnknown* D3D11DXVA2Manager::GetDXVADeviceManager() { MutexAutoLock lock(mLock); - return mDXGIDeviceManager.get(); + return static_cast(mDXGIDeviceManager.get()); } HRESULT From e3ca437de6f74cb1fe33819700604385a5663eb5 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:10:38 -0700 Subject: [PATCH 06/21] Gate WMF D3D11 code to Win7 and above --- dom/media/platforms/wmf/DXVA2Manager.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index c5d3416ed4..01111a0262 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -30,6 +30,9 @@ const CLSID CLSID_VideoProcessorMFT = }; const GUID MF_XVP_PLAYBACK_MODE = +// The size we use for our synchronization surface. +// 16x16 is the size recommended by Microsoft (in the D3D9ExDXGISharedSurf sample) that works +// best to avoid driver bugs. { 0x3c5d293f, 0xad67, @@ -513,6 +516,7 @@ DXVA2Manager::CreateD3D9DXVA(layers::KnowsCompositor* aKnowsCompositor, return nullptr; } +#if WINVER >= 0x0601 class D3D11DXVA2Manager : public DXVA2Manager { public: @@ -915,6 +919,14 @@ DXVA2Manager::CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, return nullptr; } + #else + DXVA2Manager* DXVA2Manager::CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, + nsACString& aFailureReason) + { + aFailureReason.AssignLiteral("D3D11 DXVA is not available on Windows Vista"); + return nullptr; + } + #endif nsAutoPtr manager(new D3D11DXVA2Manager()); HRESULT hr = manager->Init(aKnowsCompositor, aFailureReason); NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); From 0148ffcba64b38727c66241e16da35a6533a3e8e Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:23:45 -0700 Subject: [PATCH 07/21] Gate WMF D3D11 code pt..2 --- dom/media/platforms/wmf/DXVA2Manager.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 01111a0262..563592e36c 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -910,6 +910,7 @@ DXVA2Manager* DXVA2Manager::CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, nsACString& aFailureReason) { +#if WINVER >= 0x0601 // DXVA processing takes up a lot of GPU resources, so limit the number of // videos we use DXVA with at any one time. uint32_t dxvaLimit = gfxPrefs::PDMWMFMaxDXVAVideos(); @@ -919,19 +920,15 @@ DXVA2Manager::CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, return nullptr; } - #else - DXVA2Manager* DXVA2Manager::CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, - nsACString& aFailureReason) - { - aFailureReason.AssignLiteral("D3D11 DXVA is not available on Windows Vista"); - return nullptr; - } - #endif nsAutoPtr manager(new D3D11DXVA2Manager()); HRESULT hr = manager->Init(aKnowsCompositor, aFailureReason); NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); return manager.forget(); +#else + aFailureReason.AssignLiteral("D3D11 DXVA is not available on Windows Vista"); + return nullptr; +#endif } DXVA2Manager::DXVA2Manager() From 3551d9eb0ea83eeec5c4d8ead67e4b3ba35e82d1 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:27:49 -0700 Subject: [PATCH 08/21] Gate WMF D3D11 code pt.3 (whoops) --- dom/media/platforms/wmf/DXVA2Manager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 563592e36c..058eb68c39 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -905,6 +905,8 @@ D3D11DXVA2Manager::ConfigureForSize(uint32_t aWidth, uint32_t aHeight) return S_OK; } +#endif // WINVER >= 0x0601 + /* static */ DXVA2Manager* DXVA2Manager::CreateD3D11DXVA(layers::KnowsCompositor* aKnowsCompositor, @@ -944,4 +946,4 @@ DXVA2Manager::~DXVA2Manager() --sDXVAVideosCount; } -} // namespace mozilla +} // namespace mozilla \ No newline at end of file From 892fc7e077c9ecc7837144dda38f0db67e64d1a5 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:40:18 -0700 Subject: [PATCH 09/21] Gate gesture/touch to Win7+ --- widget/windows/nsWinGesture.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/widget/windows/nsWinGesture.h b/widget/windows/nsWinGesture.h index fdd1588b6f..8f8373fe1f 100644 --- a/widget/windows/nsWinGesture.h +++ b/widget/windows/nsWinGesture.h @@ -11,6 +11,15 @@ */ #include "nsdefs.h" +// Ensure gesture/touch types are defined (require Windows 7+) +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0601) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0601 +#endif +#if !defined(WINVER) || (WINVER < 0x0601) +# undef WINVER +# define WINVER 0x0601 +#endif #include #include #include "nsPoint.h" From a7323f6073e9790648b43d1ad2e5a2eb0f5a0fe7 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:50:29 -0700 Subject: [PATCH 10/21] Add compatability shim for gesture/touch for WinVista --- widget/windows/nsWinGesture.h | 95 +++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/widget/windows/nsWinGesture.h b/widget/windows/nsWinGesture.h index 8f8373fe1f..9800068f94 100644 --- a/widget/windows/nsWinGesture.h +++ b/widget/windows/nsWinGesture.h @@ -10,8 +10,6 @@ * nsWinGesture - Touch input handling for tablet displays. */ -#include "nsdefs.h" -// Ensure gesture/touch types are defined (require Windows 7+) #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0601) # undef _WIN32_WINNT # define _WIN32_WINNT 0x0601 @@ -20,11 +18,102 @@ # undef WINVER # define WINVER 0x0601 #endif -#include +#include "nsdefs.h" #include #include "nsPoint.h" #include "mozilla/EventForwards.h" #include "mozilla/TouchEvents.h" +#include + +// Some builds pull in windows.h before WINVER/_WIN32_WINNT are raised, +// which hides Win7+ touch/gesture declarations. Provide compatibility +// declarations so this code still compiles; functions are resolved at runtime. +#ifndef WM_GESTURE +# define WM_GESTURE 0x0119 +#endif +#ifndef WM_GESTURENOTIFY +# define WM_GESTURENOTIFY 0x011A +#endif +#ifndef WM_TOUCH +# define WM_TOUCH 0x0240 +#endif + +#ifndef TOUCHEVENTF_MOVE +typedef HANDLE HTOUCHINPUT; +typedef struct tagTOUCHINPUT { + LONG x; + LONG y; + HANDLE hSource; + DWORD dwID; + DWORD dwFlags; + DWORD dwMask; + DWORD dwTime; + ULONG_PTR dwExtraInfo; + DWORD cxContact; + DWORD cyContact; +} TOUCHINPUT, *PTOUCHINPUT; + +# define TOUCHEVENTF_MOVE 0x0001 +# define TOUCHEVENTF_DOWN 0x0002 +# define TOUCHEVENTF_UP 0x0004 +# define TOUCHINPUTMASKF_CONTACTAREA 0x0004 +# define TWF_WANTPALM 0x00000002 +# define TOUCH_COORD_TO_PIXEL(l) ((l) / 100) +#endif + +#ifndef GID_BEGIN +typedef HANDLE HGESTUREINFO; +typedef struct tagGESTUREINFO { + UINT cbSize; + DWORD dwFlags; + DWORD dwID; + HWND hwndTarget; + POINTS ptsLocation; + DWORD dwInstanceID; + DWORD dwSequenceID; + ULONGLONG ullArguments; + UINT cbExtraArgs; +} GESTUREINFO, *PGESTUREINFO; + +typedef struct tagGESTURENOTIFYSTRUCT { + UINT cbSize; + DWORD dwFlags; + HWND hwndTarget; + POINTS ptsLocation; + DWORD dwInstanceID; +} GESTURENOTIFYSTRUCT, *PGESTURENOTIFYSTRUCT; + +typedef struct tagGESTURECONFIG { + DWORD dwID; + DWORD dwWant; + DWORD dwBlock; +} GESTURECONFIG, *PGESTURECONFIG; + +# define GID_BEGIN 1 +# define GID_END 2 +# define GID_ZOOM 3 +# define GID_PAN 4 +# define GID_ROTATE 5 +# define GID_TWOFINGERTAP 6 +# define GID_PRESSANDTAP 7 + +# define GC_ZOOM 0x00000001 +# define GC_PAN 0x00000001 +# define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 +# define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 +# define GC_PAN_WITH_GUTTER 0x00000008 +# define GC_PAN_WITH_INERTIA 0x00000010 +# define GC_ROTATE 0x00000001 +# define GC_TWOFINGERTAP 0x00000001 +# define GC_PRESSANDTAP 0x00000001 + +# define GF_BEGIN 0x00000001 +# define GF_INERTIA 0x00000002 +# define GF_END 0x00000004 + +# define GID_ROTATE_ANGLE_FROM_ARGUMENT(arg) \ + ((((double)(arg)) / 65535.0) * 4.0 * M_PI - 2.0 * M_PI) +#endif // WM_TABLET_QUERYSYSTEMGESTURESTATUS return values #define TABLET_ROTATE_GESTURE_ENABLE 0x02000000 From e752ea15e0d6be6b8e168d40b544af3be01fe820 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 05:52:30 -0700 Subject: [PATCH 11/21] Load shell32.dll dynamically for AppUserModelID and handle errors gracefully --- toolkit/xre/nsEmbedFunctions.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 662796fcaf..ddc7dfd95d 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -238,8 +238,23 @@ XRE_SetProcessType(const char* aProcessTypeString) void SetTaskbarGroupId(const nsString& aId) { - if (FAILED(SetCurrentProcessExplicitAppUserModelID(aId.get()))) { - NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process."); + typedef HRESULT (WINAPI* SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR); + HMODULE shell32 = ::LoadLibraryW(L"shell32.dll"); + if (!shell32) { + NS_WARNING("Failed to load shell32.dll for AppUserModelID."); + return; + } + + auto setAppId = reinterpret_cast( + ::GetProcAddress(shell32, "SetCurrentProcessExplicitAppUserModelID")); + + if (!setAppId) { + NS_WARNING("SetCurrentProcessExplicitAppUserModelID is unavailable."); + return; + } + + if (FAILED(setAppId(aId.get()))) { + NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process."); } } #endif From 0257f62a3481baadaeb074b4808ceb2b0935f447 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 06:03:23 -0700 Subject: [PATCH 12/21] Load shell32.dll dynamically for SetCurrentProcessExplicitAppUserModelID --- widget/windows/WinTaskbar.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/widget/windows/WinTaskbar.cpp b/widget/windows/WinTaskbar.cpp index 3e54923cec..aa40ca3532 100644 --- a/widget/windows/WinTaskbar.cpp +++ b/widget/windows/WinTaskbar.cpp @@ -322,7 +322,18 @@ WinTaskbar::RegisterAppUserModelID() { if (!GetAppUserModelID(uid)) return false; - return SUCCEEDED(SetCurrentProcessExplicitAppUserModelID(uid.get())); + HMODULE shell32 = ::LoadLibraryW(L"shell32.dll"); + if (!shell32) { + return false; + } + + auto setAppId = reinterpret_cast( + ::GetProcAddress(shell32, "SetCurrentProcessExplicitAppUserModelID")); + if (!setAppId) { + return false; + } + + return SUCCEEDED(setAppId(uid.get())); } NS_IMETHODIMP From 207849d5fc53435d872ebbb979263e15bfb8e738 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 06:54:51 -0700 Subject: [PATCH 13/21] GetThreadGroupAffinity fallback for Vista dav1d --- media/libdav1d/src/src/cpu.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/media/libdav1d/src/src/cpu.c b/media/libdav1d/src/src/cpu.c index 6b57fe4a97..ef90b2052e 100644 --- a/media/libdav1d/src/src/cpu.c +++ b/media/libdav1d/src/src/cpu.c @@ -84,13 +84,29 @@ COLD void dav1d_set_cpu_flags_mask(const unsigned mask) { COLD int dav1d_num_logical_processors(Dav1dContext *const c) { #ifdef _WIN32 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + typedef BOOL (WINAPI *GetThreadGroupAffinityPtr)(HANDLE, PGROUP_AFFINITY); + static GetThreadGroupAffinityPtr get_thread_group_affinity = NULL; + + if (!get_thread_group_affinity) { + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (kernel32) { + get_thread_group_affinity = + (GetThreadGroupAffinityPtr)GetProcAddress(kernel32, "GetThreadGroupAffinity"); + } + } + GROUP_AFFINITY affinity; - if (GetThreadGroupAffinity(GetCurrentThread(), &affinity)) { + if (get_thread_group_affinity && + get_thread_group_affinity(GetCurrentThread(), &affinity)) { int num_processors = 1; while (affinity.Mask &= affinity.Mask - 1) num_processors++; return num_processors; } + + SYSTEM_INFO system_info; + GetNativeSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; #else SYSTEM_INFO system_info; GetNativeSystemInfo(&system_info); From 43f7dc89e8da228b82b728f730e74b35e182b766 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 06:59:31 -0700 Subject: [PATCH 14/21] K32GetProcessImageFileNameW fallback for Vista --- widget/windows/WinMouseScrollHandler.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/widget/windows/WinMouseScrollHandler.cpp b/widget/windows/WinMouseScrollHandler.cpp index ef6b92ea49..58f5065bc6 100644 --- a/widget/windows/WinMouseScrollHandler.cpp +++ b/widget/windows/WinMouseScrollHandler.cpp @@ -1341,7 +1341,19 @@ MouseScrollHandler::Device::Elantech::IsHelperWindow(HWND aWnd) bool result = false; wchar_t path[256] = {L'\0'}; - if (::GetProcessImageFileNameW(hProcess, path, ArrayLength(path))) { + typedef DWORD (WINAPI *GetProcessImageFileNameWPtr)(HANDLE, LPWSTR, DWORD); + static GetProcessImageFileNameWPtr getProcessImageFileNameW = nullptr; + + if (!getProcessImageFileNameW) { + HMODULE psapi = ::LoadLibraryW(L"psapi.dll"); + if (psapi) { + getProcessImageFileNameW = reinterpret_cast( + ::GetProcAddress(psapi, "GetProcessImageFileNameW")); + } + } + + if (getProcessImageFileNameW && + getProcessImageFileNameW(hProcess, path, ArrayLength(path))) { int pathLength = lstrlenW(path); if (pathLength >= filenameSuffixLength) { if (lstrcmpiW(path + pathLength - filenameSuffixLength, From 20efb4b84961ecb3a65daf4dd852cf95cee2d591 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 08:25:08 -0700 Subject: [PATCH 15/21] TryAcquireSRWLockExclusive fallback for Vista --- ipc/chromium/src/base/condition_variable.h | 2 + .../src/base/condition_variable_win.cc | 10 +- ipc/chromium/src/base/lock_impl.h | 30 +++++- ipc/chromium/src/base/lock_impl_win.cc | 81 +++++++++++++++- .../threading/windows/ConditionVariable.cpp | 8 +- js/src/threading/windows/MutexImpl.cpp | 7 +- js/src/threading/windows/MutexPlatformData.h | 2 +- memory/mimalloc/include/mimalloc/atomic.h | 95 +++++++++++++++++-- memory/mozjemalloc/jemalloc.c | 16 ++-- 9 files changed, 220 insertions(+), 31 deletions(-) diff --git a/ipc/chromium/src/base/condition_variable.h b/ipc/chromium/src/base/condition_variable.h index f274c8eabe..83bc4da8b3 100644 --- a/ipc/chromium/src/base/condition_variable.h +++ b/ipc/chromium/src/base/condition_variable.h @@ -104,7 +104,9 @@ class ConditionVariable { #if defined(OS_WIN) CONDITION_VARIABLE cv_; + bool use_critical_section_; SRWLOCK* const srwlock_; + CRITICAL_SECTION* const critical_section_; #elif defined(OS_POSIX) pthread_cond_t condition_; pthread_mutex_t* user_mutex_; diff --git a/ipc/chromium/src/base/condition_variable_win.cc b/ipc/chromium/src/base/condition_variable_win.cc index 468fe8951d..cb241aa374 100644 --- a/ipc/chromium/src/base/condition_variable_win.cc +++ b/ipc/chromium/src/base/condition_variable_win.cc @@ -9,7 +9,9 @@ #include "base/time.h" ConditionVariable::ConditionVariable(Lock* user_lock) - : srwlock_(user_lock->lock_.native_handle()) + : use_critical_section_(user_lock->lock_.uses_critical_section()), + srwlock_(user_lock->lock_.native_srwlock()), + critical_section_(user_lock->lock_.native_critical_section()) { DCHECK(user_lock); InitializeConditionVariable(&cv_); @@ -27,7 +29,11 @@ void ConditionVariable::Wait() { void ConditionVariable::TimedWait(const base::TimeDelta& max_time) { DWORD timeout = static_cast(max_time.InMilliseconds()); - if (!SleepConditionVariableSRW(&cv_, srwlock_, timeout, 0)) { + BOOL ok = use_critical_section_ + ? SleepConditionVariableCS(&cv_, critical_section_, timeout) + : SleepConditionVariableSRW(&cv_, srwlock_, timeout, 0); + + if (!ok) { // On failure, we only expect the CV to timeout. Any other error value means // that we've unexpectedly woken up. // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the diff --git a/ipc/chromium/src/base/lock_impl.h b/ipc/chromium/src/base/lock_impl.h index a9a52d4b79..33be883cea 100644 --- a/ipc/chromium/src/base/lock_impl.h +++ b/ipc/chromium/src/base/lock_impl.h @@ -10,6 +10,24 @@ #if defined(OS_WIN) #include + +// Struct to hold either SRW lock (Win7+) or CRITICAL_SECTION (Vista fallback) +// We use a struct instead of union to avoid memory corruption from overlapping fields +#define LOCK_TYPE_SRWLOCK 0 +#define LOCK_TYPE_CRITICALECTION 1 + +struct NativeHandleWin { + int type; // Discriminator: LOCK_TYPE_SRWLOCK or LOCK_TYPE_CRITICALECTION + union { + SRWLOCK srwlock; + CRITICAL_SECTION critical_section; + } handle; + + NativeHandleWin() : type(LOCK_TYPE_SRWLOCK), handle() { + // Constructor initializes type and zero-initializes the union + } +}; + #elif defined(OS_POSIX) #include #endif @@ -23,7 +41,7 @@ namespace internal { class LockImpl { public: #if defined(OS_WIN) - using NativeHandle = SRWLOCK; + using NativeHandle = NativeHandleWin; #elif defined(OS_POSIX) using NativeHandle = pthread_mutex_t; #endif @@ -47,6 +65,16 @@ class LockImpl { // unnecessary. NativeHandle* native_handle() { return &native_handle_; } +#if defined(OS_WIN) + SRWLOCK* native_srwlock() { return &native_handle_.handle.srwlock; } + CRITICAL_SECTION* native_critical_section() { + return &native_handle_.handle.critical_section; + } + bool uses_critical_section() const { + return native_handle_.type == LOCK_TYPE_CRITICALECTION; + } +#endif + #if defined(OS_POSIX) // Whether this lock will attempt to use priority inheritance. static bool PriorityInheritanceAvailable(); diff --git a/ipc/chromium/src/base/lock_impl_win.cc b/ipc/chromium/src/base/lock_impl_win.cc index c8f2191441..99914985ba 100644 --- a/ipc/chromium/src/base/lock_impl_win.cc +++ b/ipc/chromium/src/base/lock_impl_win.cc @@ -7,20 +7,91 @@ namespace base { namespace internal { -LockImpl::LockImpl() : native_handle_(SRWLOCK_INIT) {} +namespace { -LockImpl::~LockImpl() = default; +typedef BOOLEAN(WINAPI* TryAcquireSRWLockExclusiveFn)(PSRWLOCK); +typedef void(WINAPI* AcquireSRWLockExclusiveFn)(PSRWLOCK); +typedef void(WINAPI* ReleaseSRWLockExclusiveFn)(PSRWLOCK); + +TryAcquireSRWLockExclusiveFn GetTryAcquireSRWLockExclusive() { + static TryAcquireSRWLockExclusiveFn fn = []() { + HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); + return reinterpret_cast( + ::GetProcAddress(kernel32, "TryAcquireSRWLockExclusive")); + }(); + return fn; +} + +AcquireSRWLockExclusiveFn GetAcquireSRWLockExclusive() { + static AcquireSRWLockExclusiveFn fn = []() { + HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); + return reinterpret_cast( + ::GetProcAddress(kernel32, "AcquireSRWLockExclusive")); + }(); + return fn; +} + +ReleaseSRWLockExclusiveFn GetReleaseSRWLockExclusive() { + static ReleaseSRWLockExclusiveFn fn = []() { + HMODULE kernel32 = ::GetModuleHandleW(L"kernel32.dll"); + return reinterpret_cast( + ::GetProcAddress(kernel32, "ReleaseSRWLockExclusive")); + }(); + return fn; +} + +bool HasSRWLockSupport() { + return GetTryAcquireSRWLockExclusive() && GetAcquireSRWLockExclusive() && + GetReleaseSRWLockExclusive(); +} + +} // namespace + +LockImpl::LockImpl() { + if (HasSRWLockSupport()) { + native_handle_.type = LOCK_TYPE_SRWLOCK; + ::InitializeSRWLock(&native_handle_.handle.srwlock); + } else { + native_handle_.type = LOCK_TYPE_CRITICALECTION; + ::InitializeCriticalSection(&native_handle_.handle.critical_section); + } +} + +LockImpl::~LockImpl() { + if (native_handle_.type == LOCK_TYPE_CRITICALECTION) { + ::DeleteCriticalSection(&native_handle_.handle.critical_section); + } +} bool LockImpl::Try() { - return !!::TryAcquireSRWLockExclusive(&native_handle_); + if (native_handle_.type == LOCK_TYPE_CRITICALECTION) { + return ::TryEnterCriticalSection(&native_handle_.handle.critical_section) != 0; + } + + TryAcquireSRWLockExclusiveFn try_acquire = GetTryAcquireSRWLockExclusive(); + return try_acquire && !!try_acquire(&native_handle_.handle.srwlock); } void LockImpl::Lock() { - ::AcquireSRWLockExclusive(&native_handle_); + if (native_handle_.type == LOCK_TYPE_CRITICALECTION) { + ::EnterCriticalSection(&native_handle_.handle.critical_section); + } else { + AcquireSRWLockExclusiveFn acquire = GetAcquireSRWLockExclusive(); + if (acquire) { + acquire(&native_handle_.handle.srwlock); + } + } } void LockImpl::Unlock() { - ::ReleaseSRWLockExclusive(&native_handle_); + if (native_handle_.type == LOCK_TYPE_CRITICALECTION) { + ::LeaveCriticalSection(&native_handle_.handle.critical_section); + } else { + ReleaseSRWLockExclusiveFn release = GetReleaseSRWLockExclusive(); + if (release) { + release(&native_handle_.handle.srwlock); + } + } } } // namespace internal diff --git a/js/src/threading/windows/ConditionVariable.cpp b/js/src/threading/windows/ConditionVariable.cpp index 3baebad101..168fe5faed 100644 --- a/js/src/threading/windows/ConditionVariable.cpp +++ b/js/src/threading/windows/ConditionVariable.cpp @@ -53,8 +53,8 @@ js::ConditionVariable::notify_all() void js::ConditionVariable::wait(UniqueLock& lock) { - SRWLOCK* srwlock = &lock.lock.platformData()->lock; - bool r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, INFINITE, 0); + CRITICAL_SECTION* critical_section = &lock.lock.platformData()->lock; + bool r = SleepConditionVariableCS(&platformData()->cv_, critical_section, INFINITE); MOZ_RELEASE_ASSERT(r); } @@ -69,7 +69,7 @@ js::CVStatus js::ConditionVariable::wait_for(UniqueLock& lock, const mozilla::TimeDuration& rel_time) { - SRWLOCK* srwlock = &lock.lock.platformData()->lock; + CRITICAL_SECTION* critical_section = &lock.lock.platformData()->lock; // Note that DWORD is unsigned, so we have to be careful to clamp at 0. // If rel_time is Forever, then ToMilliseconds is +inf, which evaluates as @@ -81,7 +81,7 @@ js::ConditionVariable::wait_for(UniqueLock& lock, ? INFINITE : static_cast(msecd); - BOOL r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, msec, 0); + BOOL r = SleepConditionVariableCS(&platformData()->cv_, critical_section, msec); if (r) return CVStatus::NoTimeout; MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT); diff --git a/js/src/threading/windows/MutexImpl.cpp b/js/src/threading/windows/MutexImpl.cpp index e8c04d748c..9165a0cf2d 100644 --- a/js/src/threading/windows/MutexImpl.cpp +++ b/js/src/threading/windows/MutexImpl.cpp @@ -19,7 +19,7 @@ js::detail::MutexImpl::MutexImpl() if (!platformData_) oom.crash("js::Mutex::Mutex"); - InitializeSRWLock(&platformData()->lock); + InitializeCriticalSection(&platformData()->lock); } js::detail::MutexImpl::~MutexImpl() @@ -27,17 +27,18 @@ js::detail::MutexImpl::~MutexImpl() if (!platformData_) return; + DeleteCriticalSection(&platformData()->lock); js_delete(platformData()); } void js::detail::MutexImpl::lock() { - AcquireSRWLockExclusive(&platformData()->lock); + EnterCriticalSection(&platformData()->lock); } void js::detail::MutexImpl::unlock() { - ReleaseSRWLockExclusive(&platformData()->lock); + LeaveCriticalSection(&platformData()->lock); } diff --git a/js/src/threading/windows/MutexPlatformData.h b/js/src/threading/windows/MutexPlatformData.h index 102b632393..9c08d97426 100644 --- a/js/src/threading/windows/MutexPlatformData.h +++ b/js/src/threading/windows/MutexPlatformData.h @@ -12,7 +12,7 @@ struct js::detail::MutexImpl::PlatformData { - SRWLOCK lock; + CRITICAL_SECTION lock; }; #endif // platform_win_MutexPlatformData_h diff --git a/memory/mimalloc/include/mimalloc/atomic.h b/memory/mimalloc/include/mimalloc/atomic.h index 3128050886..9c51906085 100644 --- a/memory/mimalloc/include/mimalloc/atomic.h +++ b/memory/mimalloc/include/mimalloc/atomic.h @@ -366,26 +366,107 @@ typedef _Atomic(uintptr_t) mi_atomic_guard_t; #if defined(_WIN32) +// Vista fallback: since SRW locks are Win7+ only, we use a discriminated struct +// with a nested union to safely hold both lock types +#define MI_LOCK_TYPE_SRWLOCK 0 +#define MI_LOCK_TYPE_CRITICAL 1 + typedef struct mi_lock_s { - SRWLOCK mutex; // slim reader-writer lock + int type; // Discriminator + union { + SRWLOCK srwlock; + CRITICAL_SECTION critical; + } handle; } mi_lock_t; -#define MI_LOCK_INITIALIZER { SRWLOCK_INIT } +// Note: initialize with mi_lock_init(), not MI_LOCK_INITIALIZER +#define MI_LOCK_INITIALIZER { MI_LOCK_TYPE_SRWLOCK, {0} } + +// Helper to determine if SRW locks are available on this system +static inline bool mi_srwlock_available(void) { + static int available = -1; // -1=unknown, 0=no, 1=yes + if (available < 0) { + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + available = (GetProcAddress(kernel32, "TryAcquireSRWLockExclusive") != NULL) ? 1 : 0; + } + return available == 1; +} + +typedef BOOLEAN (WINAPI *mi_try_acquire_srwlock_exclusive_fn)(PSRWLOCK); +typedef void (WINAPI *mi_acquire_srwlock_exclusive_fn)(PSRWLOCK); +typedef void (WINAPI *mi_release_srwlock_exclusive_fn)(PSRWLOCK); + +static inline mi_try_acquire_srwlock_exclusive_fn mi_try_acquire_srwlock_exclusive(void) { + static mi_try_acquire_srwlock_exclusive_fn fn = []() { + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + return reinterpret_cast( + GetProcAddress(kernel32, "TryAcquireSRWLockExclusive")); + }(); + return fn; +} + +static inline mi_acquire_srwlock_exclusive_fn mi_acquire_srwlock_exclusive(void) { + static mi_acquire_srwlock_exclusive_fn fn = []() { + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + return reinterpret_cast( + GetProcAddress(kernel32, "AcquireSRWLockExclusive")); + }(); + return fn; +} + +static inline mi_release_srwlock_exclusive_fn mi_release_srwlock_exclusive(void) { + static mi_release_srwlock_exclusive_fn fn = []() { + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + return reinterpret_cast( + GetProcAddress(kernel32, "ReleaseSRWLockExclusive")); + }(); + return fn; +} static inline bool mi_lock_try_acquire(mi_lock_t* lock) { - return TryAcquireSRWLockExclusive(&lock->mutex); + if (lock->type == MI_LOCK_TYPE_CRITICAL) { + return TryEnterCriticalSection(&lock->handle.critical) != 0; + } + mi_try_acquire_srwlock_exclusive_fn fn = mi_try_acquire_srwlock_exclusive(); + return fn && fn(&lock->handle.srwlock); } + static inline void mi_lock_acquire(mi_lock_t* lock) { - AcquireSRWLockExclusive(&lock->mutex); + if (lock->type == MI_LOCK_TYPE_CRITICAL) { + EnterCriticalSection(&lock->handle.critical); + } else { + mi_acquire_srwlock_exclusive_fn fn = mi_acquire_srwlock_exclusive(); + if (fn) { + fn(&lock->handle.srwlock); + } + } } + static inline void mi_lock_release(mi_lock_t* lock) { - ReleaseSRWLockExclusive(&lock->mutex); + if (lock->type == MI_LOCK_TYPE_CRITICAL) { + LeaveCriticalSection(&lock->handle.critical); + } else { + mi_release_srwlock_exclusive_fn fn = mi_release_srwlock_exclusive(); + if (fn) { + fn(&lock->handle.srwlock); + } + } } + static inline void mi_lock_init(mi_lock_t* lock) { - InitializeSRWLock(&lock->mutex); + if (mi_srwlock_available()) { + lock->type = MI_LOCK_TYPE_SRWLOCK; + InitializeSRWLock(&lock->handle.srwlock); + } else { + lock->type = MI_LOCK_TYPE_CRITICAL; + InitializeCriticalSection(&lock->handle.critical); + } } + static inline void mi_lock_done(mi_lock_t* lock) { - (void)(lock); + if (lock->type == MI_LOCK_TYPE_CRITICAL) { + DeleteCriticalSection(&lock->handle.critical); + } } #elif defined(MI_USE_PTHREADS) diff --git a/memory/mozjemalloc/jemalloc.c b/memory/mozjemalloc/jemalloc.c index 2bbab00252..fad71182f8 100644 --- a/memory/mozjemalloc/jemalloc.c +++ b/memory/mozjemalloc/jemalloc.c @@ -473,8 +473,8 @@ void *_mmap(void *addr, size_t length, int prot, int flags, * issues in some cases. */ #if defined(MOZ_MEMORY_WINDOWS) -#define malloc_mutex_t SRWLOCK -#define malloc_spinlock_t SRWLOCK +typedef CRITICAL_SECTION malloc_mutex_t; +typedef CRITICAL_SECTION malloc_spinlock_t; #elif defined(MOZ_MEMORY_DARWIN) typedef struct { OSSpinLock lock; @@ -1397,7 +1397,7 @@ static bool malloc_mutex_init(malloc_mutex_t *mutex) { #if defined(MOZ_MEMORY_WINDOWS) - InitializeSRWLock(mutex); + InitializeCriticalSection(mutex); #elif defined(MOZ_MEMORY_DARWIN) mutex->lock = OS_SPINLOCK_INIT; #elif defined(MOZ_MEMORY_LINUX) @@ -1435,7 +1435,7 @@ malloc_mutex_lock(malloc_mutex_t *mutex) { #if defined(MOZ_MEMORY_WINDOWS) - AcquireSRWLockExclusive(mutex); + EnterCriticalSection(mutex); #elif defined(MOZ_MEMORY_DARWIN) OSSpinLockLock(&mutex->lock); #else @@ -1448,7 +1448,7 @@ malloc_mutex_unlock(malloc_mutex_t *mutex) { #if defined(MOZ_MEMORY_WINDOWS) - ReleaseSRWLockExclusive(mutex); + LeaveCriticalSection(mutex); #elif defined(MOZ_MEMORY_DARWIN) OSSpinLockUnlock(&mutex->lock); #else @@ -1463,7 +1463,7 @@ static bool malloc_spin_init(malloc_spinlock_t *lock) { #if defined(MOZ_MEMORY_WINDOWS) - InitializeSRWLock(lock); + InitializeCriticalSection(lock); #elif defined(MOZ_MEMORY_DARWIN) lock->lock = OS_SPINLOCK_INIT; #elif defined(MOZ_MEMORY_LINUX) @@ -1490,7 +1490,7 @@ malloc_spin_lock(malloc_spinlock_t *lock) { #if defined(MOZ_MEMORY_WINDOWS) - AcquireSRWLockExclusive(lock); + EnterCriticalSection(lock); #elif defined(MOZ_MEMORY_DARWIN) OSSpinLockLock(&lock->lock); #else @@ -1502,7 +1502,7 @@ static inline void malloc_spin_unlock(malloc_spinlock_t *lock) { #if defined(MOZ_MEMORY_WINDOWS) - ReleaseSRWLockExclusive(lock); + LeaveCriticalSection(lock); #elif defined(MOZ_MEMORY_DARWIN) OSSpinLockUnlock(&lock->lock); #else From 466d69f0b81eedc90d3f9522e4fecf6286912bfc Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 08:30:39 -0700 Subject: [PATCH 16/21] TryAcquireSRWLockShared fallback for Vista --- netwerk/sctp/src/netinet/sctp_process_lock.h | 30 +++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/netwerk/sctp/src/netinet/sctp_process_lock.h b/netwerk/sctp/src/netinet/sctp_process_lock.h index feaa2c6acd..7fd824daae 100755 --- a/netwerk/sctp/src/netinet/sctp_process_lock.h +++ b/netwerk/sctp/src/netinet/sctp_process_lock.h @@ -149,19 +149,21 @@ #define SCTP_INP_INFO_RLOCK_ASSERT() #define SCTP_INP_INFO_WLOCK_ASSERT() #else +/* Vista+ fallback: always use CRITICAL_SECTION for compatibility */ #define SCTP_INP_INFO_LOCK_INIT() \ - InitializeSRWLock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_INP_INFO_LOCK_DESTROY() + InitializeCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) +#define SCTP_INP_INFO_LOCK_DESTROY() \ + DeleteCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_RLOCK() \ - AcquireSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) + EnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_TRYLOCK() \ - TryAcquireSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) + TryEnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_WLOCK() \ - AcquireSRWLockExclusive(&SCTP_BASE_INFO(ipi_ep_mtx)) + EnterCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_RUNLOCK() \ - ReleaseSRWLockShared(&SCTP_BASE_INFO(ipi_ep_mtx)) + LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_WUNLOCK() \ - ReleaseSRWLockExclusive(&SCTP_BASE_INFO(ipi_ep_mtx)) + LeaveCriticalSection(&SCTP_BASE_INFO(ipi_ep_mtx)) #define SCTP_INP_INFO_LOCK_ASSERT() #define SCTP_INP_INFO_RLOCK_ASSERT() #define SCTP_INP_INFO_WLOCK_ASSERT() @@ -552,17 +554,19 @@ #define SCTP_IPI_ADDR_LOCK_ASSERT() #define SCTP_IPI_ADDR_WLOCK_ASSERT() #else +/* address list locks - Vista+ fallback to CRITICAL_SECTION */ #define SCTP_IPI_ADDR_INIT() \ - InitializeSRWLock(&SCTP_BASE_INFO(ipi_addr_mtx)) -#define SCTP_IPI_ADDR_DESTROY() + InitializeCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) +#define SCTP_IPI_ADDR_DESTROY() \ + DeleteCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_RLOCK() \ - AcquireSRWLockShared(&SCTP_BASE_INFO(ipi_addr_mtx)) + EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_RUNLOCK() \ - ReleaseSRWLockShared(&SCTP_BASE_INFO(ipi_addr_mtx)) + LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_WLOCK() \ - AcquireSRWLockExclusive(&SCTP_BASE_INFO(ipi_addr_mtx)) + EnterCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_WUNLOCK() \ - ReleaseSRWLockExclusive(&SCTP_BASE_INFO(ipi_addr_mtx)) + LeaveCriticalSection(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_LOCK_ASSERT() #define SCTP_IPI_ADDR_WLOCK_ASSERT() #endif From 98169c0d563219f1fe18959aa16509e3c50fca34 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 08:39:32 -0700 Subject: [PATCH 17/21] SHGetPropertyStoreForWindow fallback for Vista --- widget/windows/WinTaskbar.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/widget/windows/WinTaskbar.cpp b/widget/windows/WinTaskbar.cpp index aa40ca3532..b9c4ba71e4 100644 --- a/widget/windows/WinTaskbar.cpp +++ b/widget/windows/WinTaskbar.cpp @@ -74,9 +74,31 @@ SetWindowAppUserModelProp(mozIDOMWindow *aParent, if (!toplevelHWND) return NS_ERROR_INVALID_ARG; + // SHGetPropertyStoreForWindow is Windows 7+, not available on Vista + // Use runtime lookup to fail gracefully on Vista + typedef HRESULT(WINAPI* SHGetPropertyStoreForWindowFn)( + HWND hwnd, REFIID riid, void** ppv); + + static SHGetPropertyStoreForWindowFn fn = nullptr; + static bool tried_load = false; + + if (!tried_load) { + tried_load = true; + HMODULE shell32 = ::GetModuleHandleW(L"shell32.dll"); + if (shell32) { + fn = reinterpret_cast( + ::GetProcAddress(shell32, "SHGetPropertyStoreForWindow")); + } + } + + if (!fn) { + // Vista doesn't have this API, skip it gracefully + return NS_OK; + } + RefPtr pPropStore; - if (FAILED(SHGetPropertyStoreForWindow(toplevelHWND, IID_IPropertyStore, - getter_AddRefs(pPropStore)))) { + if (FAILED(fn(toplevelHWND, IID_IPropertyStore, + getter_AddRefs(pPropStore)))) { return NS_ERROR_INVALID_ARG; } From 1c7bd188d80ad71bbc7bb9fe11090b580366fdda Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 08:46:40 -0700 Subject: [PATCH 18/21] DwmSetIconicLivePreviewBitmap fallback for Vista --- widget/windows/TaskbarPreview.cpp | 86 ++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/widget/windows/TaskbarPreview.cpp b/widget/windows/TaskbarPreview.cpp index dd109e17e0..647f50c175 100644 --- a/widget/windows/TaskbarPreview.cpp +++ b/widget/windows/TaskbarPreview.cpp @@ -136,8 +136,27 @@ TaskbarPreview::Invalidate() { if (!nsUXThemeData::CheckForCompositor()) return NS_OK; + // DwmInvalidateIconicBitmaps is Win7+ + typedef HRESULT(WINAPI* DwmInvalidateIconicBitmapsFn)(HWND hwnd); + + static DwmInvalidateIconicBitmapsFn dwm_invalidate = nullptr; + static bool tried_load = false; + + if (!tried_load) { + tried_load = true; + HMODULE dwmapi = ::GetModuleHandleW(L"dwmapi.dll"); + if (dwmapi) { + dwm_invalidate = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmInvalidateIconicBitmaps")); + } + } + + if (!dwm_invalidate) { + return NS_OK; // Vista: just skip + } + HWND previewWindow = PreviewWindow(); - return FAILED(DwmInvalidateIconicBitmaps(previewWindow)) + return FAILED(dwm_invalidate(previewWindow)) ? NS_ERROR_FAILURE : NS_OK; } @@ -281,14 +300,34 @@ TaskbarPreview::GetWindowHook() { void TaskbarPreview::EnableCustomDrawing(HWND aHWND, bool aEnable) { + // DwmSetWindowAttribute is Win7+, may fail silently on Vista + typedef HRESULT(WINAPI* DwmSetWindowAttributeFn)( + HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + + static DwmSetWindowAttributeFn dwm_set_attr = nullptr; + static bool tried_load = false; + + if (!tried_load) { + tried_load = true; + HMODULE dwmapi = ::GetModuleHandleW(L"dwmapi.dll"); + if (dwmapi) { + dwm_set_attr = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmSetWindowAttribute")); + } + } + + if (!dwm_set_attr) { + return; // Vista: DWM not available + } + BOOL enabled = aEnable; - DwmSetWindowAttribute( + dwm_set_attr( aHWND, DWMWA_FORCE_ICONIC_REPRESENTATION, &enabled, sizeof(enabled)); - DwmSetWindowAttribute( + dwm_set_attr( aHWND, DWMWA_HAS_ICONIC_BITMAP, &enabled, @@ -387,13 +426,44 @@ TaskbarPreviewCallback::Done(nsISupports *aCanvas, bool aDrawBorder) { DWORD flags = aDrawBorder ? DWM_SIT_DISPLAYFRAME : 0; HRESULT hr; + + // DwmSetIconicLivePreviewBitmap and DwmSetIconicThumbnail are Win7+ + // Use runtime lookup to fail gracefully on Vista + typedef HRESULT(WINAPI* DwmSetIconicLivePreviewBitmapFn)( + HWND hwnd, HBITMAP hbmp, POINT* pptClient, DWORD dwSITFlags); + typedef HRESULT(WINAPI* DwmSetIconicThumbnailFn)( + HWND hwnd, HBITMAP hbmp, DWORD dwSITFlags); + + static DwmSetIconicLivePreviewBitmapFn dwm_set_preview = nullptr; + static DwmSetIconicThumbnailFn dwm_set_thumbnail = nullptr; + static bool tried_load = false; + + if (!tried_load) { + tried_load = true; + HMODULE dwmapi = ::GetModuleHandleW(L"dwmapi.dll"); + if (dwmapi) { + dwm_set_preview = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmSetIconicLivePreviewBitmap")); + dwm_set_thumbnail = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmSetIconicThumbnail")); + } + } + if (!mIsThumbnail) { - POINT pptClient = { 0, 0 }; - hr = DwmSetIconicLivePreviewBitmap(mPreview->PreviewWindow(), - hBitmap, &pptClient, flags); + if (dwm_set_preview) { + POINT pptClient = { 0, 0 }; + hr = dwm_set_preview(mPreview->PreviewWindow(), + hBitmap, &pptClient, flags); + } else { + hr = S_OK; // Vista: just skip, not an error + } } else { - hr = DwmSetIconicThumbnail(mPreview->PreviewWindow(), - hBitmap, flags); + if (dwm_set_thumbnail) { + hr = dwm_set_thumbnail(mPreview->PreviewWindow(), + hBitmap, flags); + } else { + hr = S_OK; // Vista: just skip, not an error + } } MOZ_ASSERT(SUCCEEDED(hr)); mozilla::Unused << hr; From d97fdec924d5359fad13635c63025d8aaebee793 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 08:52:34 -0700 Subject: [PATCH 19/21] Various API fixes that should fix MSVCP140..dll crash on Vista --- .../cairo/src/cairo-mutex-impl-private.h | 22 ++++----- widget/windows/nsWindow.cpp | 49 +++++++++++++++++-- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/gfx/cairo/cairo/src/cairo-mutex-impl-private.h b/gfx/cairo/cairo/src/cairo-mutex-impl-private.h index 72086036c7..117508e3d8 100644 --- a/gfx/cairo/cairo/src/cairo-mutex-impl-private.h +++ b/gfx/cairo/cairo/src/cairo-mutex-impl-private.h @@ -144,24 +144,24 @@ #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif -/* We require Windows 7 features */ -#if !defined(WINVER) || (WINVER < 0x0601) -# define WINVER 0x0601 +/* Vista+ compatible implementation */ +#if !defined(WINVER) || (WINVER < 0x0600) +# define WINVER 0x0600 #endif -#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0601) -# define _WIN32_WINNT 0x0601 +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) +# define _WIN32_WINNT 0x0600 #endif # include - typedef SRWLOCK cairo_mutex_impl_t; + typedef CRITICAL_SECTION cairo_mutex_impl_t; # define CAIRO_MUTEX_IMPL_WIN32 1 -# define CAIRO_MUTEX_IMPL_LOCK(mutex) AcquireSRWLockExclusive (&(mutex)) -# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) ReleaseSRWLockExclusive (&(mutex)) -# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeSRWLock (&(mutex)) -# define CAIRO_MUTEX_IMPL_FINI(mutex) CAIRO_MUTEX_IMPL_NOOP -# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER SRWLOCK_INIT +# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER {0} #elif defined __OS2__ /******************************************************/ diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index a977f388ac..562167f4b8 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -842,8 +842,26 @@ nsWindow::Create(nsIWidget* aParent, } if (mIsRTL) { - DWORD dwAttribute = TRUE; - DwmSetWindowAttribute(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute); + // DwmSetWindowAttribute is Win7+, skip on Vista + typedef HRESULT(WINAPI* DwmSetWindowAttributeFn)( + HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + + static DwmSetWindowAttributeFn dwm_set_attr = nullptr; + static bool tried_load = false; + + if (!tried_load) { + tried_load = true; + HMODULE dwmapi = ::GetModuleHandleW(L"dwmapi.dll"); + if (dwmapi) { + dwm_set_attr = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmSetWindowAttribute")); + } + } + + if (dwm_set_attr) { + DWORD dwAttribute = TRUE; + dwm_set_attr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute); + } } if (!IsPlugin() && @@ -3118,8 +3136,31 @@ void nsWindow::UpdateGlass() // Extends the window frame behind the client area if (nsUXThemeData::CheckForCompositor()) { - DwmExtendFrameIntoClientArea(mWnd, &margins); - DwmSetWindowAttribute(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy); + // Both DwmExtendFrameIntoClientArea and DwmSetWindowAttribute are Win7+ + typedef HRESULT(WINAPI* DwmExtendFrameIntoClientAreaFn)(HWND hWnd, const MARGINS* pMarInset); + typedef HRESULT(WINAPI* DwmSetWindowAttributeFn)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + + static DwmExtendFrameIntoClientAreaFn dwm_extend = nullptr; + static DwmSetWindowAttributeFn dwm_set_attr = nullptr; + static bool tried_load = false; + + if (!tried_load) { + tried_load = true; + HMODULE dwmapi = ::GetModuleHandleW(L"dwmapi.dll"); + if (dwmapi) { + dwm_extend = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmExtendFrameIntoClientArea")); + dwm_set_attr = reinterpret_cast( + ::GetProcAddress(dwmapi, "DwmSetWindowAttribute")); + } + } + + if (dwm_extend) { + dwm_extend(mWnd, &margins); + } + if (dwm_set_attr) { + dwm_set_attr(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy); + } } } From 75dd84d2658088ffd31e0d5ec6036d21084c3681 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 11:34:50 -0700 Subject: [PATCH 20/21] Should fix Vista specific crashes --- intl/icu/source/common/umutex.cpp | 76 +++++++++++++++++ intl/icu/source/common/unifiedcache.cpp | 106 +++++++++++++++++++++++- 2 files changed, 179 insertions(+), 3 deletions(-) diff --git a/intl/icu/source/common/umutex.cpp b/intl/icu/source/common/umutex.cpp index 0c053968dc..22d530b829 100644 --- a/intl/icu/source/common/umutex.cpp +++ b/intl/icu/source/common/umutex.cpp @@ -27,6 +27,10 @@ #include "ucln_cmn.h" #include "cmemory.h" +#if defined(_WIN32) +#include +#endif + U_NAMESPACE_BEGIN @@ -44,8 +48,50 @@ U_NAMESPACE_BEGIN *************************************************************************************************/ namespace { +#if defined(_WIN32) +struct InitMutex { + CRITICAL_SECTION cs; + + InitMutex() { + InitializeCriticalSection(&cs); + } + + ~InitMutex() { + DeleteCriticalSection(&cs); + } +}; + +struct InitCondition { + CONDITION_VARIABLE cv; + + InitCondition() { + InitializeConditionVariable(&cv); + } +}; + +class AutoCriticalSection { +public: + explicit AutoCriticalSection(CRITICAL_SECTION &criticalSection) + : criticalSection_(&criticalSection) { + EnterCriticalSection(criticalSection_); + } + + ~AutoCriticalSection() { + LeaveCriticalSection(criticalSection_); + } + + CRITICAL_SECTION *get() const { return criticalSection_; } + +private: + CRITICAL_SECTION *criticalSection_; +}; + +InitMutex *initMutex = nullptr; +InitCondition *initCondition = nullptr; +#else std::mutex *initMutex; std::condition_variable *initCondition; +#endif // The ICU global mutex. // Used when ICU implementation code passes nullptr for the mutex pointer. @@ -58,8 +104,13 @@ std::once_flag *pInitFlag = &initFlag; U_CDECL_BEGIN static UBool U_CALLCONV umtx_cleanup() { +#if defined(_WIN32) + delete initMutex; + delete initCondition; +#else initMutex->~mutex(); initCondition->~condition_variable(); +#endif UMutex::cleanup(); // Reset the once_flag, by destructing it and creating a fresh one in its place. @@ -70,8 +121,13 @@ static UBool U_CALLCONV umtx_cleanup() { } static void U_CALLCONV umtx_init() { +#if defined(_WIN32) + initMutex = new InitMutex(); + initCondition = new InitCondition(); +#else initMutex = STATIC_NEW(std::mutex); initCondition = STATIC_NEW(std::condition_variable); +#endif ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup); } U_CDECL_END @@ -81,7 +137,11 @@ std::mutex *UMutex::getMutex() { std::mutex *retPtr = fMutex.load(std::memory_order_acquire); if (retPtr == nullptr) { std::call_once(*pInitFlag, umtx_init); +#if defined(_WIN32) + AutoCriticalSection guard(initMutex->cs); +#else std::lock_guard guard(*initMutex); +#endif retPtr = fMutex.load(std::memory_order_acquire); if (retPtr == nullptr) { fMutex = new(fStorage) std::mutex(); @@ -144,7 +204,11 @@ umtx_unlock(UMutex* mutex) U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) { std::call_once(*pInitFlag, umtx_init); +#if defined(_WIN32) + AutoCriticalSection lock(initMutex->cs); +#else std::unique_lock lock(*initMutex); +#endif if (umtx_loadAcquire(uio.fState) == 0) { umtx_storeRelease(uio.fState, 1); return true; // Caller will next call the init function. @@ -152,7 +216,11 @@ umtx_initImplPreInit(UInitOnce &uio) { while (umtx_loadAcquire(uio.fState) == 1) { // Another thread is currently running the initialization. // Wait until it completes. +#if defined(_WIN32) + U_ASSERT(SleepConditionVariableCS(&initCondition->cv, lock.get(), INFINITE)); +#else initCondition->wait(lock); +#endif } U_ASSERT(uio.fState == 2); return false; @@ -169,10 +237,18 @@ umtx_initImplPreInit(UInitOnce &uio) { U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) { { +#if defined(_WIN32) + AutoCriticalSection lock(initMutex->cs); +#else std::unique_lock lock(*initMutex); +#endif umtx_storeRelease(uio.fState, 2); } +#if defined(_WIN32) + WakeAllConditionVariable(&initCondition->cv); +#else initCondition->notify_all(); +#endif } U_NAMESPACE_END diff --git a/intl/icu/source/common/unifiedcache.cpp b/intl/icu/source/common/unifiedcache.cpp index 68af4e04c1..101980a75f 100644 --- a/intl/icu/source/common/unifiedcache.cpp +++ b/intl/icu/source/common/unifiedcache.cpp @@ -13,15 +13,66 @@ #include "unifiedcache.h" #include // For std::max() -#include #include "uassert.h" #include "uhash.h" #include "ucln_cmn.h" +#if defined(_WIN32) +#include +#else +#include +#endif + static icu::UnifiedCache *gCache = nullptr; +#if defined(_WIN32) +struct CacheMutex { + CRITICAL_SECTION cs; + + CacheMutex() { + InitializeCriticalSection(&cs); + } + + ~CacheMutex() { + DeleteCriticalSection(&cs); + } +}; + +struct CacheConditionVariable { + CONDITION_VARIABLE cv; + + CacheConditionVariable() { + InitializeConditionVariable(&cv); + } + + void notify_all() { + WakeAllConditionVariable(&cv); + } +}; + +class AutoCriticalSection { +public: + explicit AutoCriticalSection(CRITICAL_SECTION &criticalSection) + : criticalSection_(&criticalSection) { + EnterCriticalSection(criticalSection_); + } + + ~AutoCriticalSection() { + LeaveCriticalSection(criticalSection_); + } + + CRITICAL_SECTION *get() const { return criticalSection_; } + +private: + CRITICAL_SECTION *criticalSection_; +}; + +static CacheMutex *gCacheMutex = nullptr; +static CacheConditionVariable *gInProgressValueAddedCond; +#else static std::mutex *gCacheMutex = nullptr; static std::condition_variable *gInProgressValueAddedCond; +#endif static icu::UInitOnce gCacheInitOnce {}; static const int32_t MAX_EVICT_ITERATIONS = 10; @@ -34,9 +85,9 @@ static UBool U_CALLCONV unifiedcache_cleanup() { gCacheInitOnce.reset(); delete gCache; gCache = nullptr; - gCacheMutex->~mutex(); + delete gCacheMutex; gCacheMutex = nullptr; - gInProgressValueAddedCond->~condition_variable(); + delete gInProgressValueAddedCond; gInProgressValueAddedCond = nullptr; return true; } @@ -72,8 +123,13 @@ static void U_CALLCONV cacheInit(UErrorCode &status) { ucln_common_registerCleanup( UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup); +#if defined(_WIN32) + gCacheMutex = new CacheMutex(); + gInProgressValueAddedCond = new CacheConditionVariable(); +#else gCacheMutex = STATIC_NEW(std::mutex); gInProgressValueAddedCond = STATIC_NEW(std::condition_variable); +#endif gCache = new UnifiedCache(status); if (gCache == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; @@ -135,28 +191,48 @@ void UnifiedCache::setEvictionPolicy( status = U_ILLEGAL_ARGUMENT_ERROR; return; } +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif fMaxUnused = count; fMaxPercentageOfInUse = percentageOfInUseItems; } int32_t UnifiedCache::unusedCount() const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif return uhash_count(fHashtable) - fNumValuesInUse; } int64_t UnifiedCache::autoEvictedCount() const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif return fAutoEvictedCount; } int32_t UnifiedCache::keyCount() const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif return uhash_count(fHashtable); } void UnifiedCache::flush() const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif // Use a loop in case cache items that are flushed held hard references to // other cache items making those additional cache items eligible for @@ -165,7 +241,11 @@ void UnifiedCache::flush() const { } void UnifiedCache::handleUnreferencedObject() const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif --fNumValuesInUse; _runEvictionSlice(); } @@ -184,7 +264,11 @@ void UnifiedCache::dump() { } void UnifiedCache::dumpContents() const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif _dumpContents(); } @@ -224,7 +308,11 @@ UnifiedCache::~UnifiedCache() { // Now all that should be left in the cache are entries that refer to // each other and entries with hard references from outside the cache. // Nothing we can do about these so proceed to wipe out the cache. +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif _flush(true); } uhash_close(fHashtable); @@ -325,7 +413,11 @@ void UnifiedCache::_putIfAbsentAndGet( const CacheKeyBase &key, const SharedObject *&value, UErrorCode &status) const { +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::lock_guard lock(*gCacheMutex); +#endif const UHashElement *element = uhash_find(fHashtable, &key); if (element != nullptr && !_inProgress(element)) { _fetch(element, value, status); @@ -350,14 +442,22 @@ UBool UnifiedCache::_poll( UErrorCode &status) const { U_ASSERT(value == nullptr); U_ASSERT(status == U_ZERO_ERROR); +#if defined(_WIN32) + AutoCriticalSection lock(gCacheMutex->cs); +#else std::unique_lock lock(*gCacheMutex); +#endif const UHashElement *element = uhash_find(fHashtable, &key); // If the hash table contains an inProgress placeholder entry for this key, // this means that another thread is currently constructing the value object. // Loop, waiting for that construction to complete. while (element != nullptr && _inProgress(element)) { +#if defined(_WIN32) + U_ASSERT(SleepConditionVariableCS(&gInProgressValueAddedCond->cv, lock.get(), INFINITE)); +#else gInProgressValueAddedCond->wait(lock); +#endif element = uhash_find(fHashtable, &key); } From fecbb6c53450b014adb6d66353bb902c4bb9c644 Mon Sep 17 00:00:00 2001 From: wuggy Date: Tue, 19 May 2026 11:51:55 -0700 Subject: [PATCH 21/21] ICU startup/cleanup crash fix on WinVista --- intl/icu/source/common/umutex.cpp | 56 ++++++++++++++++++++++++++++--- intl/icu/source/common/umutex.h | 22 ++++++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/intl/icu/source/common/umutex.cpp b/intl/icu/source/common/umutex.cpp index 22d530b829..1a1b2cab40 100644 --- a/intl/icu/source/common/umutex.cpp +++ b/intl/icu/source/common/umutex.cpp @@ -49,6 +49,18 @@ U_NAMESPACE_BEGIN namespace { #if defined(_WIN32) +struct WindowsMutex { + CRITICAL_SECTION cs; + + WindowsMutex() { + InitializeCriticalSection(&cs); + } + + ~WindowsMutex() { + DeleteCriticalSection(&cs); + } +}; + struct InitMutex { CRITICAL_SECTION cs; @@ -133,15 +145,29 @@ static void U_CALLCONV umtx_init() { U_CDECL_END -std::mutex *UMutex::getMutex() { - std::mutex *retPtr = fMutex.load(std::memory_order_acquire); +#if defined(_WIN32) +void *UMutex::getMutex() { + void *retPtr = fMutex.load(std::memory_order_acquire); if (retPtr == nullptr) { std::call_once(*pInitFlag, umtx_init); -#if defined(_WIN32) AutoCriticalSection guard(initMutex->cs); + retPtr = fMutex.load(std::memory_order_acquire); + if (retPtr == nullptr) { + retPtr = new WindowsMutex(); + fMutex = retPtr; + fListLink = gListHead; + gListHead = this; + } + } + U_ASSERT(retPtr != nullptr); + return retPtr; +} #else +std::mutex *UMutex::getMutex() { + std::mutex *retPtr = fMutex.load(std::memory_order_acquire); + if (retPtr == nullptr) { + std::call_once(*pInitFlag, umtx_init); std::lock_guard guard(*initMutex); -#endif retPtr = fMutex.load(std::memory_order_acquire); if (retPtr == nullptr) { fMutex = new(fStorage) std::mutex(); @@ -153,13 +179,33 @@ std::mutex *UMutex::getMutex() { U_ASSERT(retPtr != nullptr); return retPtr; } +#endif + +#if defined(_WIN32) +void UMutex::lock() { + WindowsMutex *m = static_cast(fMutex.load(std::memory_order_acquire)); + if (m == nullptr) { + m = static_cast(getMutex()); + } + EnterCriticalSection(&m->cs); +} + +void UMutex::unlock() { + WindowsMutex *m = static_cast(fMutex.load(std::memory_order_relaxed)); + LeaveCriticalSection(&m->cs); +} +#endif UMutex *UMutex::gListHead = nullptr; void UMutex::cleanup() { UMutex *next = nullptr; for (UMutex *m = gListHead; m != nullptr; m = next) { - (*m->fMutex).~mutex(); +#if defined(_WIN32) + delete static_cast(m->fMutex.load(std::memory_order_relaxed)); +#else + (*m->fMutex).~mutex(); +#endif m->fMutex = nullptr; next = m->fListLink; m->fListLink = nullptr; diff --git a/intl/icu/source/common/umutex.h b/intl/icu/source/common/umutex.h index 8ae6d10293..028f4d4ea8 100644 --- a/intl/icu/source/common/umutex.h +++ b/intl/icu/source/common/umutex.h @@ -212,6 +212,27 @@ class U_COMMON_API_CLASS UMutex { void* operator new(size_t) = delete; // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard +#if defined(_WIN32) + U_COMMON_API void lock(); + U_COMMON_API void unlock(); + + U_COMMON_API static void cleanup(); + +private: + std::atomic fMutex { nullptr }; + + /** All initialized UMutexes are kept in a linked list, so that they can be found, + * and the underlying Windows mutex object destructed, by u_cleanup(). + */ + UMutex *fListLink { nullptr }; + static UMutex *gListHead; + + /** Out-of-line function to lazily initialize a UMutex on first use. + * Initial fast check is inline, in lock(). The returned value may never + * be nullptr. + */ + void *getMutex(); +#else U_COMMON_API void lock() { std::mutex *m = fMutex.load(std::memory_order_acquire); if (m == nullptr) { m = getMutex(); } @@ -236,6 +257,7 @@ class U_COMMON_API_CLASS UMutex { * be nullptr. */ std::mutex *getMutex(); +#endif };