Embarcadero C ++ Builderによって開発されたOpen WinSCPプロジェクトの検証

PVS-StudioおよびWinSP

C / C ++でオープンソースプロジェクトを常にチェックしています。 しかし、ほとんどの場合、これらはVisual Studioで開発されたプロジェクトです。 しかし、どういうわけかEmbarcadero C ++ Builderから注目を奪われました。 修正する必要があり、今日はWinSCPプロジェクトをチェックしました。



Winscp



WinSCPは、Windows用に設計されたSFTPおよびSCPプロトコル用の無料のグラフィカルクライアントです。 GNU GPLで配布されています。 これらのプロトコルをサポートするコンピューターとサーバー間の安全なファイルコピーを提供します。



公式ウェブサイト: http : //winscp.net



プロジェクトをビルドするには、Embarcadero C ++ Builder XE2が必要です。



確認する



検証は、 PVS-Studioアナライザーを使用して実行されました。 現在、PVS-Studioは以下をサポートしています。 さらに、PVS-Studio Standaloneを実行できます。 事前に準備された* .iファイルを確認したり、プロジェクトのビルドプロセスを追跡したり、検証に必要なすべての情報を収集したりできます。 詳細については、「 PVS-Studioがすべてのビルドシステムをサポートするようになりました」をご覧ください。



検証結果



多くのエラーはありませんでしたが、この記事を書いてEmbarcadero RAD Studioユーザーの注意を引くのに十分です。



memset()関数の引数を混同しました



TForm * __fastcall TMessageForm::Create(....) { .... LOGFONT AFont; .... memset(&AFont, sizeof(AFont), 0); .... }
      
      





PVS-Studio警告:V575「memset」関数は「0」要素を処理します。 3番目の引数を調べます。 messagedlg.cpp 786



memset()関数は、3番目の引数で配列のサイズを受け取ります。 シンプルだが不快なタイプミス。 構造は未初期化のままです。



以下のコードには、別の同じタイプミスがあります:messagedlg.cpp 796



存在しないオブジェクトを使用する



 void __fastcall TCustomScpExplorerForm::EditorAutoConfig() { .... else { .... TEditorList EditorList; EditorList = *WinConfiguration->EditorList; EditorList.Insert(0, new TEditorPreferences(EditorData)); WinConfiguration->EditorList = &EditorList; } .... }
      
      





PVS-Studio警告:V506ローカル変数「EditorList」へのポインターは、この変数のスコープ外に保存されます。 そのようなポインターは無効になります。 customscpexplorer.cpp 2633



「EditorList」オブジェクトは、スコープを離れるとすぐに破棄されます。 ただし、プログラムはこのオブジェクトへのポインタを保存してから使用します。 これにより、未定義の動作が発生します。



会話のゴミ箱



 bool __fastcall RecursiveDeleteFile(....) { SHFILEOPSTRUCT Data; memset(&Data, 0, sizeof(Data)); .... Data.pTo = L""; .... }
      
      





PVS-Studio警告:V540メンバー「pTo」は、2つの0文字で終了する文字列を指す必要があります。 common.cpp 1659



MSDNのpToパラメータの説明にある次の行に注意してください。「この文字列はダブルヌルで終了する必要があります。」



ファイルを操作するためのダイアログのエラーにより、ゴミが含まれます。 またはされません。 それはすべて運にかかっています。 しかし、とにかくコードは間違っています。



行を複製



 int CFileZillaApi::Init(....) { .... m_pMainThread->m_hOwnerWnd=m_hOwnerWnd; m_pMainThread->m_hOwnerWnd=m_hOwnerWnd; .... }
      
      





PVS-Studio警告:V519「m_pMainThread-> m_hOwnerWnd」変数には、値が連続して2回割り当てられます。 おそらくこれは間違いです。 行を確認:88、89。filezillaapi.cpp 89



おそらく間違いはありません。 1行だけが余分です。



アイドルチェック



 STDMETHODIMP CShellExtClassFactory::CreateInstance(....) { .... CShellExt* ShellExt = new CShellExt(); if (NULL == ShellExt) { return E_OUTOFMEMORY; } .... }
      
      





PVS-Studio警告:V668メモリが「new」演算子を使用して割り当てられたため、「ShellExt」ポインターをnullに対してテストしても意味がありません。 メモリ割り当てエラーの場合、例外が生成されます。 dragext.cpp 554



「if(NULL == ShellExt)」をチェックしても意味がありません。メモリを割り当てることができない場合、「new」演算子は例外std :: bad_allocをスローするからです。



fprintf()関数を使用する危険な方法



 bool CAsyncSslSocketLayer::CreateSslCertificate(....) { .... char buffer[1001]; int len; while ((len = pBIO_read(bio, buffer, 1000)) > 0) { buffer[len] = 0; fprintf(file, buffer); } .... }
      
      





V618このような方法で「fprintf」関数を呼び出すのは危険です。渡される行にはフォーマット仕様が含まれている可能性があるためです。 安全なコードの例:printf( "%s"、str); asyncsslsocketlayer.cpp 2247



ファイルへの書き込み時に制御指定子がバッファに含まれている場合、結果は予測できません。 安全な方法:

 fprintf(file, "%s", buffer);
      
      





一般に、このエラーは潜在的な脆弱性と見なすことができます



変数「err」に問題があります



 static error_t client_send_propfind_request(....) { .... error_t err = 0; int code = 0; apr_hash_t * props = NULL; const char * target = path_uri_encode(remote_path, pool); char * url_path = apr_pstrdup(pool, target); WEBDAV_ERR(neon_get_props(&props, ras, url_path, NEON_DEPTH_ZERO, starting_props, false, pool)); if (err && (err == WEBDAV_ERR_DAV_REQUEST_FAILED)) .... }
      
      





警告:V560条件式の一部は常にfalseです:(err == 1003)。 webdavfilesystem.cpp 10990



おわりに



Embarcadero RAD Studioを使用しているプログラマーはどこですか? あぁ! 統計が示すように、ほとんどありません。 PVS-Studioコードアナライザーをお試しください!



この記事は英語です。



この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Andrey Karpov。 Embarcadero C ++ Builderで開発されたオープンソースプロジェクトWinSCPのチェック



記事を読んで質問がありますか?
多くの場合、記事には同じ質問が寄せられます。 ここでそれらに対する回答を収集しました: PVS-StudioおよびCppCatバージョン2014に関する記事の読者からの質問への回答 。 リストをご覧ください。




All Articles