Skip to content

fix (WeaselUI): Crash when the Weasel Panel creation is re-entried.#1839

Open
cqjjjzr wants to merge 1 commit intorime:masterfrom
cqjjjzr:ui-create
Open

fix (WeaselUI): Crash when the Weasel Panel creation is re-entried.#1839
cqjjjzr wants to merge 1 commit intorime:masterfrom
cqjjjzr:ui-create

Conversation

@cqjjjzr
Copy link
Copy Markdown

@cqjjjzr cqjjjzr commented Apr 14, 2026

尝试修复如下问题:打开 Thunderbird 的回复窗口后,如果 Thunderbird 安装了 Reply With Header 扩展,那么由于目前疑似 Thunderbird 的问题(我目前开在了 https://bugzilla.mozilla.org/show_bug.cgi?id=2031427 ),在一些条件下 StartComposition 调用会返回 E_FAIL。然后因为一些未知原因 UI::Create 会在未销毁之前就被调用。

在 Debug 下这会造成 Assertion Fail,在 Release 下似乎会造成后续的空指针解引用(具体位置没有特别定位到,因为测的时候没带调试 PDB)带崩整个 Thunderbird。

此 commit 尝试把 UI::Create 改成幂等的,目前是复用了一下现有的 Panel,或许也应该考虑一下先销毁再创建新的,如果有必要例如更换 parent 等。但至少不应该出现输入法带崩整个应用程序的情况。

Do not create UI::pimpl_->panel when the previous one is still alive.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes weasel::UI::Create(HWND parent) idempotent to prevent crashes/assertions when panel creation is re-entered (e.g., Thunderbird composition edge cases), by reusing an existing WeaselPanel instead of attempting to recreate it.

Changes:

  • Lazily allocate UIImpl only when needed.
  • Early-return from UI::Create when the panel window already exists.
  • Return a success/failure result based on the underlying WeaselPanel::Create call.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread WeaselUI/WeaselUI.cpp
Comment on lines +92 to +93
if (pimpl_->panel.IsWindow())
return true;
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create(HWND parent) now returns early when panel.IsWindow() is true, which makes the parent argument effectively ignored on re-entry. If callers can re-enter Create() with a different parent (e.g., focus moved to a different active window), the panel will remain owned by the old window, which can break z-order/lifetime semantics for a popup. Consider checking the current owner (GetParent() for a WS_POPUP owned window) and, when it differs from parent, either update the owner (e.g., via SetWindowLongPtr(GWLP_HWNDPARENT, ...)) or destroy/recreate the panel with the new parent.

Suggested change
if (pimpl_->panel.IsWindow())
return true;
if (pimpl_->panel.IsWindow()) {
HWND current_parent = ::GetParent(pimpl_->panel.m_hWnd);
if (current_parent != parent) {
::SetLastError(0);
LONG_PTR previous_parent = ::SetWindowLongPtr(
pimpl_->panel.m_hWnd, GWLP_HWNDPARENT,
reinterpret_cast<LONG_PTR>(parent));
if (previous_parent == 0 && ::GetLastError() != 0)
return false;
}
return true;
}

Copilot uses AI. Check for mistakes.
Comment thread WeaselUI/WeaselUI.cpp
Comment on lines +87 to 90
pimpl_ = new UIImpl(*this);
if (!pimpl_)
return false;
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new UIImpl(*this) will typically throw std::bad_alloc on failure (or terminate if exceptions are disabled), so the subsequent if (!pimpl_) return false; is ineffective/misleading unless you intentionally use std::nothrow. Consider either switching to new (std::nothrow) UIImpl(*this) and keeping the null-check, or removing the null-check and handling allocation failure via exception policy for this project.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants