Skip to content

Commit 2fc4c91

Browse files
committed
コメントを追加
1 parent 898eb86 commit 2fc4c91

5 files changed

Lines changed: 51 additions & 9 deletions

File tree

sakura_core/_os/CClipboard.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ namespace {
2525
#define STATUS_NO_MEMORY ((DWORD)0xC0000017L)
2626
#endif
2727

28+
/**
29+
* IWBuffer::Append を SEH 例外 STATUS_NO_MEMORY から保護して呼び出す。
30+
*
31+
* C++ 例外ではなく Windows SEH を直接拾うためのラッパ。
32+
*/
2833
static bool SafeAppend(IWBuffer* cmemBuf, const wchar_t* pData, size_t nLen)
2934
{
3035
__try {
@@ -336,7 +341,7 @@ bool CClipboard::GetText(IWBuffer* cmemBuf, bool* pbColumnSelect, bool* pbLineSe
336341
}
337342
}
338343

339-
//サクラ形式のデータがあれば取得
344+
// SAKURAClipW は破損データを検出したら拒否し、既定取得では次の形式へフォールバックする。
340345
CLIPFORMAT uFormatSakuraClip = CClipboard::GetSakuraFormat();
341346
if( (uGetFormat == -1 || uGetFormat == uFormatSakuraClip)
342347
&& IsClipboardFormatAvailable( uFormatSakuraClip ) ){
@@ -362,6 +367,7 @@ bool CClipboard::GetText(IWBuffer* cmemBuf, bool* pbColumnSelect, bool* pbLineSe
362367
}else{
363368
const size_t cchData = static_cast<size_t>(cchRaw);
364369
const size_t cchMax = (cbData - sizeof(SSakuraClipHeader)) / sizeof(wchar_t);
370+
// ヘッダの自己申告値が実メモリを超える場合は破損データとして扱う。
365371
if( cchData > cchMax ){
366372
::GlobalUnlock(hSakura);
367373
if( uGetFormat == uFormatSakuraClip ){
@@ -371,6 +377,7 @@ bool CClipboard::GetText(IWBuffer* cmemBuf, bool* pbColumnSelect, bool* pbLineSe
371377
bool bSakuraCopied = true;
372378
if( cchData > 0 ){
373379
const wchar_t* szData = reinterpret_cast<const wchar_t*>(pData + sizeof(SSakuraClipHeader));
380+
// SAKURAClipW の貼り付けも SEH 経由で保護する。
374381
bSakuraCopied = SafeAppend(cmemBuf, szData, cchData);
375382
}
376383
::GlobalUnlock(hSakura);
@@ -397,6 +404,7 @@ bool CClipboard::GetText(IWBuffer* cmemBuf, bool* pbColumnSelect, bool* pbLineSe
397404
if (szData) {
398405
const SIZE_T cbGlobal = ::GlobalSize(hUnicode);
399406
const size_t cchTotal = wcsnlen(szData, cbGlobal / sizeof(wchar_t));
407+
// 文字数上限で切り詰めたうえで、SEH 例外を SafeAppend で拾う。
400408
const size_t cchSafe = std::min(cchTotal, CLIPBOARD_MAX_CHARS);
401409
if( !SafeAppend(cmemBuf, szData, cchSafe) ){
402410
::GlobalUnlock(hUnicode);
@@ -418,6 +426,7 @@ bool CClipboard::GetText(IWBuffer* cmemBuf, bool* pbColumnSelect, bool* pbLineSe
418426
if( szData ){
419427
const SIZE_T cbGlobal = ::GlobalSize(hText);
420428
const SIZE_T cbLimit = static_cast<SIZE_T>(CLIPBOARD_MAX_CHARS) * sizeof(wchar_t);
429+
// SJIS バイト列の上限も設けてから Unicode 変換する。
421430
const SIZE_T cbSafe = std::min(cbGlobal, cbLimit);
422431
//SJIS→UNICODE
423432
CMemory cmemSjis( szData, cbSafe );
@@ -692,6 +701,7 @@ bool CClipboard::GetClipboardByFormat(CNativeW& mem, const wchar_t* pFormatName,
692701

693702
// 長さオプションの解釈
694703
size_t nLength = GetLengthByMode(hClipData, pData, nMode, nEndMode);
704+
// バイナリモードは文字数、それ以外はバイト数で上限を適用する。
695705
const size_t nLimit = (nMode == -1)
696706
? CLIPBOARD_MAX_CHARS
697707
: static_cast<size_t>(CLIPBOARD_MAX_CHARS) * sizeof(wchar_t);

sakura_core/_os/CClipboard.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,17 @@ struct StdWStringBuffer : public IWBuffer {
4949
};
5050

5151
#pragma pack(push, 1)
52+
/**
53+
* SAKURAClipW 独自クリップボード形式のバイナリヘッダ。
54+
*
55+
* メモリレイアウト:
56+
* [SSakuraClipHeader (4bytes)] [wchar_t szData[cchData]] [wchar_t L'\0']
57+
*
58+
* int32_t 固定にすることで 32bit/64bit 間のレイアウト不一致を避ける。
59+
* フォーマット名 "SAKURAClipW" 自体は変更しない。
60+
*/
5261
struct SSakuraClipHeader {
53-
int32_t cchData;
62+
int32_t cchData; //!< データの文字数(wchar_t 単位、負値は不正データ)
5463
};
5564
#pragma pack(pop)
5665
static_assert(sizeof(SSakuraClipHeader) == 4, "SSakuraClipHeader must be exactly 4 bytes");
@@ -88,6 +97,7 @@ class CClipboard{
8897
// OpenClipboard retry constants (public for testing)
8998
static constexpr int CLIPBOARD_RETRY_COUNT = 10;
9099
static constexpr int CLIPBOARD_RETRY_DELAY_MS = 10;
100+
//! クリップボード読み込み時の安全な上限(文字数)。INT32_MAX に合わせる。
91101
static constexpr size_t CLIPBOARD_MAX_CHARS = static_cast<size_t>(INT32_MAX);
92102

93103
private:
@@ -116,5 +126,6 @@ class CClipboard{
116126
virtual HGLOBAL GlobalAlloc(UINT uFlags, SIZE_T dwBytes) const;
117127
virtual LPVOID GlobalLock(HGLOBAL hMem) const;
118128
};
129+
//! CClipboard::CLIPBOARD_MAX_CHARS のグローバルスコープ別名。
119130
static constexpr size_t CLIPBOARD_MAX_CHARS = CClipboard::CLIPBOARD_MAX_CHARS;
120131
#endif /* SAKURA_CCLIPBOARD_4E783022_214C_4E51_A2E0_54EC343500F6_H_ */

sakura_core/_os/CDropTarget.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ namespace {
2727
#define STATUS_NO_MEMORY ((DWORD)0xC0000017L)
2828
#endif
2929

30+
/**
31+
* new BYTE[] を SEH 例外 STATUS_NO_MEMORY から保護して呼び出す。
32+
*/
3033
static bool SafeNewBytes(BYTE** ppOut, size_t nSize)
3134
{
3235
__try {
@@ -212,9 +215,11 @@ void CDataObject::SetText( LPCWSTR lpszText, size_t nTextLen, BOOL bColumnSelect
212215
m_nFormat = 0;
213216
}
214217
if( lpszText != nullptr ){
218+
// SAKURAClipW は int32_t 範囲に収まる場合だけ作る。
215219
const bool bUseSakuraFormat = (nTextLen <= static_cast<size_t>(INT32_MAX));
216220
m_nFormat = (bUseSakuraFormat ? 3 : 2) + (bColumnSelect ? 1 : 0); // 矩形を含めるか
217221
m_pData = new DATA[m_nFormat];
222+
// goto fail 時に未初期化ポインタを delete[] しないようにする。
218223
for( i = 0; i < m_nFormat; i++ ){
219224
m_pData[i].data = nullptr;
220225
}
@@ -243,6 +248,7 @@ void CDataObject::SetText( LPCWSTR lpszText, size_t nTextLen, BOOL bColumnSelect
243248
if( !SafeNewBytes(&m_pData[i].data, m_pData[i].size) ){
244249
goto fail;
245250
}
251+
// SAKURAClipW のヘッダは固定幅の int32_t で書き込む。
246252
const int32_t cchData = static_cast<int32_t>(nTextLen);
247253
memcpy_raw( m_pData[i].data, &cchData, sizeof(cchData) );
248254
memcpy_raw( m_pData[i].data + sizeof(SSakuraClipHeader), lpszText, nTextLen * sizeof( wchar_t ) );

sakura_core/view/CEditView_Mouse.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ namespace {
5252
#define STATUS_NO_MEMORY ((DWORD)0xC0000017L)
5353
#endif
5454

55+
/**
56+
* CNativeW::SetString を SEH 例外 STATUS_NO_MEMORY から保護して呼び出す。
57+
*/
5558
static bool SafeSetString(CNativeW& buf, const wchar_t* pData, size_t nLen)
5659
{
5760
__try {
@@ -1857,16 +1860,19 @@ STDMETHODIMP CEditView::Drop( LPDATAOBJECT pDataObject, DWORD dwKeyState, POINTL
18571860
return E_INVALIDARG;
18581861
pData = ::GlobalLock( hData );
18591862
nSize = ::GlobalSize( hData );
1863+
// SAKURAClipW は壊れたヘッダを検出したら拒否し、次の形式へフォールバックする。
18601864
if( cf == CClipboard::GetSakuraFormat() ){
18611865
if( pData == nullptr || nSize < sizeof(SSakuraClipHeader) ){
18621866
}else{
18631867
SSakuraClipHeader header;
1868+
// エイリアシング安全な読み取り。
18641869
memcpy_raw(&header, pData, sizeof(header));
18651870
if( header.cchData >= 0 ){
18661871
const size_t cchData = static_cast<size_t>(header.cchData);
18671872
const size_t cchMax = (nSize - sizeof(SSakuraClipHeader)) / sizeof(wchar_t);
18681873
if( cchData <= cchMax ){
18691874
const wchar_t* pszData = reinterpret_cast<const wchar_t*>((BYTE*)pData + sizeof(SSakuraClipHeader));
1875+
// 途中の NUL 文字も含めて貼り付ける。
18701876
cmemBuf.SetString( pszData, cchData ); // 途中のNUL文字も含める
18711877
break;
18721878
}
@@ -1889,6 +1895,7 @@ STDMETHODIMP CEditView::Drop( LPDATAOBJECT pDataObject, DWORD dwKeyState, POINTL
18891895
}
18901896
continue;
18911897
}
1898+
// CF_UNICODETEXT は文字数を上限で切り詰めたうえで SetString する。
18921899
if( cf == CF_UNICODETEXT ){
18931900
const size_t cchTotal = wcsnlen( (wchar_t*)pData, nSize / sizeof(wchar_t) );
18941901
const size_t cchSafe = (cchTotal > CClipboard::CLIPBOARD_MAX_CHARS)
@@ -1904,6 +1911,7 @@ STDMETHODIMP CEditView::Drop( LPDATAOBJECT pDataObject, DWORD dwKeyState, POINTL
19041911
return E_OUTOFMEMORY;
19051912
}
19061913
}else{
1914+
// CF_TEXT は SJIS とみなして Unicode へ変換する。
19071915
const SIZE_T cbLimit = static_cast<SIZE_T>(CClipboard::CLIPBOARD_MAX_CHARS) * sizeof(wchar_t);
19081916
const SIZE_T cbSafe = (nSize > cbLimit) ? cbLimit : nSize;
19091917
CNativeA binary;

src/test/cpp/tests1/test-cclipboard.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ MATCHER_P(AnsiStringInGlobalMemory, expected_string, "") {
4646
return match;
4747
}
4848

49-
// グローバルメモリに書き込まれたサクラ独自形式データにマッチする述語関数
49+
// グローバルメモリに書き込まれた SAKURAClipW 独自形式データにマッチする述語関数。
50+
// SSakuraClipHeader から int32_t でデータ長を読み取り、負値を不正として扱う。
5051
MATCHER_P(SakuraFormatInGlobalMemory, expected_string, "") {
5152
char* p = (char*)::GlobalLock(arg);
5253
if (!p) return false;
@@ -196,15 +197,17 @@ TEST(CClipboard, SetText6) {
196197
EXPECT_FALSE(clipboard.SetText(text.data(), text.length(), false, true, 0));
197198
}
198199

199-
// SetText のテスト。SAKURAClipW のヘッダが int32_t 範囲を超える場合。
200+
// SetText のテスト。nDataLen > INT32_MAX でサクラ形式を指定した場合、
201+
// SAKURAClipW のヘッダに収まらないため SetClipboardData は呼ばれず false を返す。
200202
TEST(CClipboard, SetText7) {
201203
const wchar_t text[] = L"x";
202204
MockCClipboard clipboard;
203205
EXPECT_CALL(clipboard, SetClipboardData(_, _)).Times(0);
204206
EXPECT_FALSE(clipboard.SetText(text, static_cast<size_t>(INT32_MAX) + 1, false, false, CClipboard::GetSakuraFormat()));
205207
}
206208

207-
// SetText のテスト。nDataLen > INT32_MAX でも矩形選択フラグは書き込まれる。
209+
// SetText のテスト。nDataLen > INT32_MAX でもフォーマット未指定(-1)の場合、
210+
// SAKURAClipW はスキップされるが CF_UNICODETEXT と矩形選択フラグは書き込まれ true を返す。
208211
TEST(CClipboard, SetText8) {
209212
const wchar_t text[] = L"x";
210213
const size_t hugeLen = static_cast<size_t>(INT32_MAX) + 1;
@@ -215,7 +218,8 @@ TEST(CClipboard, SetText8) {
215218
EXPECT_TRUE(clipboard.SetText(text, hugeLen, true, false, -1));
216219
}
217220

218-
// SetText のテスト。nDataLen + 1 が size_t を超える場合は失敗する。
221+
// SetText のテスト。nDataLen + 1 が size_t をオーバーフローする場合、
222+
// CF_UNICODETEXT の GlobalAlloc サイズ計算段階で検出されスキップ、false を返す。
219223
TEST(CClipboard, SetTextSizeTOverflow) {
220224
const wchar_t text[] = L"x";
221225
MockCClipboard clipboard;
@@ -336,7 +340,8 @@ TEST_F(CClipboardGetText, NoSpecifiedFormat6) {
336340
EXPECT_FALSE(clipboard.GetText(&buffer, nullptr, nullptr, eol, -1));
337341
}
338342

339-
// サクラ形式のヘッダが負値の場合は失敗する。
343+
// GetText のテスト。SAKURAClipW ヘッダの cchData が負値(-1)の場合、
344+
// 第2段階フェイルセーフにより不正データとして拒否される(フォーマット未指定で false)。
340345
TEST_F(CClipboardGetText, SakuraFormatNegativeLength) {
341346
GlobalMemory mem(GMEM_MOVEABLE, sizeof(SSakuraClipHeader) + (sakuraText.size() + 1) * sizeof(wchar_t));
342347
mem.Lock<unsigned char>([=](unsigned char* p) {
@@ -348,7 +353,8 @@ TEST_F(CClipboardGetText, SakuraFormatNegativeLength) {
348353
EXPECT_FALSE(clipboard.GetText(&buffer, nullptr, nullptr, eol, -1));
349354
}
350355

351-
// サクラ形式のヘッダが実データ長を超えている場合は失敗する。
356+
// GetText のテスト。SAKURAClipW ヘッダの cchData(= 2)が実データ長(1文字分)を超過する場合、
357+
// 第3段階フェイルセーフにより破損データとして拒否される。
352358
TEST_F(CClipboardGetText, SakuraFormatOverflowLength) {
353359
constexpr std::wstring_view shortText = L"x";
354360
GlobalMemory mem(GMEM_MOVEABLE, sizeof(SSakuraClipHeader) + shortText.size() * sizeof(wchar_t));
@@ -361,7 +367,8 @@ TEST_F(CClipboardGetText, SakuraFormatOverflowLength) {
361367
EXPECT_FALSE(clipboard.GetText(&buffer, nullptr, nullptr, eol, -1));
362368
}
363369

364-
// 壊れたサクラ形式があっても、既定取得では Unicode にフォールバックする。
370+
// GetText のテスト。SAKURAClipW が破損(ヘッダ負値)していても、
371+
// フォーマット未指定の既定取得では CF_UNICODETEXT にフォールバックし true を返す。
365372
TEST_F(CClipboardGetText, CorruptedSakuraFallsBackToUnicode) {
366373
GlobalMemory mem(GMEM_MOVEABLE, sizeof(SSakuraClipHeader) + (sakuraText.size() + 1) * sizeof(wchar_t));
367374
mem.Lock<unsigned char>([=](unsigned char* p) {

0 commit comments

Comments
 (0)