Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

コンボボックスのサブクラス化に関連するクラッシュバグの修正 #1481

Merged
merged 2 commits into from
Dec 12, 2020

Conversation

kengoide
Copy link
Member

@kengoide kengoide commented Dec 9, 2020

PR の目的

「ファイルを開く」および「名前を付けて保存」ダイアログにて、「最近のファイル」・「最近のフォルダ」コンボボックスにフォーカスがある状態で Ctrl+Backspace を押すとクラッシュします。
#1470 の機能追加による劣化バグで、本PRはその修正が目的です。

カテゴリ

  • 不具合修正

PR の背景

問題の原因ですが、コンボボックスをサブクラス化する処理が CBS_DROPDOWNLIST (編集できないコンボボックス)を考慮していなかったことです。
SetComboBoxDeleter 関連のコードは、API関数 GetComboBoxInfo を通じて コンボボックス内部の Edit のハンドルを入手できることを前提としています。編集可能なコンボボックスでは期待通りにEditを取得できますが、CBS_DROPDOWNLIST スタイルのコンボボックスに対して同じことをすると結果は ComboBox のハンドルになってしまいます。このケースを考慮できていませんでした。

COMBOBOXINFO info = { sizeof(COMBOBOXINFO) };
if (!::GetComboBoxInfo(hwndCtl, &info))
return;
::SetWindowSubclass(info.hwndItem, SubEditProc, 0, (DWORD_PTR)pRecent);

hwndCtl が CBS_DROPDOWNLIST スタイルのコンボボックスだった場合、info.hwndItem に ComboBox が入った状態で返ってくるため、Edit をサブクラス化するつもりで ComboBox をサブクラス化することになります。

LRESULT CALLBACK SubEditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
HWND hwndCombo = GetParent(hwnd);

ここで Edit の親(=ComboBox)を取得しようとして ComboBox の親(=ダイアログ)を取得してます。

case WM_CHAR:
// ASCII 削除文字。Ctrl + Backspace が入力された。
if (wParam == 0x7f) {
DWORD selStart, selEnd;
Combo_GetEditSel(hwndCombo, selStart, selEnd);

hwndCombo はダイアログです。CB_GETEDITSELには反応してくれません。selStartselEndは未初期化のままです。

// 単語削除する
const int length = ::GetWindowTextLength(hwndCombo);
auto text = std::make_unique<wchar_t[]>(length + 1);
::GetWindowText(hwndCombo, text.get(), length + 1);
const int pos = DeletePreviousWord(text.get(), length, selStart);

length は 0、textL'\0'が入った長さ1の配列となります。selStartが偶然0になっていなければDeletePreviousWordの中で Access Violation が発生します😢

仕様・動作説明

問題に対する対処として、CBS_DROPDOWNLIST スタイルのコンボボックスに SetComboBoxDeleter を適用しないことにします。該当するのは「ファイルを開く」および「名前を付けて保存」ダイアログ下部のそれです。
副作用として履歴削除が機能しなくなる…と思いきや、実は別バグ(後述)により CBS_DROPDOWNLIST スタイルのコンボボックスでは元から機能していなかったため、機能面では退行しないものと思われます。

PR の影響範囲

以下のダイアログに存在したクラッシュバグを修正します。

  • ファイルを開く・名前を付けて保存(Vistaスタイルを除く)

以下の画面に存在するコンボボックスに関係するコードを変更します。

  • 検索・置換
  • Grep・Grep置換
  • 外部コマンド実行
  • ツールバーの検索ボックス

テスト内容

  • 「共通設定」→「編集」→「Vistaスタイルのファイルダイアログ」にチェックが入っていない状態で、開く・保存ダイアログに対して以下のテストが必要です

    • 「最近のファイル」・「最近のフォルダ」をクリックするなどしてフォーカスを移動させる
    • Ctrl + Backspace を押下する
    • プログラムがクラッシュしないことを確認する
  • 他の画面の該当コンボボックス(上記)に対して、履歴削除・単語削除がそれぞれ引き続き機能することの確認が必要です。

関連 issue, PR

#1463, #1470

参考資料

履歴削除の別バグ

// コンボボックスのキャレット位置を取得
DWORD dwSelStart = 0;
DWORD dwSelEnd = 0;
Combo_GetEditSel( hwndCombo, dwSelStart, dwSelEnd );
// アイテムテキストとエディットテキストが異なる、またはエディットが全選択でなかった場合
if ( cItemText != cEditText
|| 0 < dwSelStart
|| dwSelEnd < (DWORD)cEditText.GetStringLength()
)
{
// 履歴削除をスキップする
return;
}

CBS_DROPDOWNLIST スタイルのコンボボックスは CB_GETEDITSEL が送られてきても何もしないようで、dwSelStartdwSelEndは常に0のまま変わりません。cEditTextは最短でも長さ1(null文字の分)であるため、dwSelEnd < (DWORD)cEditText.GetStringLength()の条件式により、履歴削除が実行されることはありません。
本 PR では元から動いていなかったことを理由として機能を削除しますが、対処方針として適切かどうかというと微妙だと思っています。後から追加PRとして修正することも考えていますので、問題があればご指摘ください。

@kengoide kengoide added 🐛bug🦋 ■バグ修正(Something isn't working) 💩degradation🧻🚽 デグレ (前に動いていた機能が動かなくなった) labels Dec 9, 2020
@AppVeyorBot
Copy link

Build sakura 1.0.3287 completed (commit 6073a73ce1 by @k-kagari)

berryzplus
berryzplus previously approved these changes Dec 9, 2020
Copy link
Contributor

@berryzplus berryzplus left a comment

Choose a reason for hiding this comment

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

指摘2件ありますが、クラッシュバグの回復が優先だと思うのでapproveにしておきます。

sakura_core/dlg/CDialog.cpp Outdated Show resolved Hide resolved
sakura_core/dlg/CDialog.cpp Outdated Show resolved Hide resolved
sanomari
sanomari previously approved these changes Dec 10, 2020
@kengoide kengoide dismissed stale reviews from sanomari and berryzplus via e726726 December 11, 2020 09:30
@kengoide
Copy link
Member Author

Approvalをいただきましたが、PRの出し直しを避けたいため先に指摘に対応させてください。

@AppVeyorBot
Copy link

Build sakura 1.0.3288 completed (commit 25aff663e3 by @k-kagari)

@kengoide
Copy link
Member Author

承認ありがとうございます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛bug🦋 ■バグ修正(Something isn't working) 💩degradation🧻🚽 デグレ (前に動いていた機能が動かなくなった)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants