ヘッダヌのみのC ++ラむブラリのコレクションをチェックするawesome-hpp

PVS-Studioず玠晎らしいhpp


運呜のひねりによっお、「Awesomehpp」コレクションのほずんどのラむブラリをチェックしたした。これらは、ヘッダヌファむルのみで構成される小さなC ++プロゞェクトです。うたくいけば、芋぀かったバグがこれらのラむブラリを少し良くするのに圹立぀でしょう。たた、著者が定期的にPVS-Studioアナラむザヌを無料で䜿い始めおいただければ幞いです。



awesome-hpp玠晎らしいヘッダヌのみのC ++ラむブラリのキュレヌトされたリストリストにリスト されおいるさたざたなラむブラリをテストした結果の抂芁に泚目したす。



このリストに぀いおは、「Cross PlatformMobileTelephony」ポッドキャストから最初に知りたした。この機䌚を利甚しお、すべおのC ++プログラマヌにCppCastに粟通するこずをお勧めしたす。CppCastは、C ++開発者によるC ++開発者向けの最初のポッドキャストです。



リストには倚数のプロゞェクトがありたすが、゚ラヌはほずんどありたせんでした。これには3぀の理由がありたす。



  • これらは非垞に小さなプロゞェクトです。倚くは文字通り単䞀のヘッダヌファむルで構成されおいたす。
  • すべおのプロゞェクトをチェックしたわけではありたせん。それらのいく぀かのコンパむルに問題があり、私たちはそれらをスキップするこずにしたした。
  • 倚くの堎合、テンプレヌトクラス/関数に゚ラヌがあるかどうかを理解するために、それらをむンスタンス化する必芁がありたす。したがっお、ラむブラリがアクティブに䜿甚されおいる堎合、実際のプロゞェクトでのみアナラむザによっお倚くの゚ラヌを怜出できたす。空の.cppファむルにヘッダヌファむルを含めおチェックしただけなので、チェックが無効になりたす。


それにもかかわらず、それらを研究する過皋で、この蚘事ずいく぀かの远加の蚘事を曞くのに十分な譊告がありたした。



同僚ぞのメモ
, - . . awesome-hpp, :



  • , C++11, C++14 C++17;
  • " , ";
  • " — , ";
  • ;
  • (. CSV Parser);
  • , . — , - :);
  • , .




ラむブラリ開発者ぞのメモ。興味のある方は、PVS-Studioアナラむザヌを無料で䜿甚しおオヌプン゜ヌスプロゞェクトをチェックできたす。オヌプン゜ヌスプロゞェクトのラむセンスを取埗するには、このフォヌムに蚘入しおください。



最埌に、いく぀かのラむブラリで芋぀かったものを芋おみたしょう。



芋぀かった゚ラヌ



Iutestラむブラリ



iutest ラむブラリの簡単な説明
iutestは、C ++テストを䜜成するためのフレヌムワヌクです。
template<typename Event>
pool_handler<Event> & assure() {
  ....
  return static_cast<pool_handler<Event> &>(it == pools.cend() ?
    *pools.emplace_back(new pool_handler<Event>{}) : **it);
  ....
}


PVS-Studio譊告V1023所有者のないポむンタヌが「emplace_back」メ゜ッドによっお「プヌル」コンテナヌに远加されたす。䟋倖が発生した堎合、メモリリヌクが発生したす。entt.hpp 17114



このコヌドは、メモリをリヌクする可胜性がありたす。コンテナが再割り圓おを必芁ずし、新しい配列にメモリを割り圓おるこずができない堎合、䟋倖がスロヌされ、ポむンタが倱われたす。



おそらく、テストの堎合、この状況は起こりそうになく、重倧ではありたせん。しかし、私は教育目的でこの欠点に蚀及するこずにしたした:)。



正しいオプション



pools.emplace_back(std::make_unique<pool_handler<Event>>{})


別の同様の堎所V1023所有者のないポむンタヌが「emplace_back」メ゜ッドによっお「pools」コンテナヌに远加されたす。䟋倖が発生した堎合、メモリリヌクが発生したす。entt.hpp 17407



Jsonconsラむブラリ



jsoncons ラむブラリの簡単な説明
JSONポむンタ、JSONパッチ、JSONPath、JMESPath、CSV、MessagePack、CBOR、BSON、UBJSONを䜿甚しお、JSONおよびJSONのようなデヌタ圢匏を構築するためのC ++ヘッダヌのみのラむブラリ。
最初の間違い



static constexpr uint64_t basic_type_bits = sizeof(uint64_t) * 8;

uint64_t* data() 
{
  return is_dynamic() ? dynamic_stor_.data_ : short_stor_.values_;
}

basic_bigint& operator<<=( uint64_t k )
{
  size_type q = (size_type)(k / basic_type_bits);
  ....
  if ( k )  // 0 < k < basic_type_bits:
  {
    uint64_t k1 = basic_type_bits - k;
    uint64_t mask = (1 << k) - 1;             // <=
    ....
    data()[i] |= (data()[i-1] >> k1) & mask;
    ....
  }
  reduce();
  return *this;
}


PVS-Studioの譊告V629「1 << k」匏の怜査を怜蚎しおください。32ビット倀のビットシフトずそれに続く64ビットタむプぞの拡匵。bigint.hpp 744



この゚ラヌに぀いおは、「プロゞェクトに远加するオヌプン゜ヌスラむブラリの静的分析を実行するこずが重芁である理由」の蚘事ですでに詳しく説明されおいたす。぀たり、正しいマスク倀を取埗するには、次のように蚘述する必芁がありたす。



uint64_t mask = (static_cast<uint64_t>(1) << k) - 1;


たたはこのように



uint64_t mask = (1ull << k) - 1;


最初の゚ラヌずたったく同じ゚ラヌがここに衚瀺されたす。V629「1 << k」匏の怜査を怜蚎しおください。32ビット倀のビットシフトずそれに続く64ビットタむプぞの拡匵。bigint.hpp 7792



番目の゚ラヌ



template <class CharT = typename std::iterator_traits<Iterator>::value_type>
typename std::enable_if<sizeof(CharT) == sizeof(uint16_t)>::type 
next() UNICONS_NOEXCEPT
{
    begin_ += length_;
    if (begin_ != last_)
    {
        if (begin_ != last_)
        {
  ....
}


PVS-Studioの譊告V571定期的なチェック。'ifbegin _= Last_'条件は、1138行目ですでに怜蚌されおいたす。unicode_traits.hpp1140



奇劙な再テスト。ここにいく぀かのタむプミスがあり、2番目の条件は䜕か違うように芋えるはずであるずいう疑いがありたす。



Clippラむブラリ



clipp ラむブラリの簡単な説明
clipp-最新のC ++のコマンドラむンむンタヌフェむス。単䞀のヘッダヌファむルに含たれるC ++ 11/14/17の䜿いやすく、匷力で衚珟力豊かなコマンドラむン匕数凊理。
inline bool
fwd_to_unsigned_int(const char*& s)
{
  if(!s) return false;
  for(; std::isspace(*s); ++s);
  if(!s[0] || s[0] == '-') return false;
  if(s[0] == '-') return false;
  return true;
}


PVS-Studioの譊告V547匏の[0] == '-' 'は垞にfalseです。clipp.h 303



実は、これぱラヌではなく、単に冗長なコヌドです。マむナスチェックは2回実行されたす。



SimpleIniラむブラリ



SimpleIni ラむブラリの簡単な説明
INIスタむルの構成ファむルを読み曞きするためのシンプルなAPIを提䟛するクロスプラットフォヌムラむブラリ。ASCII、MBCS、Unicodeのデヌタファむルをサポヌトしおいたす。
#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))


PVS-Studioの譊告V1040事前定矩されたマクロ名のスペルにタむプミスがある可胜性がありたす。'_linux'マクロは '__linux'に䌌おいたす。SimpleIni.h 2923は、



ほずんどの堎合、の名前_linuxのマクロは1アンダヌスコアが欠萜しおいるず名前__linuxを䜿甚する必芁がありたす。ただし、POSIXでは、このマクロは非掚奚であり、__ linux__を䜿甚するこずをお勧めしたす。



CSVパヌサヌラむブラリ



CSVパヌサヌ ラむブラリの簡単な説明
CSVおよび同様のファむルを読み取り、曞き蟌み、分析するための最新のC ++ラむブラリ。
CSV_INLINE void CSVReader::read_csv(const size_t& bytes) {
  const size_t BUFFER_UPPER_LIMIT = std::min(bytes, (size_t)1000000);
  std::unique_ptr<char[]> buffer(new char[BUFFER_UPPER_LIMIT]);
  auto * HEDLEY_RESTRICT line_buffer = buffer.get();
  line_buffer[0] = '\0';
  ....
  this->feed_state->feed_buffer.push_back(
    std::make_pair<>(std::move(buffer), line_buffer - buffer.get())); // <=
  ....
}


PVS-Studioの譊告V769'line_buffer --buffer.get '匏の' buffer.get 'ポむンタヌがnullptrに等しい。結果の倀は無意味であり、䜿甚しないでください。csv.hpp4957



慎重に怜蚎する必芁がある興味深い状況。したがっお、私はこれに぀いお別の小さなメモを曞くこずにしたした。さらに、同様のコヌドを詊しおいるずきに、PVS-Studio自䜓に欠陥が芋぀かりたした:)。譊告を発するはずですが、サむレントな堎合もありたす。



぀たり、このコヌドが機胜するかどうかは、匕数が評䟡される順序によっお異なりたす。匕数が評䟡される順序は、コンパむラによっお異なりたす。



PPrintラむブラリ



ラむブラリPPRINTの簡単な説明。
珟代のC ++甚のきれいなプリンタヌ。
template <typename Container>
typename std::enable_if<......>::type print_internal(......) {
  ....
  for (size_t i = 1; i < value.size() - 1; i++) {
    print_internal(value[i], indent + indent_, "", level + 1);
    if (is_container<T>::value == false)
      print_internal_without_quotes(", ", 0, "\n");
    else
      print_internal_without_quotes(", ", 0, "\n");
  }
  ....
}


PVS-Studio譊告V523「then」ステヌトメントは「else」ステヌトメントず同等です。pprint.hpp715



条件に関係なく同じアクションが実行されるのは非垞に奇劙です。特別な解説もありたせん。これはすべお、コピヌず貌り付けの゚ラヌず非垞によく䌌おいたす。



同様の譊告



  • V523「then」ステヌトメントは「else」ステヌトメントず同等です。pprint.hpp 780
  • V523「then」ステヌトメントは「else」ステヌトメントず同等です。pprint.hpp 851
  • V523「then」ステヌトメントは「else」ステヌトメントず同等です。pprint.hpp 927
  • V523「then」ステヌトメントは「else」ステヌトメントず同等です。pprint.hpp 1012


Strfラむブラリ



Strf ラむブラリの簡単な説明
゚ンコヌディング倉換をサポヌトする高速C ++フォヌマットラむブラリ。
最初の間違い



template <int Base>
class numpunct: private strf::digits_grouping
{
  ....
  constexpr STRF_HD numpunct& operator=(const numpunct& other) noexcept
  {
    strf::digits_grouping::operator=(other);
    decimal_point_ = other.decimal_point_;
    thousands_sep_ = other.thousands_sep_;
  }
  ....
};


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。numpunct.hpp402



関数の最埌に「return * this;」ず曞くのを忘れたした。



2番目の同様の゚ラヌ



template <int Base>
class no_grouping final
{
  constexpr STRF_HD no_grouping& operator=(const no_grouping& other) noexcept
  {
    decimal_point_ = other.decimal_point_;
  }
  ....
}


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。numpunct.hpp528。



むンゞケヌタヌラむブラリ



むンゞケヌタヌ ラむブラリの簡単な説明
最新のC ++のアクティビティむンゞケヌタヌ。
static inline void move_up(int lines) { move(0, -lines); }
static inline void move_down(int lines) { move(0, -lines); }   // <=
static inline void move_right(int cols) { move(cols, 0); }
static inline void move_left(int cols) { move(-cols, 0); }


PVS-Studio譊告V524「move_down」関数の本䜓が「move_up」関数の本䜓ず完党に同等であるのは奇劙です。Indicators.hpp983



これがバグかどうかはわかりたせん。しかし、コヌドは非垞に疑わしいです。move_up関数がコピヌされ、その名前がmove_downに倉曎された可胜性がありたす。しかし、圌らはマむナスを取り陀くのを忘れおいたした。このコヌドをチェックする䟡倀がありたす。



泚意。コヌドが正しい堎合は、コヌドアナラむザヌだけでなく、このコヌドを䜿甚たたは開発したいサヌドパヌティのプログラマヌにも誀解を䞎えるこずを理解する必芁がありたす。このコヌドにコメントを远加するず䟿利です。



マニフラむブラリ



マニフ ラむブラリの簡単な説明
manifは、ロボット工孊アプリケヌションを察象ずした状態掚定甚のヘッダヌのみのC ++ 11Lie理論ラむブラリです。
template <typename _Derived>
typename LieGroupBase<_Derived>::Scalar*
LieGroupBase<_Derived>::data()
{
  return derived().coeffs().data();
}

template <typename _Derived>
const typename LieGroupBase<_Derived>::Scalar*
LieGroupBase<_Derived>::data() const
{
  derived().coeffs().data(); // <=
}


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。lie_group_base.h 347



非定数関数は正しく実装されおいたすが、定数関数は正しく実装されおいたせん。それがどのように起こったかはさらに興味深いです...



FakeItラむブラリ



FakeIt ラむブラリの簡単な説明
FakeItは、C ++甚の単玔なモックフレヌムワヌクです。GCC、Clang、MS Visual C ++をサポヌトしおいたす。FakeItはC ++ 11で蚘述されおおり、C ++ 11プロゞェクトずC ++プロゞェクトの䞡方のテストに䜿甚できたす。
template<typename ... arglist>
struct ArgumentsMatcherInvocationMatcher :
         public ActualInvocation<arglist...>::Matcher {
  ....
  template<typename A>
  void operator()(int index, A &actualArg) {
      TypedMatcher<typename naked_type<A>::type> *matcher =
        dynamic_cast<TypedMatcher<typename naked_type<A>::type> *>(
          _matchers[index]);
      if (_matching)
        _matching = matcher->matches(actualArg);
  }
  ....
  const std::vector<Destructible *> _matchers;
};


PVS-Studio譊告V522朜圚的なヌルポむンタヌ「マッチャヌ」の逆参照がある可胜性がありたす。fakeit.hpp 6720マッチャヌ



ポむンタは、dynamic_cast挔算子によっお返される倀で初期化されたす。そしお、この挔算子はnullptrを返す可胜性があり、これは非垞にありそうなシナリオです。それ以倖の堎合は、dynamic_castの代わりにstatic_castを䜿甚する方が効率的です。



状態にタむプミスがある疑いがあり、実際には次のように曞く必芁がありたす。



if (matcher)
  _matching = matcher->matches(actualArg);


GuiLiteラむブラリ



GuiLite ラむブラリの簡単な説明
すべおのプラットフォヌム甚の最小のヘッダヌのみのGUIラむブラリ4 KLOC。
#define CORRECT(x, high_limit, low_limit)  {\
  x = (x > high_limit) ? high_limit : x;\
  x = (x < low_limit) ? low_limit : x;\
}while(0)

void refresh_wave(unsigned char frame)
{
  ....
  CORRECT(y_min, m_wave_bottom, m_wave_top);
  ....
}


PVS-Studio譊告V529奇数セミコロン ';' 'while'挔算子の埌。 GuiLite.h 3413



マクロの゚ラヌは、問題を匕き起こしたせん。しかし、それでも間違いなので、蚘事で説明するこずにしたした。



マクロで....ながら、叀兞的なパタヌンdo {...}を䜿甚するこずが蚈画されおいたした。これにより、1぀のブロックで耇数のアクションを実行するず同時に、関数呌び出しであるかのように、矎しさのためにマクロの埌にセミコロン ';'を曞き蟌むこずができたす。



しかし、怜蚎察象のマクロでは、誀っおdoキヌワヌドを曞くのを忘れおいたした。その結果、マクロは、いわば2぀の郚分に分割されたす。最初はブロックです。 2぀目は、空の非実行ルヌプです。while0; ..。



そしお、問題は䜕ですか



たずえば、このようなマクロは、次のような構造では䜿甚できたせん。



if (A)
  CORRECT(y_min, m_wave_bottom, m_wave_top);
else
  Foo();


このコヌドは次のように展開されるため、コンパむルされたせん。



if (A)
  { ..... }
while(0);
else
  Foo();


同意したす。このような問題は、䜿甚段階ではなく、ラむブラリ開発の段階で芋぀けお修正するこずをお勧めしたす。静的コヌド分析を適甚したす:)。





PpluXラむブラリ



PpluX ラむブラリの簡単な説明
スレッドのスケゞュヌリング、レンダリングなどのための単䞀ヘッダヌC ++ラむブラリ..。
struct DisplayList {
  DisplayList& operator=(DisplayList &&d) {
    data_ = d.data_;
    d.data_ = nullptr;
  }
  ....
}


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。px_render.h 398



ナニバヌサルラむブラリ



ナニバヌサルラむブラリの簡単な説明
Universal Numbersunumsの目暙は、IEEEフロヌティングポむントを、同時実行環境でより効率的で数孊的に䞀貫性のある数倀システムに眮き換えるこずです。
最初の間違い



template<typename Scalar>
vector<Scalar> operator*(double scalar, const vector<Scalar>& v) {
  vector<Scalar> scaledVector(v);
  scaledVector *= scalar;
  return v;
}


PVS-Studio譊告V1001'scaledVector '倉数が割り圓おられおいたすが、関数の最埌では䜿甚されおいたせん。vector.hpp124タむプミス



。元のベクトルvの代わりに、関数は新しいベクトル、scaledVectorを返す必芁がありたす。



同様のタむプミスがここに芋られたすV1001'normalizedVector '倉数が割り圓おられおいたすが、関数の終わりでは䜿甚されおいたせん。vector.hpp 1312



番目の゚ラヌ



template<typename Scalar>
class matrix {
  ....
  matrix& diagonal() {
  }
  ....
};


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。matrix.hpp 1093



番目の゚ラヌ



template<size_t fbits, size_t abits>
void module_subtract_BROKEN(
  const value<fbits>& lhs, const value<fbits>& rhs, value<abits + 1>& result)
{
  if (lhs.isinf() || rhs.isinf()) {
    result.setinf();
    return;
  }
  int lhs_scale = lhs.scale(),
      rhs_scale = rhs.scale(),
      scale_of_result = std::max(lhs_scale, rhs_scale);

  // align the fractions
  bitblock<abits> r1 =
    lhs.template nshift<abits>(lhs_scale - scale_of_result + 3);
  bitblock<abits> r2 =
    rhs.template nshift<abits>(rhs_scale - scale_of_result + 3);
  bool r1_sign = lhs.sign(), r2_sign = rhs.sign();
  //bool signs_are_equal = r1_sign == r2_sign;

  if (r1_sign) r1 = twos_complement(r1);
  if (r1_sign) r2 = twos_complement(r2);  // <=

  ....
}


PVS-Studio譊告V581互いに䞊んで配眮されおいる「if」ステヌトメントの条件匏は同じです。チェック行789、790。value.hpp790



コピヌアンドペヌストによっお匕き起こされる叀兞的な゚ラヌ。圌らは次の行を取り、乗算したした。



if (r1_sign) r1 = twos_complement(r1);


その䞭でr1をr2に倉曎したした



if (r1_sign) r2 = twos_complement(r2);


そしお、圌らはr1_signを倉曎するのを忘れおいたした。正しいオプション



if (r2_sign) r2 = twos_complement(r2);


Choboシングルヘッダヌラむブラリ



Choboシングルヘッダヌラむブラリの 簡単な説明
Chobolabsによる小さなシングルヘッダヌC ++ 11ラむブラリのコレクション。
最初の間違い



template <typename T, typename U, typename Alloc = std::allocator<T>>
class vector_view
{
  ....
  vector_view& operator=(vector_view&& other)
  {
    m_vector = std::move(other.m_vector);
  }
  ....
}


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。vector_view.hpp 1632



番目の゚ラヌ



template <typename UAlloc>
vector_view& operator=(const std::vector<U, UAlloc>& other)
{
  size_type n = other.size();
  resize(n);
  for (size_type i = 0; i < n; ++i)
  {
    this->at(i) = other[i];
  }
}


PVS-Studio譊告V591非void関数は倀を返す必芁がありたす。vector_view.hpp 184



ラむブラリPGM-むンデックス



PGMむンデックス ラむブラリの簡単な説明
Piecewise Geometric ModelむンデックスPGM-indexは、埓来のむンデックスよりも数桁少ないスペヌスを䜿甚しお、同じ最悪の堎合のク゚リ時間の保蚌を提䟛しながら、数十億のアむテムの配列で高速ルックアップ、先行、範囲怜玢、および曎新を可胜にするデヌタ構造です..。
最初の間違い



char* str_from_errno()
{
#ifdef MSVC_COMPILER
  #pragma warning(disable:4996)
  return strerror(errno);
#pragma warning(default:4996)
#else
  return strerror(errno);
#endif
}


PVS-Studio譊告V665おそらく、このコンテキストでは「#pragma譊告デフォルトX」の䜿甚法が正しくありたせん。代わりに、「pragma譊告プッシュ/ポップ」を䜿甚する必芁がありたす。チェック行9170、9172。sdsl.hpp9172



コンパむラの譊告を䞀時的に無効にするのが正しくありたせん。このような䞍正確さは、ナヌザヌコヌドにはどういうわけか蚱されたす。ただし、これはヘッダヌのみのラむブラリでは絶察に蚱可されおいたせん。



2番目の間違い



template<class t_int_vec>
t_int_vec rnd_positions(uint8_t log_s, uint64_t& mask,
                        uint64_t mod=0, uint64_t seed=17)
{
  mask = (1<<log_s)-1;         // <=
  t_int_vec rands(1<<log_s ,0);
  set_random_bits(rands, seed);
  if (mod > 0) {
    util::mod(rands, mod);
  }
  return rands;
}


PVS-Studioの譊告V629「1 << log_s」匏の怜査を怜蚎しおください。32ビット倀のビットシフトずそれに続く64ビットタむプぞの拡匵。sdsl.hpp 1350



正しいオプションの1぀



mask = ((uint64_t)(1)<<log_s)-1;


Hnswlibラむブラリ



Hnswlib ラむブラリの簡単な説明
Pythonバむンディングを䜿甚したヘッダヌのみのC ++ HNSW実装。HNSW 200MSIFT実隓甚の玙のコヌド。
template<typename dist_t>
class BruteforceSearch : public AlgorithmInterface<dist_t> {
public:
  BruteforceSearch(SpaceInterface <dist_t> *s, size_t maxElements) {
    maxelements_ = maxElements;
    data_size_ = s->get_data_size();
    fstdistfunc_ = s->get_dist_func();
    dist_func_param_ = s->get_dist_func_param();
    size_per_element_ = data_size_ + sizeof(labeltype);
    data_ = (char *) malloc(maxElements * size_per_element_);
    if (data_ == nullptr)
      std::runtime_error(
        "Not enough memory: BruteforceSearch failed to allocate data");
    cur_element_count = 0;
  }
  ....
}


PVS-Studio譊告V596オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。'throw'キヌワヌドが欠萜しおいる可胜性がありたすthrow runtime_errorFOO; bruteforce.h 26 std :: runtime_errorの



前にthrowステヌトメントを曞くのを忘れたした。 別のそのような゚ラヌV596オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。'throw'キヌワヌドが欠萜しおいる可胜性がありたすthrow runtime_errorFOO; bruteforce.h 161







tiny-dnnラむブラリ



tiny-dnnラむブラリの 簡単な説明
tiny-dnnは、深局孊習のC ++ 14実装です。限られた蚈算リ゜ヌス、組み蟌みシステム、IoTデバむスでの深い孊習に適しおいたす。
最初の間違い



class nn_error : public std::exception {
 public:
  explicit nn_error(const std::string &msg) : msg_(msg) {}
  const char *what() const throw() override { return msg_.c_str(); }

 private:
  std::string msg_;
};

inline Device::Device(device_t type, const int platform_id, const int device_id)
  : type_(type),
    has_clcuda_api_(true),
    platform_id_(platform_id),
    device_id_(device_id) {
  ....
#else
  nn_error("TinyDNN has not been compiled with OpenCL or CUDA support.");
#endif
}


PVS-Studio譊告V596オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。'throw'キヌワヌドが欠萜しおいる可胜性がありたすthrow nn_errorFOO; device.h 68



nn_errorは䟋倖をスロヌする関数ではなく、単なるクラスです。したがっお、次のように䜿甚するのが正しいです。



throw nn_error("TinyDNN has not been compiled with OpenCL or CUDA support.");


このクラスのもう1぀の誀甚V596オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。'throw'キヌワヌドが欠萜しおいる可胜性がありたすthrow nn_errorFOO; conv2d_op_opencl.h 1362



番目の゚ラヌ



inline std::string format_str(const char *fmt, ...) {
  static char buf[2048];

#ifdef _MSC_VER
#pragma warning(disable : 4996)
#endif
  va_list args;
  va_start(args, fmt);
  vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);
#ifdef _MSC_VER
#pragma warning(default : 4996)
#endif
  return std::string(buf);
}


PVS-Studio譊告V665おそらく、このコンテキストでは「#pragma譊告デフォルトX」の䜿甚法が正しくありたせん。代わりに、「pragma譊告プッシュ/ポップ」を䜿甚する必芁がありたす。チェックラむン139、146。util.h 146



Dlibラむブラリ



Dlib ラむブラリの簡単な説明
Dlibは、珟実䞖界の問題を解決するためにC ++で耇雑な゜フトりェアを䜜成するための機械孊習アルゎリズムずツヌルを含む最新のC ++ツヌルキットです。
最初の゚ラヌ



楜しみのために、この゚ラヌを自分で芋぀けおみおください。



class bdf_parser
{
public:

  enum bdf_enums
  {
    NO_KEYWORD = 0,
    STARTFONT = 1,
    FONTBOUNDINGBOX = 2,
    DWIDTH = 4,
    DEFAULT_CHAR = 8,
    CHARS = 16,
    STARTCHAR = 32,
    ENCODING = 64,
    BBX = 128,
    BITMAP = 256,
    ENDCHAR = 512,
    ENDFONT = 1024
  };
  ....
  bool parse_header( header_info& info )
  {
    ....
    while ( 1 )
    {
      res = find_keywords( find | stop );
      if ( res & FONTBOUNDINGBOX )
      {
          in_ >> info.FBBx >> info.FBBy >> info.Xoff >> info.Yoff;
          if ( in_.fail() )
              return false;    // parse_error
          find &= ~FONTBOUNDINGBOX;
          continue;
      }
      if ( res & DWIDTH )
      {
          in_ >> info.dwx0 >> info.dwy0;
          if ( in_.fail() )
              return false;    // parse_error
          find &= ~DWIDTH;
          info.has_global_dw = true;
          continue;
      }
      if ( res & DEFAULT_CHAR )
      {
          in_ >> info.default_char;
          if ( in_.fail() )
              return false;    // parse_error
          find &= ~DEFAULT_CHAR;
          continue;
      }
      if ( res & NO_KEYWORD )
          return false;    // parse_error: unexpected EOF
      break;
    }
  ....
};


それを芋぀けた



混乱したトラボルタ-ナニコヌン


圌女はここにいたす



if ( res & NO_KEYWORD )


PVS-Studio譊告V616倀0の「NO_KEYWORD」ずいう名前の定数がビット単䜍の操䜜で䜿甚されたす。fonts.cpp 288



名前付き定数NO_KEYWORDの倀は0です。したがっお、条件は無意味です。次のように曞くのが正しいでしょう



if ( res == NO_KEYWORD )


別の誀ったチェックがここにありたす。V616倀0の定数ずいう名前の「NO_KEYWORD」がビット単䜍の操䜜で䜿甚されたす。fonts.cpp 3342



番目の゚ラヌ



void set(std::vector<tensor*> items)
{
  ....
  epa.emplace_back(new enable_peer_access(*g[0], *g[i]));
  ....
}


PVS-Studio譊告V1023所有者のないポむンタヌが「emplace_back」メ゜ッドによっお「epa」コンテナヌに远加されたす。䟋倖が発生した堎合、メモリリヌクが発生したす。tensor_tools.h 1665



キャッチがどこにあるかを理解するために、V1023蚺断のドキュメントに粟通するこずを提案したす。



3番目の間違い



template <
    typename detection_type, 
    typename label_type 
    >
bool is_track_association_problem (
  const std::vector<
    std::vector<labeled_detection<detection_type,label_type> > >& samples
)
{
  if (samples.size() == 0)
    return false;

  unsigned long num_nonzero_elements = 0;
  for (unsigned long i = 0; i < samples.size(); ++i)
  {
    if (samples.size() > 0)
      ++num_nonzero_elements;
  }
  if (num_nonzero_elements < 2)
    return false;
  ....
}


PVS-Studioの譊告V547匏 'samples.size> 0'は垞にtrueです。svm.h 360



これは非垞に奇劙なコヌドですルヌプが開始されるず、条件samples.size> 0は垞に真になりたす。したがっお、ルヌプを簡略化できたす。



for (unsigned long i = 0; i < samples.size(); ++i)
{
  ++num_nonzero_elements;
}


その埌、ルヌプはたったく必芁ないこずが明らかになりたす。それははるかに簡単か぀効率的に曞くこずができたす



unsigned long num_nonzero_elements = samples.size();


しかし、それは行われる予定でしたかコヌドは明らかにプログラマヌによる泚意深い研究に倀したす。



4番目の間違い



class console_progress_indicator
{
  ....
  double seen_first_val;
  ....
};

bool console_progress_indicator::print_status (
  double cur, bool always_print)
{
  ....
  if (!seen_first_val)
  {
    start_time = cur_time;
    last_time = cur_time;
    first_val = cur;
    seen_first_val = true;  // <=
    return false;
  }
  ....
}


PVS-Studio譊告V601boolタむプは暗黙的にdoubleタむプにキャストされたす。console_progress_indicator.h 136倀trueは



、double型のクラスのメンバヌに曞き蟌たれたす。うヌん... 5番目の間違い







void file::init(const std::string& name)
{
  ....
  WIN32_FIND_DATAA data;
  HANDLE ffind = FindFirstFileA(state.full_name.c_str(), &data);
  if (ffind == INVALID_HANDLE_VALUE ||
      (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0)
  {
    throw file_not_found("Unable to find file " + name);                
  }
  else
  {
    ....
  } 
}


PVS-Studio譊告V773「ffind」ハンドルによっお参照されるファむルを閉じずに䟋倖がスロヌされたした。リ゜ヌスリヌクが発生する可胜性がありたす。dir_nav_kernel_1.cpp 60



ディレクトリが芋぀かるず、䟋倖がスロヌされたす。しかし、誰がハンドルを閉じたすか



6番目の間違い



もう䞀぀の非垞に奇劙な堎所。



inline double poly_min_extrap(double f0, double d0,
                              double x1, double f_x1,
                              double x2, double f_x2)
{
  ....
  matrix<double,2,2> m;
  matrix<double,2,1> v;

  const double aa2 = x2*x2;
  const double aa1 = x1*x1;
  m =  aa2,       -aa1,
      -aa2*x2, aa1*x1;   
  v = f_x1 - f0 - d0*x1,
      f_x2 - f0 - d0*x2;
  ....
}


PVS-Studio譊告V521 '、'挔算子を䜿甚したこのような匏は危険です。匏が正しいこずを確認しおください。Optimization_line_search.h211



マトリックスを初期化するようにスケゞュヌルされおいたす。ただし、これらすべおのaa2、f_x1、d0などは、double型の倉数にすぎたせん。これは、コンマがマトリックスの䜜成を目的ずした匕数を区切るのではなく、右偎の倀を返す通垞のコンマ挔算子であるこずを意味したす。



結論



蚘事の冒頭で、いく぀かの䟿利なものを䞀床に組み合わせる方法の䟋を瀺したした。静的アナラむザヌの䜿甚は、いく぀かの理由で同時に圹立ちたす。



  • トレヌニング。アナラむザヌの譊告を調べるこずで、倚くの新しくお䟿利なこずを孊ぶこずができたす。䟋memset、pragma warning、emplace_back、厳密に敎列。
  • タむプミス、バグ、朜圚的な脆匱性の早期発芋。
  • コヌドは埐々に良くなり、単玔になり、理解しやすくなっおいたす。
  • プロゞェクトを開発するずきは、誇りを持っお、最新のテクノロゞヌを䜿甚しおいるこずを党員に䌝えるこずができたす:)。そしお、これは郚分的にナヌモアです。これは真の競争䞊の利点です。


唯䞀の問題は、どのように開始するか、それを簡単に実装する方法、そしおそれを正しく䜿甚する方法です。次の蚘事はこれに圹立ちたす



  • CおよびC ++コヌド甚のPVS-Studioアナラむザヌによっお生成された興味深い譊告をすばやく衚瀺するにはどうすればよいですか
  • 静的コヌドアナラむザヌをレガシヌプロゞェクトに実装し、チヌムの意欲を削ぐ方法。
  • 静的分析をプロセスに導入したす。バグを探すのではありたせん。




この蚘事を英語を話す聎衆ず共有したい堎合は、翻蚳リンクを䜿甚しおくださいAndreyKarpov。ヘッダヌのみのC ++ラむブラリコレクションのチェックawesome-hpp。



All Articles