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

SonarQubeの静的解析で検出されたバグを修正する #1439

Merged
merged 14 commits into from
Oct 29, 2020

Conversation

sanomari
Copy link
Contributor

PR の目的

SonarQubeの静的解析で検出されたバグを修正します。

カテゴリ

  • リファクタリング

PR の背景

https://github.com/sakura-editor/sakura の README.md に貼ってある Sonar Qube の静的解析で、致命的なエラーが出ているのが気になっています。

Quality Gate Status
 👆2020/10/26現在、failed って出てます。

現在検出されているNG箇所は 330個 あります。

今回は、ランク分けされたNG箇所のうち、最もダメな警告に対処してみたいと思います。

対処するNG指摘

Potential leak of memory pointed to by field '_Myval2'

対処方法

std::wstring を使ってメモリ確保失敗時に例外が発生するように修正します。

PR の影響範囲

ウインドウテキストの取得に生配列のスマートポインタを利用していた箇所をstd::wstringで置換します。

PR のメリット

静的解析で検出される警告が減ります。

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

何か動作かえてしまっていたらごめんなさい。

仕様・動作説明

設計時にバッファサイズを確定できない wchar_t 配列を動的に確保するコードをリファクタリングします。

PR の影響範囲

テスト内容

動作を変えていないので軽く動かしてみただけです。

関連 issue, PR

参考資料

https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsLrUe04Z9I8ZMqv&open=AXHBcsLrUe04Z9I8ZMqv
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsLrUe04Z9I8ZMqw&open=AXHBcsLrUe04Z9I8ZMqw
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsLrUe04Z9I8ZMqx&open=AXHBcsLrUe04Z9I8ZMqx
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsJ7Ue04Z9I8ZMqt&open=AXHBcsJ7Ue04Z9I8ZMqt
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsJ7Ue04Z9I8ZMqu&open=AXHBcsJ7Ue04Z9I8ZMqu
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqAzUe04Z9I8ZMqP&open=AXHBcqAzUe04Z9I8ZMqP
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcp85Ue04Z9I8ZMqN&open=AXHBcp85Ue04Z9I8ZMqN
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcp85Ue04Z9I8ZMqO&open=AXHBcp85Ue04Z9I8ZMqO
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsLrUe04Z9I8ZMqv&open=AXHBcsLrUe04Z9I8ZMqv
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsLrUe04Z9I8ZMqw&open=AXHBcsLrUe04Z9I8ZMqw
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsLrUe04Z9I8ZMqx&open=AXHBcsLrUe04Z9I8ZMqx
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsJ7Ue04Z9I8ZMqt&open=AXHBcsJ7Ue04Z9I8ZMqt
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcsJ7Ue04Z9I8ZMqu&open=AXHBcsJ7Ue04Z9I8ZMqu
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqAzUe04Z9I8ZMqP&open=AXHBcqAzUe04Z9I8ZMqP
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcp85Ue04Z9I8ZMqN&open=AXHBcp85Ue04Z9I8ZMqN
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcp85Ue04Z9I8ZMqO&open=AXHBcp85Ue04Z9I8ZMqO
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcp2SUe04Z9I8ZMqL&open=AXHBcp2SUe04Z9I8ZMqL
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcp5XUe04Z9I8ZMqM&open=AXHBcp5XUe04Z9I8ZMqM
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqEqUe04Z9I8ZMqQ&open=AXHBcqEqUe04Z9I8ZMqQ
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqEqUe04Z9I8ZMqR&open=AXHBcqEqUe04Z9I8ZMqR
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBco-yUe04Z9I8ZMqF&open=AXHBco-yUe04Z9I8ZMqF
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqo5Ue04Z9I8ZMqS&open=AXHBcqo5Ue04Z9I8ZMqS
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqo5Ue04Z9I8ZMqT&open=AXHBcqo5Ue04Z9I8ZMqT
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqo5Ue04Z9I8ZMqU&open=AXHBcqo5Ue04Z9I8ZMqU
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqW&open=AXHBcqvOUe04Z9I8ZMqW
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqX&open=AXHBcqvOUe04Z9I8ZMqX
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqY&open=AXHBcqvOUe04Z9I8ZMqY
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqZ&open=AXHBcqvOUe04Z9I8ZMqZ
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqa&open=AXHBcqvOUe04Z9I8ZMqa
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqb&open=AXHBcqvOUe04Z9I8ZMqb
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqc&open=AXHBcqvOUe04Z9I8ZMqc
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqd&open=AXHBcqvOUe04Z9I8ZMqd
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqe&open=AXHBcqvOUe04Z9I8ZMqe
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcqvOUe04Z9I8ZMqf&open=AXHBcqvOUe04Z9I8ZMqf
https://sonarcloud.io/project/issues?id=sakura-editor_sakura&issues=AXHBcr28Ue04Z9I8ZMqs&open=AXHBcr28Ue04Z9I8ZMqs

std::make_unique<WCHAR[]>を使わないで済むようにラッパー関数を追加する
std::make_unique<WCHAR[]>を使わないで済むようにラッパー関数を追加する
std::make_unique<WCHAR[]>を使わないで済むようにラッパー関数を追加する
std::make_unique<WCHAR[]>を使わないように修正
std::make_unique<WCHAR[]>を使わないように修正
std::make_unique<WCHAR[]>を使わないように修正
std::make_unique<WCHAR[]>を使わないように修正
std::make_unique<WCHAR[]>を使わないように修正
@AppVeyorBot
Copy link

Build sakura 1.0.3187 completed (commit cae422f7b5 by @sanomari)

berryzplus
berryzplus previously approved these changes Oct 26, 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.

ざっと見た感じ問題なさそうです。

sakura_core/CHokanMgr.cpp Outdated Show resolved Hide resolved
sakura_core/apiwrap/StdControl.h Show resolved Hide resolved
sakura_core/debug/Debug1.cpp Outdated Show resolved Hide resolved
sakura_core/debug/Debug1.cpp Outdated Show resolved Hide resolved
@oooonduke
Copy link

サクラエディタ v2.4.2.3187 64bit dev Alpha Version
(GitHash cae422f)
(GitURL https://github.com/sakura-editor/sakura.git)
バージョン情報のSourceURLが…giとなっているのが気になります。

@berryzplus
Copy link
Contributor

バージョン情報のSourceURLが…giとなっているのが気になります。

ほんとですね。
image

@sanomari
Copy link
Contributor Author

すみません、やらかしていました。

@sanomari sanomari marked this pull request as ready for review October 26, 2020 03:49
@AppVeyorBot
Copy link

Build sakura 1.0.3188 failed (commit e9d0e88a1d by @sanomari)

@AppVeyorBot
Copy link

Build sakura 1.0.3189 completed (commit c010103003 by @sanomari)

@AppVeyorBot
Copy link

Build sakura 1.0.3190 completed (commit f02504c121 by @sanomari)

Copy link
Contributor

@usagisita usagisita left a comment

Choose a reason for hiding this comment

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

エラーメッセージでぐぐると以下のものがヒットします。
https://bugs.llvm.org/show_bug.cgi?id=38176
これって誤検出なのではないか、と思うのですが、実際にバグで、メモリーリークするケースがあるのでしょうか?
どういう状況で問題があるのか分かっているなら、教えてほしいなと思います。
もっとも、誤検出かどうかにかかわらず、これらのべた書きの処理をまとめるという部分に関しては、大賛成です。

while( NULL != (token = my_strtok<WCHAR>( strPath.data(), nPathLen, &nPathPos, L";")) ){
std::wstring strTemp( token );
if( strTemp.length() >= 2 && strTemp.front() == L'"' && strTemp.back() == strTemp.front() ){
strTemp = strTemp.substr( 1, strTemp.length() - 2 );
Copy link
Contributor

Choose a reason for hiding this comment

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

ここは一見同じ処理かもしれませんが、違いますね。
元のコードはパス中に見つかった"をすべて削除するコードです。途中に"がある場合も含まれています。
途中の"も勘案してくれるのは、my_strtokがそういう仕様です。
file"\hoge piyo"subfolder みたいなちょっと気持ち悪いパスにも対応しています。
新しいコードは前後で囲われた""のみに対応しています。
これが問題になるのはかなりのレアケースではあるんでしょうけど、違うといえば違います。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

レビューありがとうございます。
パスに含まれる " を削除する処理に直したいと思います。

}

// ウィンドウテキストを取得するのに必要なバッファを確保する
strText.reserve( cchRequired );
Copy link
Contributor

Choose a reason for hiding this comment

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

reserveはバッファの確保はしてくれるものの、その拡張領域へ勝手にアクセスしてはいけないことになっています。
https://qiita.com/amayaw9/items/6e55b91c28cdc8d32cf2
この記事や、信頼性ありそうなサイトだと
https://cpprefjp.github.io/reference/string/basic_string/data.html

この関数を使用するユーザーは、p + size() (NULL終端) に格納されている値を変更してはならない

ということで、resize()のほうが好ましいです。
例えばreserveしていても、clearしているので中身の空文字列のdata()やc_str()が「スモールバッファ」側のポインタを返す場合が考えられるかもしれません。
そうすると、reserveしていても、size()より後ろを勝手に書き換えると、どうなるかは未保証です。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

resize()に直しておきます。

}

// データサイズを反映する
strText.assign( strText.data(), actualCopied );
Copy link
Contributor

Choose a reason for hiding this comment

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

basic_stringのoperator=ではない自己代入(領域が重なる配列)の動作保証は、怪しいと思います。
検索はしてみたものの、問題ないという資料を発見できず、完全には安全ではないっぽいということまでしか、わかりませんでした。
https://stackoverflow.com/questions/28142011/can-you-assign-a-substring-of-a-stdstring-to-itself
それから上のreserveを修正したら無効になる話ですが、reserveだけの状態でsize()より後ろにアクセスしてはいけないので、actualCopiedがsize以上の場合もおそらく未定義の動作です。

str.resize()→str.data()による書き換え→万が一APIの結果文字列長が短い場合は再度str.resize()で縮める。
とするのがいいんじゃないかと思います。
重箱の隅のような指摘ではありますが、C言語にはmemmoveがわざわざ存在しているくらいなので、気になりました。

他の追加された処理ももちろん同様です。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ここは実際にはコピーは行われずlength)だけが更新されます。

ポインタからポインタに値をコピーする処理で、ポインタが同じかどうかをチェックしないでコピーするコードを書いて静的解析ツールに怒られたことがあります。絶対に大丈夫?って聞かれるとゴニョニョですが、大丈夫なんじゃないかと思います。(VC++の実装は大丈夫でした。

Copy link
Contributor

Choose a reason for hiding this comment

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

assign メソッドではなく resize メソッドの呼び出しに置き換えるのに心理的に抵抗が無ければそうした方が良いのではないかと自分も思います。というかそれに変える事によるデメリットってあるんでしょうか?メリットとしては安心感でしょうか?

ここは実際にはコピーは行われずlength)だけが更新されます。

自分は実装は確認していませんが assign で自己代入で長さを縮める操作をする場合はバッファの指定長の位置に null terminator の書き込みとかも行うんじゃないかと想像してます。

さて、動いているから問題ないだろと言われたら明確な反論は出来ないです…。

@berryzplus
Copy link
Contributor

これって誤検出なのではないか、と思うのですが、実際にバグで、メモリーリークするケースがあるのでしょうか?

std::make_uniqueの仕様とMSVCのnew()の仕様を見た感じでは誤検出っぽいです。
https://cpprefjp.github.io/reference/memory/make_unique.html

  1. std::make_uniqueは仕様的に operator new() を呼ぶ。
  2. MSVC の operator new() は失敗時に std::bad_alloc を投げる。
    ここだけ見ると誤検知に見えます。
  3. operator new() は独自にオーバーロードできる。
    いいか悪いかは別にして、例外を投げないオーバーロードも可能。
    これを考慮すると、一概に誤検出だとは言えない気もします。

個人的には「failedなのはマズいっしょ!」という趣旨と理解してて、
バッチが真っ赤なのに気付いてなかったんで「やっべ!」と思っています。

前後の '"" を取り除くように実装してたのを
パスに含まれる '"' を削除するように修正。
@AppVeyorBot
Copy link

Build sakura 1.0.3193 failed (commit 79424e436b by @sanomari)

Copy link
Contributor

@beru beru left a comment

Choose a reason for hiding this comment

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

883eee4 で確認しましたがビルドに失敗します。

1>CMainToolBar.cpp
1>C:\projects\sakura\sakura_core\window\CMainToolBar.cpp(189,2): error C3861: 'CreateToolBarButtons': identifier not found

最初のエラーメッセージが上記のものですが、CMainToolBar.h ファイルに CreateToolBarButtons メソッドのプロトタイプが存在しないので git のステージングし忘れのような気がします。

手間ですがローカル側でいったん別の場所で pull してビルド出来るかの確認はした方が良いです。

あとこれは強制的ではないですが開発ブランチの名前は master ではない方が良いと思います。

@beru
Copy link
Contributor

beru commented Oct 26, 2020

あくまで個人の意見に過ぎないですが、1つのPRで観点が色々な変更を一挙にやろうとしない方が良いと思います。変更のボリュームが大きい場合はなおさらです。レビューするのが大変というレビューアー側の能力の問題もありますが…。

SonarQubeの静的解析で検出されたバグ が多数ある場合はそれをまず新規に Issue を作成してでも良いので列挙して、複数のPRに分けた方がシンプルに片づけられそうならそうした方が良いかなと思います。

ただまぁ考え方は人によって違うので正解は無い事だと思います。急がば回れにするか、回りくどいやり方はかったるくてやってられるかで一気に済ませるか、人それぞれですね。

@berryzplus
Copy link
Contributor

CodeFactorの警告対応は修正と関係ない箇所で、
かつ、対応入れても警告が消えなかったようなので、
今回は外したほうがいいように思います。

@AppVeyorBot
Copy link

Build sakura 1.0.3194 completed (commit 276fc006c9 by @sanomari)

@sanomari
Copy link
Contributor Author

最初のエラーメッセージが上記のものですが、CMainToolBar.h ファイルに CreateToolBarButtons メソッドのプロトタイプが存在しないので git のステージングし忘れのような気がします。

レビューありがとうございます。
原因はステージング漏れでした。

@sanomari
Copy link
Contributor Author

CodeFactorの警告対応は修正と関係ない箇所で、
かつ、対応入れても警告が消えなかったようなので、
今回は外したほうがいいように思います。

今回は外してしまうことにしました。

std::wstringのsize()が返すインデックス以降をアクセスした場合の動作は保証されない。
reserveだけだとsizeが変更されないのでresizeに変更しておく。
@AppVeyorBot
Copy link

Build sakura 1.0.3195 completed (commit 132c52897b by @sanomari)

@berryzplus
Copy link
Contributor

berryzplus commented Oct 28, 2020

結果を確認したいのでマージしてしまいます・・・・って出来ませんでした。

@sanomari sanomari requested a review from beru October 28, 2020 12:08
@return 成功した場合 true
@return 失敗した場合 false
*/
bool DlgItem_GetText( HWND hDlg, int nIDDlgItem, std::wstring& strText )
Copy link
Contributor

Choose a reason for hiding this comment

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

ヘッダ側の他の関数と同様にインライン関数にしてしまうのが良い気がします。
/LTCG (リンク時のコード生成) があるから不要と言われるかもしれませんが、ヘッダファイルの行数を増やす事で目grepに頼るプログラマの眼神経に負荷を与える事を思い浮かべて大きな自己満足を得る事が出来ます。

Combo_GetText( hwndCombo, &vText[0], nBufferSize );
if (m_strText.compare( &vText[0] ) != 0) {
std::wstring strText;
if( !ApiWrap::DlgItem_GetText( GetHwnd(), IDC_COMBO_TEXT, strText ) || strText != m_strText ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

IDC_COMBO_TEXT の HWND を取る操作を Get と Set で2回繰り返していることが気になります。

Copy link
Contributor

@beru beru left a comment

Choose a reason for hiding this comment

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

ビルドでエラーが起きないで起動して簡単な操作が出来る事は確認しました。
変更箇所が多いので変更箇所それぞれに対応する動作確認は取っていません。

@sanomari
Copy link
Contributor Author

ビルドでエラーが起きないで起動して簡単な操作が出来る事は確認しました。
変更箇所が多いので変更箇所それぞれに対応する動作確認は取っていません。

お手数おかけしました。change requiredを無視するのはよくないと思ってお願いしていました。

@sanomari sanomari merged commit 388a736 into sakura-editor:master Oct 29, 2020
@sanomari
Copy link
Contributor Author

いま数えてみたら残数302でした。

静的解析の結果で、この修正と同じ内容の警告がいくつか残っていることに気づきました。

@berryzplus
Copy link
Contributor

いま335件ですね。

SonarQubeのビルドは4本走っているので、バグの数は日によって異なります。
(Win32/x64、Debug/Releaseの組み合わせで4本です。)

今日の分は x64 - Release のビルドが最後に終わってるから、致命的にダメな警告がちょっと多いってことみたいです。

@beru beru added the refactoring リファクタリング 【ChangeLog除外】 label Mar 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactoring リファクタリング 【ChangeLog除外】
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants