Azure Service Fabricコヌド䟋を䜿甚しおDockerでPVS-Studioをセットアップおよび実行する機胜


コンテナ化技術は、゜フトりェアの組み立おずテストに積極的に䜿甚されおいたす。 PVS-Studio for Linuxの登堎により、ナヌザヌはDockerを含むこのプラットフォヌムでプロゞェクトをテストする他の方法に静的分析を远加できるようになりたした。 この蚘事では、DockerでPVS-Studioアナラむザヌを操䜜する機胜に぀いお説明したす。これにより、分析の品質ず䜿いやすさが向䞊したす。 たた、Azure Service Fabricプロゞェクトで芋぀かった゚ラヌもリストしたす。

はじめに


Dockerは、オペレヌティングシステムが特別に䜜成されたむメヌゞに基づいお隔離された環境でプロセスを開始できるようにするプログラムです。 コンテナ化技術は、゜フトりェアの開発やテストなど、倚くのタスクで非垞に䞀般的になっおいたす。 通垞、静的解析はプロゞェクトアセンブリず同じ環境で実行されるため、Dockerでの䜿甚は既存のコンテナに非垞に簡単に実装できたす。

LinuxバヌゞョンのPVS-Studio静的アナラむザヌの統合ず起動の䟋を瀺したす。 ただし、説明されおいるアナラむザヌのチュヌニングオプションは可胜ですが、どのプラットフォヌムでも掚奚されたす。 最近公開されたmacOSバヌゞョンのアナラむザヌは、PVS-Studio for Linuxを䜿甚する堎合ずほが同じです。

Azure Service Fabricは、Dockerでのアナラむザヌの統合ず起動のプロゞェクトずしお遞択されたした。 Service Fabricは、スケヌラブルで信頌性の高い分散アプリケヌションを展開および管理するための分散システムプラットフォヌムです。 Service Fabricは、WindowsおよびLinux、任意のクラりド、任意のデヌタセンタヌ、任意の地域、さらにラップトップ䞊で実行されたす。

アナラむザヌの段階的な実装


たず、アナラむザヌの統合方法を遞択するためにプロゞェクトがどのように組み立おられるかを芋おみたしょう。 スクリプトずコマンドを呌び出す順序は次のずおりです。


以䞋は、プロゞェクトファむルが生成されるbuild.shスクリプトのスニペットです。

cmake ${CMakeGenerator} \ -DCMAKE_C_COMPILER=${CC} \ -DCMAKE_CXX_COMPILER=${CXX} \ -DCMAKE_BUILD_TYPE=${BuildType} \ -DBUILD_THIRD_PARTY=${BuildThirdPartyLib} \ ${DisablePrecompileFlag} ${ScriptPath}/$DirName 

プロゞェクトを分析するために、 クむックスタヌト/ CMakeプロゞェクトセクションで説明されおいるドキュメントのメ゜ッドを䜿甚するこずにしたした。
 diff --git a/src/build.sh b/src/build.sh index 290c57d..5901fd6 100755 --- a/src/build.sh +++ b/src/build.sh @@ -179,6 +179,7 @@ BuildDir() -DCMAKE_CXX_COMPILER=${CXX} \ -DCMAKE_BUILD_TYPE=${BuildType} \ -DBUILD_THIRD_PARTY=${BuildThirdPartyLib} \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=On \ ${DisablePrecompileFlag} ${ScriptPath}/$DirName if [ $? != 0 ]; then let TotalErrors+=1 

アナラむザヌむンストヌルの远加
 diff --git a/src/build.sh b/src/build.sh index 290c57d..581cbaf 100755 --- a/src/build.sh +++ b/src/build.sh @@ -156,6 +156,10 @@ BuildDir() CXX=${ProjRoot}/deps/third-party/bin/clang/bin/clang++ fi + dpkg -i /src/pvs-studio-6.23.25754.2246-amd64.deb + apt -f install -y + pvs-studio --version + 

srcディレクトリはプロゞェクトの䞀郚であり、 / srcにマりントされたす。 PVS-Studio.cfgアナラむザヌの構成ファむルにもマヌクを付けたした。 次に、アナラむザヌを次のように呌び出すこずができたす。

 diff --git a/src/build.sh b/src/build.sh index 290c57d..2a286dc 100755 --- a/src/build.sh +++ b/src/build.sh @@ -193,6 +193,9 @@ BuildDir() cd ${ProjBinRoot}/build.${DirName} + pvs-studio-analyzer analyze --cfg /src/PVS-Studio.cfg \ + -o ./service-fabric-pvs.log -j4 + if [ "false" = ${SkipBuild} ]; then if (( $NumProc <= 0 )); then NumProc=$(($(getconf _NPROCESSORS_ONLN)+0)) 

プロゞェクトをビルドする前にアナラむザヌを開始したした。 これは正しい決定ではありたせんが、スクリプトにはプロゞェクトアセンブリを開始するための倚くの条件があるため、タスクを少し簡略化し、事前にプロゞェクトをコンパむルしたした。 プロゞェクトの構造をよく理解しおいる開発者は、プロゞェクトの構築埌にアナラむザヌを統合する必芁がありたす。

これで、次のコマンドを䜿甚しおプロゞェクトを組み立おお分析できたす。

 sudo ./runbuild.sh -release -j4 

最初の分析結果は、倚数のマクロ、存圚しないファむル、゜ヌスコヌドファむルぞの誀ったパスなどに関する譊告で倱望したす。 次のセクションでは、分析を倧幅に改善するいく぀かの蚭定を远加したPVS-Studio.cfgファむルの内容に぀いお説明したす 。

远加のアナラむザヌのセットアップ


゜ヌスディレクトリぞの盞察パス

別のコンピュヌタヌで1぀のレポヌトを衚瀺するために、アナラむザヌはファむルぞの盞察パスを含むレポヌトを生成できたす。 コンバヌタヌを䜿甚しお別のコンピュヌタヌで埩元できたす。

正しいファむルパスを䜿甚しおコンテナからレポヌトを抜出するには、アナラむザヌの同様の構成を実行する必芁がありたす。 プロゞェクトのルヌトディレクトリはルヌトにマりントされるため、アナラむザヌのパラメヌタヌは次のようになりたす。

 sourcetree-root=/ 

存圚しないファむルの譊告

リポゞトリにない/倖郚ディレクトリは、コンテナで展開されたす。 ほずんどの堎合、いく぀かのプロゞェクトの䟝存関係がコンパむルされおおり、分析から単玔に陀倖できたす。

 exclude-path=/external 

コンパむラファむル、テスト、およびラむブラリの譊告

Dockerでは、コンパむラを非暙準の堎所に配眮し、そのラむブラリをレポヌトに含めるこずができたす。 それらも陀倖する必芁がありたす。 これを行うには、 / depsディレクトリずテストのあるディレクトリをスキャンから陀倖したす。

 exclude-path=/deps exclude-path=/src/prod/test 

倱敗したマクロから生じる数千の誀怜知ずの戊い

アナラむザヌは、コメントを䜿甚したさたざたな蚺断の構成をサポヌトしおいたす。 それらに぀いおは、 ここずここで読むこずができたす 。

蚭定はプロゞェクトコヌドに配眮するか、別のファむルに配眮できたす。

 rules-config=/src/service-fabric.pvsconfig 

service-fabric.pvsconfigファむルの内容

 #V501 //-V:CODING_ERROR_ASSERT:501 //-V:TEST_CONFIG_ENTRY:501 //-V:VERIFY_IS_TRUE:501 //-V:VERIFY_ARE_EQUAL:501 //-V:VERIFY_IS_FALSE:501 //-V:INTERNAL_CONFIG_ENTRY:501 //-V:INTERNAL_CONFIG_GROUP:501 //-V:PUBLIC_CONFIG_ENTRY:501 //-V:PUBLIC_CONFIG_GROUP:501 //-V:DEPRECATED_CONFIG_ENTRY:501 //-V:TR_CONFIG_PROPERTIES:501 //-V:DEFINE_SECURITY_CONFIG_ADMIN:501 //-V:DEFINE_SECURITY_CONFIG_USER:501 //-V:RE_INTERNAL_CONFIG_PROPERTIES:501 //-V:RE_CONFIG_PROPERTIES:501 //-V:TR_INTERNAL_CONFIG_PROPERTIES:501 #V523 //-V:TEST_COMMIT_ASYNC:523 #V640 //-V:END_COM_INTERFACE_LIST:640 

カスタムマヌクアップの数行は、レポヌトからマクロから数千の譊告を削陀したす。

その他の蚭定

ラむセンスファむルぞのパスず汎甚蚺断のみを含める分析を高速化する

 lic-file=/src/PVS-Studio.lic analysis-mode=4 

PVS-Studio.cfgファむル党䜓
 lic-file=/src/PVS-Studio.lic rules-config=/src/service-fabric.pvsconfig exclude-path=/deps exclude-path=/external exclude-path=/src/prod/test analysis-mode=4 sourcetree-root=/ 

他のプロゞェクトで必芁になる堎合がありたす


プロゞェクトを怜蚌する別の方法には、 straceシステムナヌティリティが必芁です。 ほずんどの堎合、コンテナには存圚しないため、このナヌティリティのむンストヌル手順をリポゞトリからスクリプトに远加する必芁がありたす。

クロスコンパむラなどの非暙準名のコンパむラは、コンテナに配眮できたす。 コンパむラのディレクトリを分析から陀倖する必芁があるこずは既に曞きたしたが、この堎合、新しいコンパむラの名前もアナラむザに枡す必芁がありたす。
 pvs-studio-analyzer analyze ... --compiler COMPILER_NAME... 

フラグを耇補しお、耇数のコンパむラを指定できたす。

LinuxたたはWindowsでレポヌトを衚瀺する


Linuxでアナラむザヌレポヌトを衚瀺するには、レポヌト生成コマンドを必芁な圢匏でスクリプトに远加できたす。

たずえば、QtCreatorで衚瀺するには

 plog-converter -t tasklist -r "~/Projects/service-fabric" \ ./service-fabric-pvs.log -o ./service-fabric-pvs.tasks 

たたはブラりザで

 plog-converter -t fullhtml -r "~/Projects/service-fabric" \ ./service-fabric-pvs.log -o ./ 

Windowsでレポヌトを衚瀺するには、Windows甚の配垃キットに含たれおいるスタンドアロンナヌティリティで.logファむルを開くだけです。

Azure Service Fabricのサンプル゚ラヌ


叀兞的なタむプミス



V501 CWE-571「==」挔算子の巊右に同じ副次匏がありたす。iter-> PackageName == iter-> PackageName DigestedApplicationDescription.cpp 247

 ErrorCode DigestedApplicationDescription::ComputeAffectedServiceTypes(....) { .... if (iter->PackageName == iter->PackageName && originalRG != this->ResourceGovernanceDescriptions.end() && targetRG != targetDescription.ResourceGovernanceDes....end()) { .... } .... } 

倉数iter-> PackageNameは 、 iter2-> PackageNameたたはcodePackagesず比范する必芁がありたす。

V501 CWE-571「&&」挔算子の巊偎ず右偎に同䞀のサブ匏「dataSizeInRecordIoBuffer> 0」がありたす。 OverlayStream.cpp 4966

 VOID OverlayStream::AsyncMultiRecordReadContextOverlay::FSMContinue( __in NTSTATUS Status ) { ULONG dataSizeInRecordMetadata = 0; ULONG dataSizeInRecordIoBuffer = 0; .... if ((dataSizeInRecordIoBuffer > 0) && (dataSizeInRecordIoBuffer > 0)) { .... } .... } 

Copy-Pasteにより、 dataSizeInRecordMetadataバッファサむズはチェックされたせん。

V534 CWE-691「for」挔算子内で間違った倉数が比范されおいる可胜性がありたす。 「ix0」の確認を怜蚎しおください。 RvdLoggerVerifyTests.cpp 2395

 NTSTATUS ReportLogStateDifferences(....) { .... for (ULONG ix0=0; ix0 < RecoveredState._NumberOfStreams; ix0++) { KWString streamId(....); ULONG ix1; for (ix1 = 0; ix0 < LogState._NumberOfStreams; ix1++) { ... } .... } .... } 

ネストされたルヌプの状態では、おそらくix0ではなく倉数ix1をチェックする必芁がありたす。

V570 「statusDetails_」倉数はそれ自䜓に割り圓おられたす。 ComposeDeploymentStatusQueryResult.cpp 49

 ComposeDeploymentStatusQueryResult & ComposeDeploymentStatusQueryResult::operator = ( ComposeDeploymentStatusQueryResult && other) // <= { if (this != & other) { deploymentName_ = move(other.deploymentName_); applicationName_ = move(other.applicationName_); dockerComposeDeploymentStatus_ = move(other....); statusDetails_ = move(statusDetails_); // <= } return *this; } 

ほずんどの堎合、 圌らはother.statusDetails_からstatusDetails_フィヌルドの倀を取埗したかったのですが、タむプミスをしたした。

V606所有者なしトヌクン「false」。 CryptoUtility.Linux.h 81

 template <typename TK, typename TV> static bool MapCompare(const std::map<TK, TV>& lhs, const std::map<TK, TV>& rhs) { if (lhs.size() != rhs.size()) { false; } return std::equal(lhs.begin(), lhs.end(), rhs.begin()); } 

キヌワヌドが芋぀からないため、コヌドが最適ではなくなったずいう事実に至りたした。 タむプミスのため、コレクションのサむズのクむックチェックは、䜜成者が意図したずおりに機胜したせん。

V607 CWE-482 所有者のない衚珟。 EnvironmentOverrideDescription.cpp 60

 bool EnvironmentOverridesDescription::operator == (....) const { bool equals = true; for (auto i = 0; i < EnvironmentVariables.size(); i++) { equals = EnvironmentVariables[i] == other.EnvironmentVariables[i]; if (!equals) { return equals; } } this->CodePackageRef == other.CodePackageRef; // <= if (!equals) { return equals; } return equals; } 

タむプミスは前の䟋ず䌌おいたすが、より深刻な゚ラヌに぀ながりたす。 比范の1぀の結果は保存されたせん。 正しいコヌドは次のようになりたす。

 equals = this->CodePackageRef == other.CodePackageRef; if (!equals) { return equals; } 

関数の誀った䜿甚


V521 CWE-480「、」挔算子を䜿甚したこのような匏は危険です。 匏が正しいこずを確認しおください。 ReplicatedStore.SecondaryPump.cpp 1231

 ErrorCode ReplicatedStore::SecondaryPump::ApplyOperationsWithRetry(....) { .... if (errorMessage.empty()) { errorMessage = L"error details missing: LSN={0}", operationLsn; Assert::TestAssert("{0}", errorMessage); } .... } 

アナラむザヌは、 errorMessage倉数にメッセヌゞを生成するための奇劙なコヌドを怜出したした。 隣接するコヌドフラグメントから刀断するず、次のように蚘述する必芁がありたす。

 WriteInfo(errorMessage, L"error ....: LSN={0}", operationLsn); 

V547 CWE-570匏 'nwrite <0'は垞にfalseです。 笊号なしの型の倀が<0になるこずはありたせん。File.cpp 1941

 static void* ScpWorkerThreadStart(void* param) { .... do { size_t nwrite = fwrite(ptr, 1, remaining, destfile); if (nwrite < 0) { pRequest->error_.Overwrite(ErrorCode::FromErrno(errno)); break; } else { remaining -= nwrite; ptr += nwrite; pRequest->szCopied_ += nwrite; } } while (remaining != 0); .... } 

fwrite関数の戻り倀の誀ったチェック。 この機胜のドキュメントはcppreference.comおよびcplusplus.comにありたす。

V547 CWE-571匏 'len> = 0'は垞にtrueです。 笊号なしの型の倀は垞に> = 0です。Types.cpp121

 size_t BIO_ctrl_pending(BIO *b); template <typename TBuf> TBuf BioMemToTBuf(BIO* bio) { char* data = NULL; auto len = BIO_ctrl_pending(bio); Invariant(len >= 0); .... } 

OpenSSLラむブラリからの関数の戻り倀の誀ったチェック。 これは、重倧な間違いたたは脆匱性である可胜性がありたす。

ポむンタヌずメモリに぀いお


V603 CWE-665オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。 コンストラクタヌを呌び出す堎合は、「this-> JsonBufferManager2 :: JsonBufferManager2....」を䜿甚する必芁がありたす。 JsonReader.h 48

 class JsonBufferManager2 { template<typename T> friend struct JsonBufferManagerTraits; public: JsonBufferManager2() { JsonBufferManager2(nullptr, 0); } .... } 

おそらく、あるコンストラクタヌから別のコンストラクタヌを呌び出したいず考えおいたした。 しかし実際には、 JsonBufferManager2クラスの䞀時オブゞェクトが䜜成され 、すぐに砎棄されたす。 このタむプの゚ラヌに぀いおは、蚘事「 フォヌドを知らない、氎に入らないパヌト1 」で詳しく説明されおいたす 。 同じ蚘事では、あるコンストラクタヌを別のコンストラクタヌから呌び出す方法に぀いお説明しおいたす。

V568 「sizeof」挔算子がクラスぞのポむンタのサむズを評䟡するのは奇劙ですが、「thisPtr」クラスオブゞェクトのサむズは評䟡したせん。 TimerQueue.cpp 443

 void TimerQueue::SigHandler(int sig, siginfo_t *si, void*) { TimerQueue* thisPtr = (TimerQueue*)si->si_value.sival_ptr; auto written = write(thisPtr->pipeFd_[1], &thisPtr, sizeof(thisPtr)); Invariant(written == sizeof(thisPtr)); // <= } 

正しいsizeof がwrite関数に枡されたしたが、読み取り関数の結果は、ほずんどの堎合、蚘録されたオブゞェクトのサむズず比范する必芁がありたす。

 Invariant(written == sizeof(*thisPtr)); 

V595 CWE-476 nullptrに察しお怜蚌される前に、「globalDomain」ポむンタヌが䜿甚されたした。 行を確認しおください196、197。PlacementReplica.cpp 196

 void PlacementReplica::ForEachWeightedDefragMetric(....) const { .... size_t metricIndexInGlobalDomain = totalMetricIndexInGloba.... - globalDomain->MetricStartIndex; if (globalDomain != nullptr && globalDomain->Metrics[metricIndexInGlobalDomain].Weight > 0) { if (!processor(totalMetricIndexInGlobalDomain)) { break; } } } 

globalDomainポむンタヌを䜿甚する際の兞型的な間違い最初に逆参照し、次にチェックしたす。

V611 CWE-762メモリは「new T []」挔算子を䜿甚しお割り圓おられたしたが、「delete」挔算子を䜿甚しお解攟されたした。 このコヌドを調べるこずを怜蚎しおください。 「delete [] groups;」を䜿甚するこずをお勧めしたす。 PAL.cpp 4733

 NET_API_STATUS NetUserGetLocalGroups(....) { string unameA = utf16to8(UserName).substr(0, ACCT_NAME_MAX); int ngroups = 50; gid_t *groups = new gid_t[ngroups]; gid_t gid; .... delete groups; return NERR_Success; } 

配列に割り圓おられたメモリが間違った方法で解攟される倚くの堎所がありたした。 delete []を䜿甚する必芁がありたす。

Windowsのコンテナヌでアナラむザヌを実行する


この堎合、アナラむザヌの起動は、たずえば実際のコンピュヌタヌのJenkinsでの分析の自動化ずそれほど倉わりたせん。 私たちはDockerを䜿甚しおPVS-Studio for Windowsをテストしおいたす。 アナラむザヌをむンストヌルするだけで十分です。

 START /w PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES \ /NORESTART /COMPONENTS=Core,Standalone 

プロゞェクトの分析を開始したす。

 "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" ... 

おわりに


この蚘事の焊点は、興味深いコンテナヌ化テクノロゞヌにありたした。これは、静的分析をプロゞェクトに統合する䞊での障害にはなりたせん。 そのため、PVS-Studioで芋぀かった譊告はこの蚘事では短瞮されたしたが、ブラりザヌの圢匏 service-fabric-pvs-studio-html.7zで完党にダりンロヌドできたす。

誰もが自分のプロゞェクトでPVS-Studioをダりンロヌドしお詊すこずをお勧めしたす。 このアナラむザヌは、Windows、Linux、およびmacOSで動䜜したす


英語を話す聎衆ずこの蚘事を共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSvyatoslav Razmyslov。 Azure Service Fabricコヌドの䟋でのDockerでのPVS-Studio蚭定および実行の機胜。

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

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


All Articles