Fix #115940, #111152: Handle access violations while loading Wintab

Some Wintab drivers can randomly crash while loading. Guard against this
by catching such exceptions using SEH. Also save and restore the current
unhandled exception filter as some drivers replace it with their own for
some reason.

Pull Request: https://projects.blender.org/blender/blender/pulls/141685
This commit is contained in:
Jorn Visser
2025-07-10 19:59:34 +02:00
committed by Harley Acheson
parent 73fe848e07
commit 035bc3e7ca
2 changed files with 49 additions and 1 deletions

View File

@@ -10,7 +10,7 @@
#include "GHOST_Wintab.hh"
GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
GHOST_Wintab *GHOST_Wintab::loadWintabUnsafe(HWND hwnd)
{
/* Load Wintab library if available. */
auto handle = unique_hmodule(::LoadLibrary("Wintab32.dll"), &::FreeLibrary);
@@ -141,6 +141,48 @@ GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
size_t(queueSize));
}
static int access_violation_exception_filter(unsigned int code, LPEXCEPTION_POINTERS pointers)
{
if (code == EXCEPTION_ACCESS_VIOLATION) {
fprintf(stderr,
"Error loading Wintab library: Access Violation at 0x%p: 0x%p, 0x%p\n",
pointers->ExceptionRecord->ExceptionAddress,
(void *)pointers->ExceptionRecord->ExceptionInformation[0],
(void *)pointers->ExceptionRecord->ExceptionInformation[1]);
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
{
/* The only way to get the current handler is by seting a new one. */
LPTOP_LEVEL_EXCEPTION_FILTER current_filter = SetUnhandledExceptionFilter(nullptr);
SetUnhandledExceptionFilter(current_filter);
/* __except and __finally cannot be used together, as such a second nested __try block is needed.
*/
__try
{
__try
{
return GHOST_Wintab::loadWintabUnsafe(hwnd);
}
__except (access_violation_exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
}
}
__finally
{
/* Restore our handler in case the Wintab driver replaced it. Huion's driver is known to do
* this.
*/
SetUnhandledExceptionFilter(current_filter);
}
return nullptr;
}
void GHOST_Wintab::modifyContext(LOGCONTEXT &lc)
{
lc.lcPktData = PACKETDATA;

View File

@@ -258,6 +258,12 @@ class GHOST_Wintab {
*/
GHOST_TButton mapWintabToGhostButton(UINT cursor, WORD physicalButton);
/**
* Called by loadWintab to do the actual loading. A separate function is needed because the __try
* __except block in loadWintab cannot be combined with C++ stack variable destructors.
*/
static GHOST_Wintab *loadWintabUnsafe(HWND hwnd);
/**
* Applies common modifications to Wintab context.
* \param lc: Wintab context to modify.