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

CNativeW::SetString に NULL を指定した場合に wcslen に NULL を渡して落ちてしまう不具合を修正 #1087

Merged
merged 3 commits into from
Nov 6, 2019

Conversation

beru
Copy link
Contributor

@beru beru commented Nov 3, 2019

@berryzplus さん、レビューお願いします。

PR の目的

CNativeW::SetString の引数に NULL が渡ってきた場合に wcslen にそのまま NULL を渡して落ちてしまう不具合を修正するのが目的です。

カテゴリ

  • 不具合修正

PR の背景

実際に呼ばれるケースが存在するのかは不明ですが(実アプリでの再現手順は不明)起きうるかもしれないので対処を入れました。ユニットテストに落ちる事を確認する DEATH テストが入っていましたが、落ちる動作をわざわざ期待してその挙動を保つ必要も無いのかなと思います。

PR のメリット

CNativeW::SetString の引数に NULL が渡ってきた場合に落ちる事が無くなります。

PR のデメリット (トレードオフとかあれば)

CNativeW::SetString の引数の NULL チェックの分だけ処理コストが(わずかに)増えます。

PR の影響範囲

CNativeW::SetString の呼び出し箇所の動作に影響します。しかし落ちる動作を保つべきという事も無いと思います。

関連チケット

#1086

@beru beru added the 🐛bug🦋 ■バグ修正(Something isn't working) label Nov 3, 2019
@beru beru requested a review from berryzplus November 3, 2019 19:20
@AppVeyorBot
Copy link

Build sakura 1.0.2371 completed (commit 19296a07d6 by @beru)

if (pszData)
CNative::SetRawData(pszData,wcslen(pszData) * sizeof(wchar_t));
else
Clear();
Copy link
Contributor

Choose a reason for hiding this comment

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

NullとEmpty(空文字列)を区別して扱えるようにしたいです。
ここの Clear() は型修飾を付けて CMemory::Clear() とすべきだと思います。

CNativeWから修飾なしで Clear() を呼び出すと CNative::Clear() が使われます。
CMemoryCNative では Clear() の意味が違っていて、CNative::Clear() だとメモリを開放しないのでNULLを代入できません。

  • 派生関係にある2つのクラスで、同名関数の挙動が違う、というのは混乱のもとです。そういう混乱を防ぐための指針として リスコフの置換原則 というものがあります。
  • CNative::Clear() の挙動を変更したのは CNative::Clear の実装を改善 #777 で、比較的最近の話です。たしか当時、std::basic_string::clear() の挙動に習って「メモリを開放しない」という拡張を行った気がします。この変更自体を「間違い」とは思っていません。
  • CMemory のメモリ解放関数の名前が _Empty() なのも混乱の元かもです。CMemory は「空っぽにできる対象」を2つ持っています。1つ目が「確保したメモリ」で2つ目が「メモリの中身」です。現在の CMemory::Clear() の実装は「確保したメモリ」を「空っぽにする」です。派生クラス側で「メモリの中身」を空っぽにする関数に Clear() と名付けているのでややこしくなってる感じです。

Copy link
Contributor Author

@beru beru Nov 4, 2019

Choose a reason for hiding this comment

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

お、そういう違いがあるんですね。認識してませんでした。ややこしいなぁ。

しかし文字列型クラスである CNativeW って今は CNative を継承する作りになっていて、CNative は CMemory を継承していますが、機能を実現するにあたって継承構造にする必要性って無いような気がするんですよね。

ところで、領域確保していない NULL と、領域確保はしているけど文字列の長さが 0 の空文字状態の区別は、外部から区別するとしたら capacity メソッドを使う事ぐらいでしょうかね。

void CNativeW::SetString( const wchar_t* pszData ) に NULL が渡されたときに領域確保していない状態にする事で何かの旨味があるのかはよくわかりません。文字列型として考えた時に使用する外部が使い分けを意識するのは何か面倒くさそう…。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#1086 の説明を読むと、NULL 代入後に NULL と比較した際に true が返るようにしたい、というのがモチベなんでしょうか?

メモリ領域を確保していない NULL 状態と 領域確保してて文字列の長さが 0 の場合のインスタンスの比較結果は false になるという事ですよね。うーん、文字列型としてその挙動が自然なのかなぁ。抽象的な文字列というより具象的な文字列メモリとして扱う型になりそう。

Copy link
Contributor

Choose a reason for hiding this comment

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

#1086 の説明を読むと、NULL 代入後に NULL と比較した際に true が返るようにしたい、というのがモチベなんでしょうか?

う~む。それがモチベか?と問われると微妙です。

  • 代入できるってことは、代入後に指定した値と等価になることなんじゃないかと思います。

  • NULLが代入できるってことは、代入後にNULLと等価になるんだと思います。

  • 現在はNULLと比較できないので微妙です。

    • NULLと比較して等価になるCNativeWはメモリ未確保状態だと思います。
    • メモリ確保状態からメモリ未確保となるためにはメモリを開放する必要があります。
  • std::wstringはNULLという値を保持できません。

  • CNativeWはNULLという値を保持できます。

考えようによっては、NULLを保持できることがCNativeWを残して使っていくメリットの1つだと思います。
全部「std::wstringに習って」で進めていくんだとしたら「なんでCNativeWを残してくの?」という疑問がつきまとう気がします。CNativeWを使うメリット、というのはあると思っているので、今後も改善しつつ残していくつもりではいますが。

メモリ領域を確保していない NULL 状態と 領域確保してて文字列の長さが 0 の場合のインスタンスの比較結果は false になるという事ですよね。うーん、文字列型としてその挙動が自然なのかなぁ。

まだ比較演算子は実装できてないんですが、そういうことになります。
NULLとL""は区別したいっす。あとで string.IsNullOrEmpty() を作る羽目になるとしても、です。

抽象的な文字列というより具象的な文字列メモリとして扱う型になりそう。

言葉の意味がわからんかったとです。

抽象的な文字列ってのは、たとえば std::wstring ですかね?
超ざっくりですが、CNativeWとstd::wstringはベツモノだと思っています。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

色々と説明ありがとうございます。NULL と L"" を区別したいという意思は分かりました。それに対して肯定/反対する明確な理由は自分は今のところ持ち合わせていないです。

抽象的な文字列ってのは、たとえば std::wstring ですかね?
超ざっくりですが、CNativeWとstd::wstringはベツモノだと思っています。

C++ の文字列型として有名なのは、std::basic_string や Microsoft の MFC/ATL/WTL 等で使われてる CString でしょうか? QTを使ってる人はQString なんかも使っていそう。まぁなんとなく文字列の扱いを快適に行える型とイメージしていました、C++に限らず。

CNativeW の内外のサポートが充実すれば快適度が増していくと思うので、そうなれば他の文字列型と気になる違いがあったとしても、それはそれ、これはこれ、と片付けてしまって良いと思います。

まぁ単に文字列型の使用状況を単純化したいなら標準の std::wstring を出来るだけ使うようにすれば良いのかもしれないですけど、そのように変更する流れになっていないという事はやっぱ色々メリットデメリットがあるのかなぁ。。C言語の標準関数使って書かれている部分もたくさんあるし、小回りが利く、とか、過去の経緯で、とか色々な理由で混在してるんでしょうか…。C++の標準ライブラリの文字列への配慮が薄いのは作者の頭髪と関連しているのかもしれないですね。


CNativeW value2(nullptr);
EXPECT_EQ(value2.GetStringLength(), 0);
EXPECT_EQ(value2.GetStringPtr(), nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

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

expected, actualの書き順が逆っす 😄

というアフォな突っ込みを過去何度か入れた気がしますが、こういう指摘はしないほうがいいんでしょうかね。

Copy link
Contributor Author

@beru beru Nov 4, 2019

Choose a reason for hiding this comment

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

http://opencv.jp/googletestdocs/primer.html#primer-binary-comparison

第1引数が期待値で、第2引数が実際の値にした方がいいんでしょうか?EXPECT_EQ マクロのコメント内の Examples ではそういう記載になっていませんけれど。

Copy link
Contributor Author

@beru beru Nov 4, 2019

Choose a reason for hiding this comment

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

expected, actualの書き順が逆っす 😄

というアフォな突っ込みを過去何度か入れた気がしますが、こういう指摘はしないほうがいいんでしょうかね。

社会の窓が開いてたりシャツの表裏や前後ろを反対に着ている人にする指摘と同じような事かもです。

どういうリアクションになるかは指摘された人の性格によるかもしれません。
実用上問題無いといって指摘をはねのける人がいるかもしれません。

パンツを頭に被っていたり全裸で歩いている人を公道で見かけた場合には…おそらく指摘しないで急いで立ち去った方が良いと思います。警察に通報するとか。

@AppVeyorBot
Copy link

Build sakura 1.0.2372 completed (commit b93dc34591 by @beru)

berryzplus
berryzplus previously approved these changes Nov 5, 2019
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.

マージにあたっての問題は解消したように思うのでレビュー更新します。

* @brief コンストラクタ(nullptr指定)の仕様
* @remark 構築できない(実行時エラーになる)
* @note バグですね(^^;
* @brief コンストラクタ(NULL指定)の仕様
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

このクラスに関して、テストを整備する目的は挙動を仕様化することなので、想定結果をコメントで入れたいっす。

まあ、後で自分でPR出しますんで対応不要ですが。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

2d5a94a でコメントを追加しました。


CNativeW value2(nullptr);
EXPECT_EQ(0, value2.GetStringLength());
EXPECT_EQ(nullptr, value2.GetStringPtr());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

キャパがゼロになるのも仕様な認識です。

これも後追いでいいです。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

2d5a94a でコメントを追加しました。

@AppVeyorBot
Copy link

Build sakura 1.0.2374 completed (commit d81719325b by @beru)

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.

対応ありがとうございます。
再approveしときます。

@beru
Copy link
Contributor Author

beru commented Nov 6, 2019

@berryzplus さん

レビューありがとうございます。
Merge します。もし問題が見つかったら別のPRで対処します。

@beru beru merged commit 3387afe into sakura-editor:master Nov 6, 2019
@beru beru deleted the CNativeW_SetString_NULL branch November 6, 2019 12:37
@m-tmatma m-tmatma added this to the v2.4.0 milestone Dec 29, 2019
HoppingTappy pushed a commit to HoppingTappy/sakura that referenced this pull request Jun 16, 2020
CNativeW::SetString に NULL を指定した場合に wcslen に NULL を渡して落ちてしまう不具合を修正
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛bug🦋 ■バグ修正(Something isn't working)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants