Bound native hook stack use and scope hooks to foreground threads
Ignored and reentrant Edit messages previously entered a callback whose large text buffers increased stack use on every nested call. Menu hook forwarding also reserved payload buffers for unrelated messages. The 64-bit helper additionally installed desktop-wide hooks, allowing background UI threads to acquire subclasses and introducing synchronous traffic through Wine's mixed-architecture global hook chain. Move Edit processing and menu payload construction into non-inlined handlers. Keep the forwarding callbacks small, retain the busy-state and destruction guards, and preserve application subclass chaining and ANSI/ Unicode text handling. Share foreground hook ownership between the Winelib helper and 32-bit host. Attach both hooks only to the matching foreground UI thread, release them when that thread changes, and retry incomplete attachment as a pair. Preserve existing Edit subclasses across foreground changes and release host hooks during shutdown. Add native 32-bit and 64-bit stack-budget fixtures covering ignored and busy reentrant messages, menu forwarding, nested text queries, application subclasses before and after attachment, text input, and destruction during a text change. Add a foreground-scope integration fixture that verifies background exclusion, thread switching, detachment, and reattachment. Keep hook debug symbols and frame pointers for native crash diagnosis, and document installation and live acceptance requirements. Validation: - CMake configure and parallel build; git diff --check. - Hook-safety CTest and foreground-scope fixtures for both architectures. - Existing menu fixtures and Edit late-attachment/restart checks for both architectures, plus the 32-bit list fixture and reader-timeout test. These checks exercise specific stack and hook-scope defects; they do not establish the cause of the live MUSHclient stack overflow. Audible speech, physical braille, and live MUSHclient acceptance remain separate checks.
This commit is contained in:
1 parent
b808c6686a
commit
3474bb39c7
12 files changed
+427
-114
No files matched your search
@@ -9,6 +9,7 @@
|
||||
#include "native_items.h"
|
||||
#include "review_service.h"
|
||||
#include "foreground_focus.h"
|
||||
#include "foreground_hooks.h"
|
||||
#include "reader_endpoint.h"
|
||||
#include "msaa_events.h"
|
||||
#include "reader_events.h"
|
||||
@@ -1065,8 +1066,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char *, int) {
|
||||
}
|
||||
|
||||
HWINEVENTHOOK hook = nullptr;
|
||||
HHOOK menuHook = nullptr;
|
||||
HHOOK inputHook = nullptr;
|
||||
WineAccessForegroundHooks foregroundHooks{};
|
||||
HMODULE menuModule = nullptr;
|
||||
HWND menuBridge = nullptr;
|
||||
HANDLE menuHost32 = nullptr;
|
||||
@@ -1082,15 +1082,13 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char *, int) {
|
||||
WINE_ACCESS_MENU_CLASS, L"", 0, 0, 0, 0, 0,
|
||||
nullptr, nullptr, instance, nullptr);
|
||||
if (menuBridge != nullptr && (menuModule = load_menu_hook()) != nullptr) {
|
||||
const auto callback = std::bit_cast<HOOKPROC>(GetProcAddress(menuModule, "WineAccessMenuHook"));
|
||||
if (callback != nullptr)
|
||||
menuHook = SetWindowsHookExW(WH_CALLWNDPROC, callback, menuModule, 0);
|
||||
const auto inputCallback = std::bit_cast<HOOKPROC>(GetProcAddress(menuModule, "WineAccessInputHook"));
|
||||
if (inputCallback != nullptr)
|
||||
inputHook = SetWindowsHookExW(WH_GETMESSAGE, inputCallback, menuModule, 0);
|
||||
editReaderActive = menuHook != nullptr && inputHook != nullptr;
|
||||
foregroundHooks.module = menuModule;
|
||||
foregroundHooks.menu_callback = std::bit_cast<HOOKPROC>(GetProcAddress(menuModule, "WineAccessMenuHook"));
|
||||
foregroundHooks.input_callback = std::bit_cast<HOOKPROC>(GetProcAddress(menuModule, "WineAccessInputHook"));
|
||||
editReaderActive = foregroundHooks.menu_callback && foregroundHooks.input_callback;
|
||||
wine_access_update_hooks(&foregroundHooks, FALSE);
|
||||
}
|
||||
if (menuHook == nullptr)
|
||||
if (!editReaderActive)
|
||||
std::fprintf(stderr, "wine-access: native menu hook unavailable (error %lu)\n",
|
||||
static_cast<unsigned long>(GetLastError()));
|
||||
if (menuBridge != nullptr) {
|
||||
@@ -1098,6 +1096,9 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char *, int) {
|
||||
if (menuHost32 == nullptr)
|
||||
std::fprintf(stderr, "wine-access: 32-bit menu host unavailable (error %lu)\n",
|
||||
static_cast<unsigned long>(GetLastError()));
|
||||
// Existing subclasses keep working after foreground hooks move away,
|
||||
// including those attached by the 32-bit host.
|
||||
editReaderActive = editReaderActive || menuHost32 != nullptr;
|
||||
}
|
||||
}
|
||||
MSG message{};
|
||||
@@ -1116,6 +1117,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char *, int) {
|
||||
if (current_msaa_source(source)) present_standard_focus(source.window);
|
||||
}
|
||||
restore_virtual_desktop_focus();
|
||||
wine_access_update_hooks(&foregroundHooks, FALSE);
|
||||
poll_control_focus();
|
||||
reviewService.focus_changed(reviewIdentities.observe_foreground());
|
||||
continue;
|
||||
@@ -1129,15 +1131,12 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char *, int) {
|
||||
reviewService.stop();
|
||||
if (hook != nullptr)
|
||||
UnhookWinEvent(hook);
|
||||
if (menuHook != nullptr)
|
||||
UnhookWindowsHookEx(menuHook);
|
||||
if (inputHook != nullptr)
|
||||
UnhookWindowsHookEx(inputHook);
|
||||
wine_access_release_hooks(&foregroundHooks);
|
||||
if (menuBridge != nullptr)
|
||||
DestroyWindow(menuBridge);
|
||||
if (menuHost32 != nullptr) {
|
||||
// Destroying the bridge ends the host's loop. Parent-process death also
|
||||
// stops it, so a reader crash cannot leave an orphaned global menu hook.
|
||||
// stops it, so a reader crash cannot leave an orphaned foreground hook.
|
||||
if (WaitForSingleObject(menuHost32, 1000) == WAIT_TIMEOUT) {
|
||||
TerminateProcess(menuHost32, 0);
|
||||
WaitForSingleObject(menuHost32, 1000);
|
||||
|
||||
Reference in new issue
Block a user