PVS-StudioがついにBoostになりました

BoostとPVS-Studio



私たちは、Boostライブラリをチェックしたいとずっと思っていました。 検証の結果がその記事にとって十分かどうかはわかりませんでした。 しかし、欲求は消えませんでした。 これを2回試みましたが、コンパイラー呼び出しをPVS-Studio.exe呼び出しに置き換える方法を理解せずに撤回しました。 今、私たちは新しいツールで武装し、3回目の試みは成功しました。 だから、Boostでエラーを見つけることは可能ですか?





ブースト



Boostは、C ++の機能を拡張するフリーウェアライブラリのコレクションです。 このプロジェクトは、C ++標準の採用後に作成されました。多くのライブラリは、一部のライブラリが標準に含まれていないことに不満を抱いていました。 このプロジェクトは、さまざまな言語拡張の一種の「テストの場」であり、一部のライブラリは、次のC ++標準に含める候補となります。 参照:







Boostは、複雑なパターンが積極的に使用される「重い」コードです。 このライブラリは、いくつかの点でコンパイラのテストです。 コンパイラーは、最新のBoostライブラリーのプロジェクトの一部のみをコンパイルできることがよくあります。



ただし、コードの解析に問題はありませんでした。 極端な場合、アナライザーは非常に複雑な設計を静かにスキップできます。 アセンブリ自体に統合するのは難しいことがわかりました。



PVS-Studioを使用してプロジェクトをチェックするための既存のオプションを思い出させてください。



Visual StudioまたはEmbarcadero C ++ Builderの通常のプロジェクトがある場合



ここではすべてが簡単です。 プロジェクト分析は、開発環境から直接実行できます。 別のオプションは、コマンドラインからPVS-Studioを起動し、出力でスキャン結果を含むファイルを取得することです。 このモードは、継続的な統合システム(Cruise Control、Draco.NET、Team Foundation Buildなど)に役立ちます。 このモードについては、ドキュメントで詳しく説明しています。 継続的統合システムとの相互作用については、 こちらをご覧ください



プロジェクトがない場合(または、プロジェクトが本質的に変装したメイクファイルである場合)



この場合、コンパイラの代わりに(またはコンパイラとともに)コードアナライザーを起動するときにビルドモードを作成する必要があります。 出力には、レポートファイルも含まれます。 必要な魔法の呪文もドキュメントに記載されています。 この場合、マジシャンは非常に注意し、マニュアルを詳細に研究し、1人のキャラクターを忘れないようにする必要があります。



Boostのテストに使用すべきだったのは、このアプローチでした。 残念です。私たちはレベルが不十分な、または怠け者の魔術師でした。 アナライザーのコンソールバージョンに必要なすべてのパラメーターを渡すために、アセンブリシステムを把握できませんでした。



プロジェクトをチェックするための新しい3番目のオプションが私たちの助けになりました



私の同僚は、最近の記事「 PVS-Studio開発者の秘密研究所の地下から 」でこの新しいモードについて言及しました 。 アセンブリシステムに完全に統合する必要はありません。 前処理された* .iファイルを取得するだけです 。 はるかに簡単です。 それが私たちがしたことです。



次に、新しいツールのプロトタイプ(PVS-Studio Standalone)を使用して、すべての* .iファイルの分析を実行し、待望のレポートを受け取りました。 同じプログラムで、エラーのリストを簡単に操作し、コードを修正できます。



このツールをいくつかのバージョンを通じてディストリビューションに含めることを期待しています。 おそらくこれはPVS-Studio 5.10で起こるでしょう。



そうではないが、私たちが夢見ている政権に関するいくつかの言葉



コンパイラのアクションをゆっくりと追跡しています。 このモードは、PVS-Studio Standaloneツールにも適用されます。 コンパイラーの起動はすべて監視され、起動するためのキーが収集されます。 したがって、次の手順で十分です。 注文-「ウォッチ」。 任意のビルドシステムを使用してプロジェクトをビルドします。 言うために-「準備完了」。 そして、アナライザーはプロジェクトを今すぐチェックする方法を知っています。 もちろん、プロジェクトの構造またはパラメーターが変更された場合、このプロセスを繰り返す必要があります。 さて、夢を見て、今度はBoostテストに戻りましょう。



絶望感



Boostに関する記事を書くことができなかった。 この悲しい仮定には、次の前提がありました。



多数のコンパイラとツール



Boostは、多数のコンパイラによって構築されます。 一部は部分的に、一部は完全に。 私はこの問題を研究しませんでした。 しかし、私が理解しているように、BoostはVisual C ++、Intel C ++、Sun Studio、Compaq C ++、GCC、Clangを使用して非常にうまくビルドされます。 各コンパイラには独自の診断機能があります。 そして、それらの合計使用により、非常に高品質のコードが提供されるはずです。 1つのコンパイラはエラーA、2番目のエラーBなどを検出します。



さらに、Boostライブラリは、さまざまなツールと静的コードアナライザーの一種のテストグラウンドです。 BoostはC ++言語のさまざまな最新機能を積極的に使用しているため、ツールがそのようなコードを処理できるかどうかを知ることは常に興味深いです。 その結果、Boostはさまざまなコードアナライザーによってテストおよびクロスチェックされます。



非常に多くのコンパイラや他のツールの後にエラーやタイプミスを探すことは、ほとんど絶望的です。



多数のユーザー



Boostライブラリは多くのプロジェクトで使用されています。 かつて、私たちはPVS-Studioプロジェクト(当時はViva64)でBoostを使用していました。 正規表現、構成ファイル、その他いくつかの小さなことを処理するメカニズムを使用しました。 その後、正規表現は行き止まりであり、コードから次第に消えることに気付きました。 構成ファイルのためだけにBoostを実行するのは疑わしかったです。 さらに、いくつかの不快な欠点が明らかになりました。 たとえば、ファイル名に「#」を使用することはできません。 この文字はコメントの始まりとしてカウントされます。 特定のケースでは、Boostは定着しませんでしたが、これは確かに非常に便利なライブラリです。



ライブラリは広く使用されているため、エラーはプログラマーによって迅速に検出されるはずです。 エラーは、めったに使用されないコードフラグメント、またはユーザーがほとんどいないエキゾチックなサブシステムにのみ存在します。



パターン



Boostには多くのテンプレートクラスがあります。 インスタンス化されない限り、検証することはほとんど不可能です。 たとえば、Visual C ++は、テンプレートクラスが使用されていない場合、テンプレートクラスをまったく解析しません。 未使用のクラスに任意のごみを書くことができます。ファイルは、開き括弧と閉じ括弧の数と引用符()、<>、{}、[]、 ""、 ''を保持するのに十分にコンパイルされます。



テンプレートクラスの分析では、誤検知の数とエラーのスキップの間で妥協する必要があります。 複雑さを簡単な例で説明しましょう。

template <typename T>
bool IsNAN(T x) { return x != x; }
      
      





, « » (Not-a-Number). float/double/long double. , .



, ? . . . . . , PVS-Studio . - , - .



. Boost .





, . , . , .



3-4 Boost .



, PVS-Studio 5.06 Boost 1.55 ( ).



Boost



. .



N1.



point3D operator/(const point3D &p1, const point3D &p2)
{
  return point3D( p1.x/p2.x , p1.y/p2.y , p1.z/p1.z );
}
      
      





PVS-Studio: V501 There are identical sub-expressions to the left and to the right of the '/' operator: p1.z / p1.z lorenz_point.cpp 61



, 'p1.z' . , 'p2.z'.



N2.



BOOST_UBLAS_INLINE
compressed_matrix_view(const compressed_matrix_view& o) :
  size1_(size1_), size2_(size2_),
  nnz_(nnz_),
  index1_data_(index1_data_),
  index2_data_(index2_data_),
  value_data_(value_data_)
{}
      
      





PVS-Studio ( ): V546 Member of a class is initialized by itself: 'size1_(size1_)'. sparse_view.hpp 193



. , . , 'o'. , :

BOOST_UBLAS_INLINE
compressed_matrix_view(const compressed_matrix_view& o) :
  size1_(o.size1_), size2_(o.size2_),
  nnz_(o.nnz_),
  index1_data_(o.index1_data_),
  index2_data_(o.index2_data_),
  value_data_(o.value_data_)
{}
      
      







N3.



static std::basic_string<wchar_t> get(char const* source = "")
{
  ....
  std::auto_ptr<wchar_t> result (new wchar_t[len+1]);
  ....
}
      
      





PVS-Studio: V554 Incorrect use of auto_ptr. The memory allocated with 'new []' will be cleaned using 'delete'. tree_to_xml.ipp 71



'std::auto_ptr' . 'delete', 'delete []'. , . "delete, new[] C++ ".



: generate_static.hpp 53.



N4. . SOCKET



-, , , SOCKET. . :

SOCKET s = Foo();
if (s < 0) { Error(); }
      
      





. SOCKET_ERROR. , «socket < 0» «socket >= 0».



Linux SOCKET . Windows SOCKET . , .



Boost.

typedef SOCKET socket_type;

class socket_holder
{
  ....
  socket_type socket_;
  ....
  socket_type get() const { return socket_; }
  ....
};

template <typename Socket>
boost::system::error_code accept(....)
{
  ....
  // On success, assign new connection to peer socket object.
  if (new_socketnew_socket.get() >= 0)
  {
    if (peer_endpoint)
      peer_endpoint->resize(addr_len);
    if (!peer.assign(impl.protocol_, new_socket.get(), ec))
      new_socket.release();
  }
  return ec;
}
      
      





PVS-Studio: V547 Expression 'new_socket.get() >= 0' is always true. Unsigned type value is always >= 0. win_iocp_socket_service.hpp 436



Windows , . «new_socketnew_socket.get() >= 0» .



N5.



void set_duration_style(duration_style style)
{
  duration_style_ == style;
}
      
      





PVS-Studio: V607 Ownerless expression 'duration_style_ == style'. base_formatter.hpp 51



. , , : «duration_style_ = style». .



, PVS-Studio . . . , . , . PVS-Studio . . , .



? ( ). , . , . , , : , TDD, .



N6.



template< typename CharT >
basic_settings< CharT > parse_settings(std::basic_istream< CharT >& strm)
{
  ....
  string_type line;
  while (!strm.eof())
  {
     std::getline(strm, line);

     const char_type* p = line.c_str();
     parser.parse_line(p, p + line.size());

     line.clear();
     ++line_number;
  }
  ....
}
      
      





PVS-Studio: V663 Infinite loop is possible. The 'cin.eof()' condition is insufficient to break from the loop. Consider adding the 'cin.fail()' function call to the conditional expression. settings_parser.cpp 285



, — . , . , , . . , . 'eof()' 'false'. . 'eof()' 'fail()'. 'fail()' , . .



: V663 Infinite loop is possible. The 'cin.eof()' condition is insufficient to break from the loop. Consider adding the 'cin.fail()' function call to the conditional expression. adjacency_list_io.hpp 195



N7.



template<> 
struct identity_element<boost::gregorian::date_duration>
{
  static boost::gregorian::date_duration value()
  { 
    return
      boost::gregorian::date(boost::gregorian::min_date_time) -
      boost::gregorian::date(boost::gregorian::min_date_time); 
  }
};
      
      





PVS-Studio: V501 There are identical sub-expressions 'boost::gregorian::date(boost::gregorian::min_date_time)' to the left and to the right of the '-' operator. gregorian.hpp 57



, 0?





, PVS-Studio . - Boost . !



All Articles