-
Notifications
You must be signed in to change notification settings - Fork 176
Grep結果のタグジャンプの一部リファクタリングと不具合の修正 #1607
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
Grep結果のタグジャンプの一部リファクタリングと不具合の修正 #1607
Conversation
|
✅ Build sakura 1.0.3607 completed (commit c604f923e0 by @usagisita) |
|
修正範囲外なのでレビュー対象外とするのが妥当と思います。 CodeSmellsのほうも、対策が難しい指摘ばかりです。
対策できるとしても if 文のやつだけですね・・・。 |
berryzplus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR趣旨は了解です。
「if等のネストレベルが3を超える」の警告が、今回作り込んだもののようなので、そこの対策がいるんじゃないかと思います。
サクラエディタには AddLastYen みたいな関数が多数定義されていて、このPRの修正で std::wstring バージョンを追加している感じなんですけど、個人的に「あんまりよくない」と思っています。
あんまりよくないと思う理由は2点あります。
LastYenという名前が変。
LastYenは「パス文字列の末尾にあるパス区切り記号」を意味します。
「Windowsにおけるパス区切り記号」はback slash(0x5C)で、字形は ⧵ です。
歴史的な理由により、日本語Windowsではこの文字が ¥ に見えます。
パス文字列の見た目から「最後の円マーク」で LastYen なんだと思いますが、実際の処理対象は「末尾のパス区切り文字」なので、ちょっと違います。
AddLastBackslash(英語向け) とか AddLastWon(韓国語向け)とか作るんかい!になります。- 処理対象が「ただの文字列」じゃないような気がします。
C言語のwchar_t*は生のデータなので属性を持たせられませんが、C++で処理を組むなら「文字列」と「パス文字列」を区別できるような気がします。この系統の自作関数を用意することは否定しませんけれども、C++のシステムライブラリを活用したほうが良いように思います。
|
LastYenは元の関数からの命名ですね。 |
|
すみません、ややこしくなっていますが、修正依頼は以下の1点のみです。
AddLastYenの件は感想なので、このままで良いです。 |
|
オーキードーキー |
|
すみません、再び実行テストをしてみたところ、タブジャンプができない状態になっているオプションのパターンがあるようです。 |
|
✅ Build sakura 1.0.3611 completed (commit 26f62acf2d by @usagisita) |
|
✅ Build sakura 1.0.3613 completed (commit d608e02bab by @usagisita) |
berryzplus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
判断できずに放置してしまっていました。
対応したかった問題の対処はできているように思うので結論出しておきます。
なお基本的に英語圏出身の人達同士で作ってきたソフトじゃないし、ピジン英語での命名でも No hay problema ではないかと。 |
| GetLineColumn( &pLine[2 + nPathLen], &nJumpToLine, &nJumpToColumn ); | ||
| break; | ||
| }else if( !GetQuoteFilePath( &pLine[2], szFile, _countof(szFile) ) ){ | ||
| }else if (strFile = GetQuoteFilePath(&pLine[2], MAX_TAG_PATH); strFile.empty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if 文の中に変数への代入とその変数を使った条件式をまとめて書くと少し読みづらいと感じるのは自分が古いからかもしれません。きっと strFile 変数に代入するのは後でその値を使用するからだと思います。この関数は元々長くて読み取りづらいのでブラウザで見る差分表示で全体像を把握するのは難しそうです。。
思いついた方法として GetQuiteFilePath 関数に std::wstring& 型の引数を追加して戻り値の型も std::wstring& 型に変更する事で
}else if (GetQuoteFilePath(&pLine[2], MAX_TAG_PATH, strFile).empty()) {のようにセミコロンで区切らずに書けると思います。更に GetQuiteFilePath を関数ではなくラムダ式にすれば引数で strFile を渡さずに済みます。ただそういう風な記述もそれはそれでトリッキーな感じがするので、その書き方に変えて本当に可読性が向上するのかというと、あくまで好みの問題かもしれません。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ごもっともだと思うので、どうしようか考え中です。
記述としては、元のコードに近いものに戻るということですね。
戻り値もstd::wstring&からさらに戻して、empty()かどうかをboolで返したほうが、記述そのものはシンプルになりそうですが、どうするかは考えようです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetQuoteFilePath 関数の最後の引数の size にはすべての呼び出し箇所で MAX_TAG_PATH しか渡していないのもなんか気になりますね。まぁでも構造化を怠ってずるずる実装してきた果てに引数の数が数十になっている酷い関数というわけでは全然無いし、細かい事は気にしない方が良いですね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else if で変数宣言してるのが違和感の正体かな?と思いました。
直前のifのtrueパートはbreakで抜けてそうなので、else ifにしてるのが違和感の原因なのではないかと思います。
・Grep結果のタグジャンプで「◆」と「■」がある形式でバッファオーバーフローが発生する不具合の修正
3ea9e8b to
feaa552
Compare
|
SonarCloud Quality Gate failed. |
|
✅ Build sakura 1.0.3641 completed (commit 98ac1a3fe5 by @usagisita) |
指摘点を対応してみました。 if (std::wstring strPath; GetQuoteFilePath(&pLine[2], strPath, MAX_TAG_PATH)) {こういう風に書くこともできますが、どうしましょうか…… |
これに関しては究極的には好きな方で良いと思います。不具合ではないのでコメントはしますが強制はしません。 Code Smell を確認しました。 https://sonarcloud.io/organizations/sakura-editor/rules?open=cpp%3AS6004&rule_key=cpp%3AS6004 C++17以降ではスコープを狭められるから使った方が良いよ、っていう文章でした。最初のコード例では なお、可読性が落ちるけど新しい言語仕様で入った記法を使わないと駄目だよと仮に強制されたら自分はそれは理不尽だと思います。こういうコーディングスタイルに関しては自分は自由に任せたら良いと思いますね。実際に不具合があるかないかとかに比べたら些細な事だと思いますし、個人個人で書き方の癖や好みって違うと思うので。 |
|
#1607 (comment) に関して。
「正しい」対策はおそらく、以下のようなコードです。 if ( auto strPath = GetQuoteFilePath(&pLine[2], MAX_TAG_PATH); strPath.length() > 0 ) {・・・要するに、GetQuoteFilePathのシグニチャを変えにゃならんです。 GetQuoteFilePathのシグニチャを再定義するのは、明らかにめんどくさい作業なので「めんどくさいので対応しません」と言っても普通に「そうだね。」ってなると思います。 というか、話の流れがわからないです。 Get Quote FilePath って関数名も意味不明だと思います。
処理内容が「囲う」ならばGetなしでQuoteFilePathだし、 いや、やり取りちゃんと読めよ!wって話かも知れませんけれども。 |
|
もしかして、TryQuoteFilePathなんですかね? |
#1607 (comment) で if 文の中に変数への代入とその変数を使った条件式をまとめて書くとわかりづらいといったコメントを自分がして、そうしないように usagisita さんが変更したらSonarCloud の Code Smell が出たという流れだと思います。#1607 (comment) こんな事を書くと白い目で見られそうですがPRのレビューでSonarCloudの指摘事項に対応するかどうかを考えるコストが無駄な気もします。自分の感覚ではSonarCloudよりusagisitaさんの方が不具合検知能力が高いので、捕獲後に科学者達が脳を解析して人類の未来に役立
同じ事は自分も思いましたが、このPRで追加された関数じゃないし変更する必要は無いと思いますね。もちろん変更するのがいけないというわけではないですが。 66ee57f#diff-040dfa00369971e38c307d19fe43f4a18bd8cf7dd258d687eb805fcf731b7baaR42 で追加されてますね。 |
SonarCloudの指摘は「スコープを狭められる変数宣言は狭いほうに寄せたほうがいいぜ?」な意図だと思います。読みづらい場合は、改行を入れたり変数名や関数名を短くするなどして対応すればよいと思います。 この手の検出を防ぐには関数先頭に宣言をまとめたらよいのではないかと思います。その場合、現代人の感覚に反するおかしなコードになるので、人間による恣意的なレビューで指摘を浴びることになると考えられますが 😃
白い目w usagisitaさんやberuさんの嗅覚が鋭いことに疑いはありませんけど、それとコレとは別です。 機械による検出は、指摘基準がブレません。 楽するためのものなので、一律に対応してゆけばよいだけです。
結局、このPRの残件はなんでしょう?
この2点がクリアできていたら残件なしとしてよい認識です。 |
beru
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
問題無いと思います。
PRの説明のテスト内容に書かれているような方法でGrep結果を加工したテキストを用意して動作確認しました。
修正前は存在しないファイルを新規エディタで開く変な挙動ですが、このPRではタグジャンプ出来なくなる事を確認しました。
確認に使用したテキスト
□検索条件 "_IsFileUpdatedByOther"
検索対象 *.h
フォルダ D:\projects\sakura\sakura_core
除外ファイル *.msi;*.exe;*.obj;*.pdb;*.ilk;*.res;*.pch;*.iobj;*.ipdb
除外フォルダ .git;.svn;.vs
(サブフォルダも検索)
(英大文字小文字を区別しない)
(文字コードセットの自動判別)
(一致した行を出力)
■"D:\projects\sakura\sakura_core"
◆"CAutoReloadAgent.h" [UTF-8]
・( 58,7 ): bool _IsFileUpdatedByOther(FILETIME* pNewFileTime) const;
◆"CAutoReloadAgent_0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456012345678901234567890123456789.h"
・( 58,7 ): bool _IsFileUpdatedByOther(FILETIME* pNewFileTime) const;
色々な組み合わせのパターンでは動作確認はしていません。面倒くさくて…。
SonarCloudの指摘内容は自分もそういう内容だと読みました。ただし if 文の中に変数宣言や代入を書いてスコープを狭められる事に利点はあるにしても可読性が落ちる事は無いですか?可読性が落ちる事をSonarCloudは判断材料に入れてないのかもしれませんが…。 feaa552 はこのPRのusagisita さんの commit ですが、if 文の中で
うーん、具体的にどのように書けば先ほどの記述が読みやすくなるんでしょうか?どのように途中で改行を入れたり変数名や関数名を短くするなどすれば読みやすくなるんでしょうか?? とはいえ、if 文の中で変数宣言や変数への代入とその変数を使って条件判定をする記述があっても可読性は落ちない!と主張する人も世の中にはいるかもしれません。またコードゴルフや4k introをやっている人達からしたら高級言語の記述で揉めるのが意味不明かもしれません。
PascalやC90的な書き方は嫌ですが、究極的には問題ではないかもしれません。
今はまだ人間みたいな判断は出来ないですよね。 |
|
何か残件ありますか? そろそろ放置で2週間経過します... |
|
放置していてすみません。 色々不満点は残っていますが、致命的な残件そのものはないという認識です。 これってPR作成者が自分で判断して、マージしなければならないんですかね? |
PR作成者が自分でマージしてもOKだし、他のマージ出来る人がマージしてもOKです。
複雑なコードは至る所にあって対処が難しいですね。力技なのか秘伝のタレなのかスパゲッティなのか、まぁ明日の献立を考えるのは止めておきます。 |
PR の目的
細工されたり
\\?\形式の長いパスのGrep結果のタグジャンプで「◆■」がある形式でバッファオーバーフローが発生する不具合の修正です。同一箇所として、下記の「◎◆■」のタグで、存在しないパスのタグがあると、それに無条件でジャンプしようとする不具合を修正します。
カテゴリ
PR の背景
strcat/strcpy、固定長バッファの一連の点検作業の一部です。
他にも、バグっぽい挙動をする部分が見られましたが、今回はスルーしました。
さらに不具合など修正リファクタリングしたコードも手元にはありますが、単体テストがないため、修正確認が非常に面倒です。
とりあえず、第1弾としたいです。
本格的にリファクタリングしたいなら、どうぞ、お願いします。
PR のメリット
バグが修正されます。
細工されたGrep結果のタブジャンプでクラッシュしにくくなります。
PR のデメリット (トレードオフとかあれば)
例のごとく、自動テストがないため、新しい不具合が出る可能性があります。
関数の中身が煩雑で、処理を追うのも難しいため、目で検証するのも大変だと思われます。
仕様・動作説明
テストの通りです。
ファイル名の固定配列を
std::wstringで置き換えました。関連するサブ関数を
wstring仕様に差し替えました。GetQuoteFilePathではバッファ長指定が_countof()なのでszPath、szFileは最大MAX_PATHまでコピーを切り出してきます。AddLastYenFromDirectoryPath()のszPathがMAX_PATH限界だと1文字はみ出します。wcscatはszPathがMAX_PATH、szFileも制限はMAX_PATHなので長さを確認しないなら倍は必要です。sakura/sakura_core/cmd/CViewCommander_TagJump.cpp
Lines 274 to 276 in 7e65eab
下記も1024文字と長いですが、条件に一致すればバッファオーバーフローします。
またパス文字列の中身をチェックする前に
szJumpToFileにコピーしてしまっているため、IsFileExists2()がfalseになるルートでは本来、タグジャンプ不可のはずが、不正パスでもタグジャンプ扱いになっていました。sakura/sakura_core/cmd/CViewCommander_TagJump.cpp
Lines 288 to 291 in 7e65eab
元のコードから、カーソル行の解析では
if (!GetQuoteFilePath())と否定ですが、後半の上の行にさかのぼる処理のほうはif (GetQuoteFilePath())と肯定になっていますので、注意してください。PR の影響範囲
Grep結果からのタグジャンプに関する範囲のみです。
テスト内容
テスト1
手順
「ファイル毎」「フォルダ毎」でGrepした結果のテキストを細工します。
サクラエディタに上記を貼り付け「◆」か「・」の行にカーソルを置き「F12」を押します。
→フォルダ+ファイルがstrcatで連結されてバッファオーバーフローしていました。
デバッグビルドで実行してジャンプさせるとスタックのエラーかフリーズすることがあります。
修正後は、タグジャンプできなくなります。
(パスのファイルは実在している必要はありません)
テスト2
手順
「ファイル毎」「フォルダ毎」「ベースフォルダ」でGrepした結果のテキストを細工します。
サクラエディタに上記を貼り付け「◆」か「・」の行にカーソルを置き「F12」を押します。
→存在しないファイルとして新規で開かれてしまうバグがありました。
修正するか非常に迷いましたが、同一の箇所であり、ファイル名、フォルダ名に*や?など任意の文字があってもタブジャンプしてしまうため、これはPRに含めました。
Grep結果には、オプションが「ノーマル/ファイル毎」「フォルダ毎」「ベースフォルダ」と全部で8パターンあります。
関連 issue, PR
参考資料