PVS-StudioがC ++ / CLIをサポートするようになりました

PVS-Studio、C ++ / CLI

C ++ / CLIで記述されたプロジェクトのサポートは、PVS-Studioの優先事項ではありません。 そのようなプロジェクトはほとんどありませんが、それにもかかわらず、時々それらに出くわします。 マイクロソフトは現在、C ++ / CLI言語のサポートを停止する予定はないため、この種の言語を引き続きサポートすることにしました。



C ++ / CLIサポート



ウィキペディア: C ++ / CLI -C ++プログラミング言語のMicrosoft .NETプログラミング環境へのバインド。 ISO標準のC ++を、Common Language Infrastructure(CLI)の一部と見なされるUnified Type System(UTS)と統合します。 ソースレベルと、ネイティブおよびマネージC ++からコンパイルされた実行可能ファイルの相互運用性の両方をサポートします。 C ++ / CLIは、C ++のさらなる開発を表します。



ほとんどのプロジェクトをテストするのに十分なレベルで、PVS-StudioでC ++ / CLIのサポートを実装しました。 ただし、テストするのに十分なプロジェクトがなかったため、一部の言語コンストラクトが正しく処理されないか、明確な誤検知が発生する可能性があります。 すべてをすぐに追跡するのは難しいです。 プロジェクトのチェックで問題が発生した場合は、お知らせください。



この記事は完成できますが、面白くありません。 そのため、私たちは小さなプロジェクトSlimDXをチェックし、以下について説明します。



Slimdx



ウィキペディア: SlimDXは、.NETでのDirectXプログラミング用のオープンソースAPIです。 SlimDXは、.NETランタイム(CLRによる)の下で任意の言語から使用できます。 SlimDXは、マルチメディアおよびインタラクティブアプリケーション(ゲームなど)の開発に使用できます。 高性能のグラフィカル表現を可能にし、プログラマーが.NETフレームワーク内で作業しながら最新のグラフィカルハードウェアを利用できるようにします。



公式ウェブサイト: http : //slimdx.org/



チェックは、 PVS-Studioコードアナライザーを使用して実行されました。 プロジェクトは小さく、別のライブラリのラッパーであるため、疑わしい場所はほとんどありませんでした。 しかし、彼らはそれらについて書くのに十分です。



検証結果



以下は、私にとって間違っているように思われるコードスニペットです。



フラグメントN1

ContainmentType BoundingBox::Contains( BoundingBox box, BoundingSphere sphere ) { .... if( box.Minimum.X + radius <= sphere.Center.X && sphere.Center.X <= box.Maximum.X - radius && box.Maximum.X - box.Minimum.X > radius && <<<=== box.Minimum.Y + radius <= sphere.Center.Y && sphere.Center.Y <= box.Maximum.Y - radius && box.Maximum.Y - box.Minimum.Y > radius && box.Minimum.Z + radius <= sphere.Center.Z && sphere.Center.Z <= box.Maximum.Z - radius && box.Maximum.X - box.Minimum.X > radius) <<<=== return ContainmentType::Contains; .... }
      
      





PVS-Studioの警告:V501「&&」演算子の左側と右側には、同一の部分式「box.Maximum.X-box.Minimum.X> radius」があります。 boundingbox.cpp 94



ほとんどの場合、このコードはCopy-Pasteを使用して作成され、最後の行を変更するのを忘れていました。 式の最後に「box.Maximum.Z-box.Minimum.Z> radius」と記述する必要があります。



フラグメントN2

 typedef struct DIJOYSTATE2 { .... LONG rglSlider[2]; .... LONG rglVSlider[2]; .... LONG rglASlider[2]; .... LONG rglFSlider[2]; .... } DIJOYSTATE2, *LPDIJOYSTATE2; void JoystickState::AssignState(const DIJOYSTATE2 &joystate) { .... for( int i = 0; i < 2; i++ ) { sliders[i] = joystate.rglSlider[i]; asliders[i] = joystate.rglASlider[i]; vsliders[i] = joystate.rglVSlider[i]; fsliders[i] = joystate.rglVSlider[i]; } .... }
      
      





警告PVS-Studio:V525同様のブロックのコレクションを含むコード。 行93、94、95、96の項目「rglSlider」、「rglASlider」、「rglVSlider」、「rglVSlider」を確認します。joystickstate.cpp 93



このコードにはタイプミスが含まれていると思います。 最後の行では、おそらくrglFSlider配列を使用する必要があります。

 sliders[i] = joystate.rglSlider[i]; asliders[i] = joystate.rglASlider[i]; vsliders[i] = joystate.rglVSlider[i]; fsliders[i] = joystate.rglFSlider[i];
      
      





フラグメントN3

 array<SoundEffectResult>^ SecondarySoundBuffer::SetEffects( array<Guid>^ effects ) { DWORD count = effects->Length; .... if( effects != nullptr && count > 0 ) .... }
      
      





PVS-Studio警告:V595 nullptrに対して検証される前に、「効果」ポインターが使用されました。 チェック行:66、73。secondarysoundbuffer.cpp 66



最初は、「効果」ポインターが逆参照されます。 次に、以下のコードで、ゼロと等しいかどうかがチェックされます。



フラグメントN4



仮想関数を含むクラス「TVariable」があります。

 template<typename IBaseInterface> struct TVariable : public IBaseInterface { virtual BOOL IsValid() { .... } .... };
      
      





SMemberクラスは、このクラスから継承されます。 ZeroMemory()関数を使用して、このクラスのフィールドにゼロが書き込まれることに注意してください。

 struct SMember : public TVariable<TMember<ID3DX11EffectVariable> > { }; CEffectVectorOwner<SMember> m_pMemberInterfaces; ZeroMemory HRESULT CEffect::CopyMemberInterfaces(....) { .... ZeroMemory( &m_pMemberInterfaces[i], sizeof(SMember) * ( Members - i ) ); .... }
      
      





PVS-Studio警告:V598「memset」関数は、「SMember」クラスのフィールドを無効にするために使用されます。 これにより、仮想メソッドテーブルが破損します。 effectnonruntime.cpp 1739



仮想関数があるため、SMemberクラスには仮想メソッドのテーブルへのポインターが含まれています。 ZeroMemory()関数を呼び出すと、このポインターが破損します。



同様に:

フラグメントN5

 #pragma warning(disable: 4369) public enum class WaveFormatTag : System::Int32 { Pcm = WAVE_FORMAT_PCM, AdPcm = WAVE_FORMAT_ADPCM, IeeeFloat = WAVE_FORMAT_IEEE_FLOAT, MpegLayer3 = WAVE_FORMAT_MPEGLAYER3, DolbyAC3Spdif = WAVE_FORMAT_DOLBY_AC3_SPDIF, WMAudio2 = WAVE_FORMAT_WMAUDIO2, WMAudio3 = WAVE_FORMAT_WMAUDIO3, WmaSpdif = WAVE_FORMAT_WMASPDIF, Extensible = WAVE_FORMAT_EXTENSIBLE, }; #pragma warning(default: 4369)
      
      





PVS-Studio警告:V665このコンテキストでは、「#pragma warning(default:X)」の使用法が間違っている可能性があります。 代わりに「#pragma warning(push / pop)」を使用する必要があります。 チェック行:1089、1102。enums.h 1102



コンパイラの警告は誤って抑制されます。 最後に、デフォルト値が復元されます。 最初に設定の状態を保存してから復元する方が適切です。 これは重大な間違いとは言えません。 ただし、ライブラリがユーザープロジェクトの警告レベル設定を損なわないことが重要です。 アラートを抑制する正しいアプローチについては、アラートV665の説明を参照してください



ヘッダーファイル「enums.h」には、さらに類似した欠陥がいくつかあります。 行番号:224、267、346。



おわりに



C ++ / CLIプロジェクトのチェックに関する最初の記事は退屈で簡潔であることがわかりました。 最初のパンケーキはゴツゴツしています。 将来的には、より大きくて興味深いプロジェクトを検証できることを望んでいます。



PVS-Studioを使用してC ++ / CLIプロジェクトをダウンロードしてテストすることをお勧めします。 フィードバックやコメントをお待ちしております。



この記事は英語です。



この記事を英語圏の聴衆と共有したい場合は、翻訳へのリンクを使用してください:Andrey Karpov。 C ++ / CLIがPVS-Studioでサポートされるようになりました



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




All Articles