]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
windows: Improve win32_change_error_mode()
authorPali Rohár <pali@kernel.org>
Mon, 27 Oct 2025 10:55:34 +0000 (11:55 +0100)
committerMartin Mareš <mj@ucw.cz>
Sun, 28 Dec 2025 20:49:06 +0000 (21:49 +0100)
Do not clear existing error bits when setting SEM_FAILCRITICALERRORS bit.
Just append SEM_FAILCRITICALERRORS to existing error bit set.

Use GetThreadErrorMode(), GetThreadErrorMode() or GetErrorMode() function
to retrive existing set error bits.

lib/physmem-windows.c
lib/win32-helpers.c
lib/win32-helpers.h

index 6263d28b7a92dab65239b5f4cf8e5c0b8269ce50..075fe57c069d948d8ffaa863eb104326ea2403b2 100644 (file)
@@ -485,9 +485,9 @@ win32_get_proc_address_by_ordinal(HMODULE module, DWORD ordinal, BOOL must_be_wi
       memcpy(module_name, func_ptr, module_name_len);
       module_name[module_name_len] = 0;
 
-      prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+      prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX, TRUE);
       module = LoadLibraryA(module_name);
-      win32_change_error_mode(prev_error_mode);
+      win32_change_error_mode(prev_error_mode, FALSE);
       if (!module)
         {
           FreeLibrary(module);
index df09d64c2569d8487ef90454a2d2870bf2a23ae5..acc1f9277fe1cd0770cd6d8223fe2818777675b6 100644 (file)
@@ -112,8 +112,15 @@ typedef BOOL (WINAPI *SetSecurityDescriptorControlProt)(PSECURITY_DESCRIPTOR pSe
 
 /*
  * This errhandlingapi function is available in kernel32.dll library on
+ * Win9x systems and then on Windows Vista and higher systems.
+ */
+typedef UINT (WINAPI *GetErrorModeProt)(VOID);
+
+/*
+ * These errhandlingapi functions are available in kernel32.dll library on
  * Windows 7 and higher systems.
  */
+typedef DWORD (WINAPI *GetThreadErrorModeProt)(VOID);
 typedef BOOL (WINAPI *SetThreadErrorModeProt)(DWORD dwNewMode, LPDWORD lpOldMode);
 
 
@@ -415,35 +422,47 @@ win32_is_not_native_process(USHORT *native_machine_ptr)
  * error mode of the whole process. Always returns previous error mode.
  */
 UINT
-win32_change_error_mode(UINT new_mode)
+win32_change_error_mode(UINT new_mode, BOOL append)
 {
+  GetThreadErrorModeProt MyGetThreadErrorMode = NULL;
   SetThreadErrorModeProt MySetThreadErrorMode = NULL;
+  GetErrorModeProt MyGetErrorMode = NULL;
   HMODULE kernel32;
   HMODULE ntdll;
   DWORD old_mode;
 
   /*
-   * Function SetThreadErrorMode() was introduced in Windows 7, so use
-   * GetProcAddress() for compatibility with older systems.
+   * Functions GetThreadErrorMode() and SetThreadErrorMode() were introduced
+   * in Windows 7, so use GetProcAddress() for compatibility with older systems.
    */
   kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
   if (kernel32)
-    MySetThreadErrorMode = (SetThreadErrorModeProt)(void(*)(void))GetProcAddress(kernel32, "SetThreadErrorMode");
+    {
+      MyGetThreadErrorMode = (GetThreadErrorModeProt)(void(*)(void))GetProcAddress(kernel32, "GetThreadErrorMode");
+      MySetThreadErrorMode = (SetThreadErrorModeProt)(void(*)(void))GetProcAddress(kernel32, "SetThreadErrorMode");
+      MyGetErrorMode = (GetErrorModeProt)(void(*)(void))GetProcAddress(kernel32, "GetErrorMode");
+    }
 
   /*
-   * Function RtlSetThreadErrorMode() was introduced in Windows XP x64
-   * and Windows Server 2003. Use GetProcAddress() as it is in ntdll.dll.
+   * Functions RtlGetThreadErrorMode() and RtlSetThreadErrorMode() were introduced
+   * in Windows XP x64 and Windows Server 2003. Use GetProcAddress() as they are in ntdll.dll.
    */
-  if (!MySetThreadErrorMode)
+  if (!MyGetThreadErrorMode || !MySetThreadErrorMode)
     {
       ntdll = GetModuleHandle(TEXT("ntdll.dll"));
       if (ntdll)
-        MySetThreadErrorMode = (SetThreadErrorModeProt)(void(*)(void))GetProcAddress(ntdll, "RtlSetThreadErrorMode");
+        {
+          MyGetThreadErrorMode = (GetThreadErrorModeProt)(void(*)(void))GetProcAddress(ntdll, "RtlGetThreadErrorMode");
+          MySetThreadErrorMode = (SetThreadErrorModeProt)(void(*)(void))GetProcAddress(ntdll, "RtlSetThreadErrorMode");
+        }
     }
 
-  if (MySetThreadErrorMode &&
-      MySetThreadErrorMode(new_mode, &old_mode))
-    return old_mode;
+  if (MyGetThreadErrorMode && MySetThreadErrorMode)
+    {
+      old_mode = MyGetThreadErrorMode();
+      MySetThreadErrorMode(new_mode | (append ? old_mode : 0), &old_mode);
+      return old_mode;
+    }
 
 #ifdef TEB_HARD_ERROR_MODE_OFFSET
   /*
@@ -454,16 +473,31 @@ win32_change_error_mode(UINT new_mode)
     {
       ULONG *hard_error_mode_ptr = (ULONG *)((BYTE *)NtCurrentTeb() + TEB_HARD_ERROR_MODE_OFFSET);
       old_mode = *hard_error_mode_ptr;
-      *hard_error_mode_ptr = new_mode;
+      *hard_error_mode_ptr = new_mode | (append ? old_mode : 0);
       return old_mode;
     }
 #endif
 
+  /*
+   * If GetErrorMode() is available and we were requested to just append
+   * new error bits then fallback to GetErrorMode()+SetErrorMode()
+   * functions which modifies error mode of the whole process just once.
+   */
+  if (MyGetErrorMode && append)
+    {
+      old_mode = MyGetErrorMode();
+      old_mode = SetErrorMode(new_mode | old_mode);
+      return old_mode;
+    }
+
   /*
    * Fallback to function SetErrorMode() which modifies error mode of the
-   * whole process and returns old mode.
+   * whole process in thread-unsafe way two times and returns old mode.
    */
-  return SetErrorMode(new_mode);
+  old_mode = SetErrorMode(new_mode);
+  if (append)
+    SetErrorMode(new_mode | old_mode);
+  return old_mode;
 }
 
 /*
@@ -1216,9 +1250,9 @@ win32_find_and_open_process_for_query(LPCSTR exe_file)
        * On older NT-based systems these functions are available in
        * psapi.dll library without K32 prefix.
        */
-      prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+      prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX, TRUE);
       psapi = LoadLibrary(TEXT("psapi.dll"));
-      win32_change_error_mode(prev_error_mode);
+      win32_change_error_mode(prev_error_mode, FALSE);
 
       if (!psapi)
         return NULL;
index 87843d7ace30453007253540654bce6788b6dfc9..ecd155b807c4c3ef7b06cca5bab5a7dd79a820e6 100644 (file)
@@ -5,7 +5,7 @@ BOOL win32_is_vista_system(void);
 BOOL win32_is_32bit_on_64bit_system(void);
 BOOL win32_is_32bit_on_win8_64bit_system(void);
 BOOL win32_is_not_native_process(USHORT *native_machine);
-UINT win32_change_error_mode(UINT new_mode);
+UINT win32_change_error_mode(UINT new_mode, BOOL append);
 BOOL win32_have_privilege(LUID luid_privilege);
 BOOL win32_enable_privilege(LUID luid_privilege, HANDLE *revert_token, BOOL *revert_only_privilege);
 VOID win32_revert_privilege(LUID luid_privilege, HANDLE revert_token, BOOL revert_only_privilege);