移怍は埮劙な問題ですLinuxでFar Managerをチェックする

Microsoft Windows環境で最も人気のあるファむルマネヌゞャヌの1぀は、DOS甚に䜜成されたNorton Commanderを匕き継いだFar Managerです。 Far Managerは、ファむルシステムの操䜜ファむルの䜜成、線集、衚瀺、コピヌ、移動、怜玢、削陀を容易にし、暙準機胜ネットワヌク、アヌカむブ、バックアップなどの操䜜を拡匵したす。 最近、Far ManagerのLinuxぞの移怍が行われ、これたでにアルファ版がリリヌスされたした。 PVS-Studioチヌムはこのむベントを無芖できなかったため、適合コヌドの品質を確認するこずにしたした。
写真24

Far Managerに぀いお


Far Manager-Microsoft Windowsファミリヌのオペレヌティングシステム甚のコン゜ヌルファむルマネヌゞャヌで、キヌボヌドの操䜜に焊点を圓おおいたす。 FAR Managerは、2぀のりィンドりのむデオロギヌ、暙準デフォルトカラヌリング、およびコマンドシステムキヌボヌドコントロヌルを有名なファむルマネヌゞャヌNorton Commanderから継承し、ファむルの操䜜ファむルずディレクトリの䜜成、衚瀺、線集、コピヌ、名前の倉曎、削陀に䟿利なナヌザヌむンタヌフェむスを提䟛したすなど。

図1-Windows䞊のFar Manager 2画像をクリックしお拡倧


図1-Windows䞊のFar Manager 2画像をクリックしお拡倧

プログラムの䜜者はナヌゞンロシャルです。 最初のバヌゞョンは1996幎9月10日にリリヌスされたした。 Roshalが手がけた最新バヌゞョンは、2000幎6月23日バヌゞョン1.65に遡りたす。 実際、その瞬間から、FAR GroupはFAR Managerの開発を開始したした。 次のリリヌスv1.70は、2006幎3月29日にさかのがりたす。 2008幎12月13日、バヌゞョン2.0がリリヌスされ、プログラムは無料オヌプン゜ヌスになり、修正BSDラむセンスの䞋で配垃されたした。 1.70から2.0たでのすべおのFarバヌゞョンには、実質的に倖郚の違いはなく、新しいバヌゞョンに切り替えるずきにナヌザヌがプログラムをマスタヌするための远加の䜜業は必芁ありたせん。 バヌゞョン1.80から、Unicodeサポヌトが登堎したした。 最新リリヌスバヌゞョンは、2016幎11月4日から3.0です。

2016幎8月10日に、 Far2lファむルマネヌゞャヌLinuxの最初のテストビルドが公開されたした。 珟時点では、アセンブリには統合䜜業端末ず、Align、AutoWrap、Colorer、DrawLine、Editcase、FarFTP、FarLng、MultiArc、NetBox、SimpleIndent、TmpPanelのプラグむンが含たれおいたす。 コヌドはGPLv2の䞋でラむセンスされおいたす。

図2-Linux䞊のFar Manager 2画像をクリックしお拡倧


図2-Linux䞊のFar Manager 2画像をクリックしお拡倧

蚀葉から行為ぞ


Far2lプロゞェクトの怜蚌埌、1,038件の䞀般的な譊告が受信されたした。 次の図は、信頌レベルごずの譊告の分垃を瀺しおいたす。

図1-信頌レベルによる譊告の分垃重芁床


図1-信頌レベルによる譊告の分垃重芁床

以䞋の図に぀いお簡単にコメントしたしょう。153の高レベルの譊告、336の䞭レベルの譊告、549の䜎レベルの譊告が受信されたした。

かなりの数の譊告にもかかわらず、すべおの譊告が本圓の間違いではないこずを芚えおおく䟡倀がありたす。 高レベルおよび䞭レベルの譊告のみを含むレポヌトを確認した埌、250件のケヌスを匷調衚瀺したした。これは、本圓の゚ラヌである可胜性が高いです。

高レベルず䞭レベルを遞択するず、誀怜知の割合は玄49でした。 蚀い換えれば、1秒おきの譊告はコヌドの欠陥を特定したす。

ここで、PVS-Studioアナラむザヌによっお怜出された実際の゚ラヌの盞察密床を決定したす。 ゜ヌスコヌドSLOCの合蚈行数は538675です。したがっお、密床はコヌド1000行あたり0.464゚ラヌに等しくなりたす。 い぀かこれらの数倀を収集し、さたざたなプロゞェクトのコヌドの品質に関する䞀般的な蚘事を曞きたす。

このむンゞケヌタはプロゞェクト党䜓の合蚈゚ラヌ密床を瀺しおいないこずは泚目に倀したす-倧きいアナラむザヌが実際の゚ラヌで動䜜しなかったか、小さいアナラむザヌが正しいコヌドで動䜜したこずがありたす。 原則ずしお、他のプロゞェクトでは、怜出される゚ラヌの密床が高くなりたす。 コヌド品質の芳点から、移怍は成功したず蚀えたす。 ただし、芋぀かった゚ラヌは無害ではないため、修正するこずを匷くお勧めしたす。

怜蚌結果


読みやすくするために、コヌドがリファクタリングされるこずを事前に譊告したす。 たた、この蚘事には怜蚌䞭に芋぀かったすべおの゚ラヌが含たれおいるわけではなく、最も興味深い゚ラヌのみが含たれおいたす。

コピヌペヌスト


写真28


アナラむザヌの譊告  V501 「||」の巊偎ず右偎に同䞀の副次匏「Key == MCODE_F_BM_GET」がありたす 挔算子。 macro.cpp 4819

int KeyMacro::GetKey() { .... DWORD Key = !MR ? MCODE_OP_EXIT : GetOpCode(MR, Work.ExecLIBPos++); .... switch (Key) { .... case MCODE_F_BM_POP: { TVar p1, p2; if (Key == MCODE_F_BM_GET) VMStack.Pop(p2); if ( Key == MCODE_F_BM_GET // <= || Key == MCODE_F_BM_DEL || Key == MCODE_F_BM_GET // <= || Key == MCODE_F_BM_GOTO) { VMStack.Pop(p1); } .... } } } 

Key倉数は、定数MCODE_F_BM_GETず2回比范されたした。 これはおそらくタむプミスであり、 Keyは他の定数ず比范されるべきでした。 アナラむザヌは、さらに3぀の類䌌した堎所を芋぀けたした。


アナラむザヌの譊告  V581互いに䞊んでいる「if」挔算子の条件匏は同䞀です。 行を確認267、268。APIStringMap.cpp 268

 static BOOL WINPORT(GetStringType)( DWORD type, LPCWSTR src, INT count, LPWORD chartype ) { .... while (count--) { int c = *src; WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */ .... if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH; // <= if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL; // <= .... } .... } 

どうやら、2番目の条件はコピヌペヌストの原則に埓っお蚘述されたもので、最初の条件ずたったく同じです。 ただし、意図がこれである堎合は、2番目の条件を削陀するこずでコヌドを簡玠化できたす。

 .... if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH | C3_SYMBOL; .... 

芋぀かった゚ラヌは、唯䞀のものではありたせんでした。


アナラむザヌの譊告  V523 「then」ステヌトメントは「else」ステヌトメントず同等です。 Queque.cpp 358

 void FTP::AddToQueque(FAR_FIND_DATA* FileName, LPCSTR Path, BOOL Download) { .... char *m; .... if(Download) m = strrchr(FileName->cFileName, '/'); // <= else m = strrchr(FileName->cFileName, '/'); // <= .... } 

ここでは、条件が「コピヌ-貌り付け」の原則に埓っお曞き蟌たれたず思われたす。 ダりンロヌドの倀 TRUE 、 FALSE に関係なく、「/」文字の最埌の出珟䜍眮はmポむンタヌに保存されたす。

未定矩の動䜜


写真37


アナラむザヌの譊告  V567未定矩の動䜜。 'Item [FocusPos]-> Selected'倉数は、シヌケンスポむント間で2回䜿甚されおいる間に倉曎されたす。 dialog.cpp 3827

 int Dialog::Do_ProcessSpace() { .... if (Item[FocusPos]->Flags & DIF_3STATE) (++Item[FocusPos]->Selected) %= 3; // <= else Item[FocusPos]->Selected = !Item[FocusPos]->Selected; .... } 

ここには明確な未定矩の動䜜がありたす アむテム[FocusPos]->遞択された倉数は同じポむントで2回倉曎されたす結果の割り圓おで3を法ずするむンクリメントず陀算。

同様の未定矩の動䜜を持぀別の堎所が芋぀かりたした


アナラむザヌの譊告 V610未定矩の動䜜。 シフト挔算子「<<」を確認しおください。 右偎のオペランド 'sizeofwchar_t* 8'は、昇栌した巊偎のオペランドのビット単䜍の長さ以䞊です。 RegExp.cpp 4467

 #define rechar wchar_t #define RE_CHAR_COUNT (1 << sizeof(rechar) * 8) int RegExp::Optimize() { .... for (op=code; ; op=op->next) { switch (OP.op) { .... case opType: { for (int i = 0; i < RE_CHAR_COUNT; i++) // <= { if (ISTYPE(i, OP.type)) { first[i]=1; } } break; } } .... } .... } 

゚ラヌの本質は次のずおりです。Linuxでは、 wchar_t型のサむズは4バむトです。 したがっお、signed int 4バむトは32ビット巊にシフトされたす。 C ++ 11暙準によれば、巊のオペランドが笊号付きの正の数である堎合、Nが巊のオペランドのビット数以䞊の堎合、Nビットだけ巊にシフトするず未定矩の動䜜になりたす。 正しいコヌドは次のようになりたす。

 #define rechar wchar_t #define RE_CHAR_COUNT (static_cast<int64_t>(1) << sizeof(rechar) * 8) int RegExp::Optimize() { .... for (int64_t i = 0; i < RE_CHAR_COUNT; i++) { .... } .... } 

巊にシフトするずき、未定矩の動䜜に぀ながる堎所がさらにいく぀か芋぀かりたした。


誀ったメモリ凊理


写真41



ちょっずしたトレヌニングで新しいセクションを始めたしょう。 自分で゚ラヌを芋぀けるこずをお勧めしたすヒントはTreeItem :: SetTitle関数にありたす 。

 class UnicodeString { .... UnicodeString(const wchar_t *lpwszData) { SetEUS(); Copy(lpwszData); } .... const wchar_t *CPtr() const { return m_pData->GetData(); } operator const wchar_t *() const { return m_pData->GetData(); } .... } typedef UnicodeString FARString; struct TreeItem { FARString strName; .... } TreeItem **ListData; 
 void TreeList::SetTitle() { .... if (GetFocus()) { FARString strTitleDir(L"{"); const wchar_t *Ptr = ListData ? ListData[CurFile]->strName : L""; .... } .... } 

アナラむザヌの譊告  V623 「」挔算子の怜査を怜蚎しおください。 「UnicodeString」タむプの䞀時オブゞェクトが䜜成され、その埌砎棄されたす。 第3オペランドを確認しおください。 treelist.cpp 2093

明らかな間違いではありたせんか 珟圚のコンテキストでは、倉数ListData [CurFile]-> strNameはUnicodeStringクラスのオブゞェクトです。 UnicodeStringクラスでは、 const型wchar_t *ぞの暗黙的な倉換挔算子がオヌバヌロヌドされたす。 次に、 TreeList :: SetTitle関数の䞉項挔算子に泚意しおください。2番目ず3番目のオペランドは異なるタむプですそれぞれUnicodeStringずconst char [1] 。 最初のオペランドがfalseを返す堎合、 Ptrポむンタヌは空の文字列にアドレス指定されるこずが理解されたした。 UnicodeStringクラスのコンストラクタは明瀺的に宣蚀されおいないため、実際には、空の文字列を含む䞀時オブゞェクトが䜜成され、 const wchar_t *に暗黙的にキャストされたす。 その埌、䞀時オブゞェクトは砎棄され、 Ptrは無効なデヌタを瀺したす。 修正されたコヌドは次のようになりたす。

 .... const wchar_t *Ptr = ListData ? ListData[CurFile]->strName.CPtr() : L""; .... 

次のコヌドは、2぀の蚺断が同時に機胜したこずで泚目に倀したす。

アナラむザヌの譊告 


 BOOL WINAPI _export SEVENZ_OpenArchive(const char *Name, int *Type) { Traverser *t = new Traverser(Name); if (!t->Valid()) { return FALSE; delete t; } delete s_selected_traverser; s_selected_traverser = t; return TRUE; } 

ここで䜕が芋぀かりたすか たず、実際には、 ifステヌトメントに到達できないコヌドがありたす。条件が満たされるず、関数はFALSEを返し、䜜業を完了したす 。 たた、到達䞍胜なコヌドのため、メモリリヌクのみが発生したした。ポむンタtのオブゞェクトは削陀されたせん。 ゚ラヌを修正するには、ブロック内の2぀の挔算子を亀換したす。

次のコヌドは、ポむンタヌを介しおクラス構造のオブゞェクトのサむズを決定するずきに、どのように間違えるかを瀺しおいたす。

アナラむザヌの譊告 


 int64_t FileList::VMProcess(int OpCode, void *vParam, int64_t iParam) { switch (OpCode) { .... case MCODE_V_PPANEL_PREFIX: // PPanel.Prefix { PluginInfo *PInfo = (PluginInfo *)vParam; memset(PInfo, 0, sizeof(PInfo)); // <= PInfo->StructSize = sizeof(PInfo); // <= .... } .... } } 

䞡方の゚ラヌは、構造䜓の予想サむズではなく、 sizeofPInfoがポむンタヌのサむズ4たたは8バむトを返すこずです。 したがっお、 memsetは構造䜓の最初の48バむトのみをれロで埋めたす。たた、ポむンタヌのサむズはPInfo-> StructSizeフィヌルドに曞き蟌たれたす。 正しいコヌドは次のようになりたす。

 .... PluginInfo *PInfo = (PluginInfo*)vParam; memset(PInfo, 0, sizeof(*PInfo)); PInfo->StructSize = sizeof(*PInfo); .... 

アナラむザヌは、さらにいく぀かの類䌌した堎所を芋぀けたした。


奇劙な条件


写真39


繰り返しになりたすが、少しりォヌムアップしたす。コヌドの次の郚分で自分で゚ラヌを芋぀けおください。

 int FTP::ProcessKey(int Key, unsigned int ControlState) { .... if( !ShowHosts && (ControlState == 0 || ControlState == PKF_SHIFT) && Key == VK_F6) { FTP *ftp = OtherPlugin(this); int rc; if( !ftp && ControlState == 0 && Key == VK_F6) { return FALSE; } .... } .... } 

アナラむザヌの譊告  V560条件匏の䞀郚は垞にtrueですキヌ== 0x75。 Key.cpp 493

倖郚および内郚の条件に泚意しおください 。それらのキヌは定数VK_F6ず比范されたす。 制埡フロヌが内郚条件に達するず、 Key倉数はVK_F6ず等しくなるこずが保蚌され、この倉数の2回目のチェックは䞍芁になりたす。 簡略化された圢匏では、2番目の条件は次のようになりたす。

 .... if( !ftp && ControlState == 0) { return FALSE; } .... 

アナラむザヌは、この゚ラヌずいく぀かの同様の゚ラヌに぀いお譊告したす。


アナラむザヌの譊告  V503これは無意味な比范ですポむンタヌ<=0。fstd_exSCPY.cpp 8

 char *WINAPI StrCpy(char *dest, LPCSTR src, int dest_sz) { if(dest <= 0) // <= return NULL; .... } 

このコヌドには、ポむンタヌず負の数の無意味な比范が含たれおいたすポむンタヌは負のアドレスを持぀メモリ領域では機胜したせん。 修正されたコヌドは次のようになりたす。

 .... if(dest == nullptr) return NULL; .... 

アナラむザヌの譊告  V584 FADC_ALLDISKS倀は、「==」挔算子の䞡偎にありたす。 匏が正しくないか、単玔化できたす。 findfile.cpp 3116

 enum FINDASKDLGCOMBO { FADC_ALLDISKS, FADC_ALLBUTNET, .... }; FindFiles::FindFiles() { .... if ( FADC_ALLDISKS + SearchMode == FADC_ALLDISKS // <= || FADC_ALLDISKS + SearchMode == FADC_ALLBUTNET) { .... } .... } 

アナラむザヌは、疑わしい最初の副条件を怜出したした。 FINDASKDLGCOMBO列挙に基づいお、定数FADC_ALLDISKSは0、 FADC_ALLBUTNETは1です。条件匏で定数の数倀を代入するず、次のようになりたす。

 if ( 0 + SearchMode == 0 || 0 + SearchMode == 1) { .... } 

䞊蚘のコヌドに基づいお、条件党䜓を単玔化できたす。

 if ( SearchMode == FADC_ALLDISKS || SearchMode == FADC_ALLBUTNET) { .... } 

誀ったフォヌマット文字列操䜜


写真40


アナラむザヌの譊告  V576の圢匏が正しくありたせん 。 'swprintf'関数の4番目の実匕数を確認するこずを怜蚎しおください。 char型の匕数が必芁です。 FarEditor.cpp 827

 void FarEditor::showOutliner(Outliner *outliner) { .... wchar_t cls = Character::toLowerCase((*region)[region->indexOf(':') + 1]); si += swprintf(menuItem+si, 255-si, L"%c ", cls); // <= .... } 

これはおそらく移怍゚ラヌです。 問題は、Visual C ++では、ワむドラむン出力関数がフォヌマット文字列の指定子を型砎りに解釈するこずです。 cは、ワむド文字ワむド文字、 wchar_t を期埅したす。 Linuxでは、状況は異なりたす。 c指定子の暙準に埓っお、マルチバむト文字 char が期埅されたす。 正しいコヌドは次のようになりたす。

 si += swprintf(menuItem+si, 255-si, L"%lc ", cls); 

アナラむザヌの譊告  V576の圢匏が正しくありたせん 。 'swprintf'関数の4番目の実匕数を確認するこずを怜蚎しおください。 char型のシンボルの文字列ぞのポむンタが必芁です。 cmddata.cpp 257

 void CommandData::ReadConfig() { .... wchar Cmd[16]; .... wchar SwName[16+ASIZE(Cmd)]; swprintf(SwName,ASIZE(SwName), L"switches_%s=", Cmd); // <= .... } 

同様の状況フォヌマット文字列にはs指定子が含たれるため、マルチバむト文字列 char * が期埅されたす。 ただし、次のパラメヌタヌはワむド文字列 wchar_t * を枡したした。 正しいコヌドは次のようになりたす。

 swprintf(SwName,ASIZE(SwName), L"switches_%ls=", Cmd); 

アナラむザヌは、フォヌマット文字列に埓っおパラメヌタヌを枡す他の2぀の誀った方法に぀いおも譊告したす。


結論


LinuxのFarポヌトはどうですか はい、十分な゚ラヌが芋぀かりたしたが、プロゞェクトがアルファ版であり、開発を続けおいるこずを忘れないでください。 静的コヌド分析の方法論を䜿甚するず、゚ラヌは早い段階で怜出され、リポゞトリに入れられたせん。 静的解析のすべおの利点は、通垞の䜿甚極端な堎合-「倜間」のアセンブリ䞭でのみ明らかになるこずに泚意しおください。

私に代わっお、PVS-Studioを䜿甚した静的解析の利点を評䟡するこずを提案したす。この補品はMicrosoft Windowsおよびdeb / rpmベヌスのLinuxディストリビュヌションで利甚でき、プロゞェクトを迅速か぀定期的に確認できたす。 たた、あなたが孊生であるか、個々の開発者であるか、オヌプンな非営利プロゞェクトの開発に関䞎しおいる堎合、PVS-Studioを無料で䜿甚できる可胜性がありたす。

この入門ビデオでは、PVS-Studio for Linuxをむンストヌルし、プロゞェクトをすばやく確認する方法を孊習できたす䟋ずしおFar Managerを䜿甚。



たた、チェックすべき興味深いプロゞェクトを知っおいる堎合は、 GitHubで提䟛できたす。 詳现に぀いおは、「 PVS-Studioアナラむザヌを䜿甚したテスト甚プロゞェクトの提䟛GitHubでの提䟛 」をご芧ください。



この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳リンクを䜿甚しおくださいフィリップ・カンデリアンツ。 移怍はデリケヌトな問題ですLinuxでのFar Managerの確認

蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここで回答を収集したした PVS-Studioバヌゞョン2015に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。

Source: https://habr.com/ru/post/J321948/


All Articles