diff options
author | Zufu Liu <unknown> | 2021-11-22 08:46:14 +1100 |
---|---|---|
committer | Zufu Liu <unknown> | 2021-11-22 08:46:14 +1100 |
commit | 8904b645419b8deb202046bbc785440d0d006404 (patch) | |
tree | 13a8e979ec427f00bff80f8f002ce18fcdbfe4f6 | |
parent | 598b0b021ca5a585ab256a7e5a1bdafd87931136 (diff) | |
download | scintilla-mirror-8904b645419b8deb202046bbc785440d0d006404.tar.gz |
Bug [#2295] Fix potential memory leak with Korean language input.
-rw-r--r-- | doc/ScintillaHistory.html | 4 | ||||
-rw-r--r-- | win32/HanjaDic.cxx | 122 | ||||
-rw-r--r-- | win32/HanjaDic.h | 2 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 6 |
4 files changed, 73 insertions, 61 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index ca0fbfff1..190820625 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -593,6 +593,10 @@ or SC_ORDER_PERFORMSORT and the list is empty. <a href="https://sourceforge.net/p/scintilla/bugs/2294/">Bug #2294</a>. </li> + <li> + On Win32 prevent potential memory leaks for Korean language input. + <a href="https://sourceforge.net/p/scintilla/bugs/2295/">Bug #2295</a>. + </li> </ul> <h3> <a href="https://www.scintilla.org/scintilla514.zip">Release 5.1.4</a> diff --git a/win32/HanjaDic.cxx b/win32/HanjaDic.cxx index a218b1f18..04df43845 100644 --- a/win32/HanjaDic.cxx +++ b/win32/HanjaDic.cxx @@ -8,23 +8,42 @@ #include <string> #include <string_view> +#include <memory> #define WIN32_LEAN_AND_MEAN 1 #include <windows.h> #include <ole2.h> -#include "UniConversion.h" #include "HanjaDic.h" -namespace Scintilla::Internal { +namespace Scintilla::Internal::HanjaDict { + +struct UnknownReleaser { + // Called by unique_ptr to destroy/free the resource + template <class T> + void operator()(T *pUnknown) noexcept { + // same as ReleaseUnknown() in PlatWin.h + try { + pUnknown->Release(); + } catch (...) { + // IUnknown::Release must not throw, ignore if it does. + } + } +}; + +struct BSTRDeleter { + void operator()(BSTR bstr) const noexcept { + SysFreeString(bstr); + } +}; -namespace HanjaDict { +using UniqueBSTR = std::unique_ptr<OLECHAR[], BSTRDeleter>; interface IRadical; interface IHanja; interface IStrokes; -typedef enum { HANJA_UNKNOWN = 0, HANJA_K0 = 1, HANJA_K1 = 2, HANJA_OTHER = 3 } HANJA_TYPE; +enum HANJA_TYPE { HANJA_UNKNOWN = 0, HANJA_K0 = 1, HANJA_K1 = 2, HANJA_OTHER = 3 }; interface IHanjaDic : IUnknown { STDMETHOD(OpenMainDic)(); @@ -60,82 +79,71 @@ extern "C" const GUID __declspec(selectany) IID_IHanjaDic = { 0xad75f3ac, 0x18cd, 0x48c6, { 0xa2, 0x7d, 0xf1, 0xe9, 0xa7, 0xdc, 0xe4, 0x32 } }; class HanjaDic { -private: - HRESULT hr; - CLSID CLSID_HanjaDic; - -public: - IHanjaDic *HJinterface; + std::unique_ptr<IHanjaDic, UnknownReleaser> HJinterface; - HanjaDic() : HJinterface(nullptr) { - hr = CLSIDFromProgID(OLESTR("mshjdic.hanjadic"), &CLSID_HanjaDic); + bool OpenHanjaDic(LPCOLESTR lpszProgID) noexcept { + CLSID CLSID_HanjaDic; + HRESULT hr = CLSIDFromProgID(lpszProgID, &CLSID_HanjaDic); if (SUCCEEDED(hr)) { + IHanjaDic *instance = nullptr; hr = CoCreateInstance(CLSID_HanjaDic, nullptr, - CLSCTX_INPROC_SERVER, IID_IHanjaDic, - (LPVOID *)& HJinterface); + CLSCTX_INPROC_SERVER, IID_IHanjaDic, + (LPVOID *)&instance); if (SUCCEEDED(hr)) { - hr = HJinterface->OpenMainDic(); + HJinterface.reset(instance); + hr = instance->OpenMainDic(); + return SUCCEEDED(hr); } } + return false; } - // Deleted so HanjaDic objects can not be copied. - HanjaDic(const HanjaDic &) = delete; - HanjaDic(HanjaDic &&) = delete; - HanjaDic &operator=(const HanjaDic &) = delete; - HanjaDic &operator=(HanjaDic &&) = delete; +public: + bool Open() noexcept { + return OpenHanjaDic(OLESTR("imkrhjd.hanjadic")) + || OpenHanjaDic(OLESTR("mshjdic.hanjadic")); + } - ~HanjaDic() { - if (SUCCEEDED(hr)) { - hr = HJinterface->CloseMainDic(); - try { - // This can never fail but IUnknown::Release is not marked noexcept. - HJinterface->Release(); - } catch (...) { - // Ignore any exception - } - } + void Close() const noexcept { + HJinterface->CloseMainDic(); } - bool HJdictAvailable() { - return SUCCEEDED(hr); + bool IsHanja(wchar_t hanja) const noexcept { + HANJA_TYPE hanjaType = HANJA_UNKNOWN; + const HRESULT hr = HJinterface->GetHanjaType(hanja, &hanjaType); + return SUCCEEDED(hr) && hanjaType > HANJA_UNKNOWN; } - bool IsHanja(int hanja) { - HANJA_TYPE hanjaType; - hr = HJinterface->GetHanjaType(static_cast<unsigned short>(hanja), &hanjaType); - if (SUCCEEDED(hr)) { - return (hanjaType > 0); - } - return false; + bool HanjaToHangul(BSTR bstrHanja, UniqueBSTR &bstrHangul) const noexcept { + BSTR result = nullptr; + const HRESULT hr = HJinterface->HanjaToHangul(bstrHanja, &result); + bstrHangul.reset(result); + return SUCCEEDED(hr); } }; -int GetHangulOfHanja(wchar_t *inout) { +bool GetHangulOfHanja(std::wstring &inout) noexcept { // Convert every hanja to hangul. - // Return the number of characters converted. - int changed = 0; + // Return whether any character been converted. + // Hanja linked to different notes in Hangul have different codes, + // so current character based conversion is enough. + // great thanks for BLUEnLIVE. + bool changed = false; HanjaDic dict; - if (dict.HJdictAvailable()) { - const size_t len = wcslen(inout); - wchar_t conv[UTF8MaxBytes] = {0}; - BSTR bstrHangul = SysAllocString(conv); - for (size_t i=0; i<len; i++) { - if (dict.IsHanja(static_cast<int>(inout[i]))) { // Pass hanja only! - conv[0] = inout[i]; - BSTR bstrHanja = SysAllocString(conv); - const HRESULT hr = dict.HJinterface->HanjaToHangul(bstrHanja, &bstrHangul); - if (SUCCEEDED(hr)) { - inout[i] = static_cast<wchar_t>(bstrHangul[0]); - changed += 1; + if (dict.Open()) { + for (wchar_t &character : inout) { + if (dict.IsHanja(character)) { // Pass hanja only! + const UniqueBSTR bstrHanja{SysAllocStringLen(&character, 1)}; + UniqueBSTR bstrHangul; + if (dict.HanjaToHangul(bstrHanja.get(), bstrHangul)) { + changed = true; + character = bstrHangul[0]; } - SysFreeString(bstrHanja); } } - SysFreeString(bstrHangul); + dict.Close(); } return changed; } } -} diff --git a/win32/HanjaDic.h b/win32/HanjaDic.h index c23abc19a..5f7f2a2f5 100644 --- a/win32/HanjaDic.h +++ b/win32/HanjaDic.h @@ -13,7 +13,7 @@ namespace Scintilla::Internal { namespace HanjaDict { -int GetHangulOfHanja(wchar_t *inout); +bool GetHangulOfHanja(std::wstring &inout) noexcept; } diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 1035384e3..e89e93977 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -1055,10 +1055,10 @@ void ScintillaWin::SelectionToHangul() { pdoc->GetCharRange(&documentStr[0], selStart, documentStrLen); std::wstring uniStr = StringDecode(documentStr, CodePageOfDocument()); - const int converted = HanjaDict::GetHangulOfHanja(&uniStr[0]); - documentStr = StringEncode(uniStr, CodePageOfDocument()); + const bool converted = HanjaDict::GetHangulOfHanja(uniStr); - if (converted > 0) { + if (converted) { + documentStr = StringEncode(uniStr, CodePageOfDocument()); pdoc->BeginUndoAction(); ClearSelection(); InsertPaste(&documentStr[0], documentStr.size()); |