﻿# Checking a header\-only C\+\+ library collection \(awesome\-hpp\)

Somehow, we've happened to check most of the libraries making up a collection called "Awesome hpp"\. These are small header\-only projects in C\+\+\. Hopefully, the information about the bugs we've found will help make the libraries better\. We'll also be happy to see the developers use PVS\-Studio on a regular basis thanks to the free\-license option we provide\.

![0770_check_awesome_hpp/image1.png](https://import.viva64.com/docx/blog/0770_check_awesome_hpp/image1.png)

What follows is an overview of bugs found in the different libraries on the curated list of awesome header\-only C\+\+ libraries: [awesome\-hpp](https://github.com/p-ranav/awesome-hpp)\.

I learned about this list from the "[Cross Platform Mobile Telephony](https://cppcast.com/telephony-dave-hagedorn/)" podcast\. While we're at it, I recommend that all C\+\+ programmers check out [CppCast](https://cppcast.com/)\. It is the first podcast for C\+\+ developers by C\+\+ developers\!

Despite the large number of projects making up the list, bugs were few\. There are three reasons for that:

1. The projects are tiny\. Many literally consist of just a header file\.
1. We decided to skip some of the projects as they were too troublesome to compile\.
1. Often, you can't figure out whether template classes/functions have bugs in them until you have them instantiated\. Consequently, many of the bugs can be detected only in a real project that makes an active use of a library\. As for our analysis method, we simply included the headers into an empty \.cpp file and ran the check, which drastically limited its effectiveness\.

Even so, we've gathered enough warnings to write the article you are reading right now and a couple of additional ones\.

**A note for my teammates :\)\.** When I do something, I like to set and achieve a number of goals at once, and I urge you to follow my example\. After learning about the awesome\-hpp collection, I managed to accomplish the following useful tasks:

* set a task for our team to include into our test database a number of nice small modern projects based on the C\+\+11, C\+\+14, and C\+\+17 standards;
* wrote the article "[Why it is important to apply static analysis for open libraries that you add to your project](https://pvs-studio.com/en/blog/posts/cpp/0762/)";
* wrote the article "[Why code reviews are good, but not enough](https://pvs-studio.com/en/blog/posts/cpp/0761/)";
* wrote this article;
* outlined a future post about argument evaluation order \(see CSV Parser\);
* figured out a way to find out which of my teammates read my posts carefully\. If you have read this, drop by and get a prize – a chocolate bar or something like that :\);
* demonstrated with this example how to accomplish several tasks\.

**A note for library developers\.** You can use PVS\-Studio to check open\-source projects for free\. To get a free license to use with your open\-source project, please fill in this [form](https://pvs-studio.com/en/order/open-source-license/)\.

Okay, let's move on to our overview\.

## Bugs found

### iutest

Brief description of the [iutest](https://github.com/srz-zumix/iutest) library:

> iutest is framework for writing C\+\+ tests\.

```cpp
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 diagnostic message: [V1023](https://pvs-studio.com/en/docs/warnings/v1023/) A pointer without owner is added to the 'pools' container by the 'emplace\_back' method\. A memory leak will occur in case of an exception\. entt\.hpp 17114

This code may end up with a memory leak\. If the container needs reallocation and fails to allocate storage for a new array, it will throw an exception and the pointer will be lost\.

Well, when found in tests, this kind of bug isn't very critical and likely to occur, but I still had to mention it for educational purposes :\)\.

Fixed code:

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

Another problem spot: V1023 A pointer without owner is added to the 'pools' container by the 'emplace\_back' method\. A memory leak will occur in case of an exception\. entt\.hpp 17407

### jsoncons

Brief description of the [jsoncons](https://github.com/danielaparker/jsoncons) library:

> A C\+\+, header\-only library for constructing JSON and JSON\-like data formats, with JSON Pointer, JSON Patch, JSONPath, JMESPath, CSV, MessagePack, CBOR, BSON, UBJSON\.

**Bug 1**

```cpp
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 diagnostic message: [V629](https://pvs-studio.com/en/docs/warnings/v629/) Consider inspecting the '1 << k' expression\. Bit shifting of the 32\-bit value with a subsequent expansion to the 64\-bit type\. bigint\.hpp 744

This bug was already discussed in detail in the article "[Why it is important to apply static analysis for open libraries that you add to your project](https://pvs-studio.com/en/blog/posts/cpp/0762/)"\. In a nutshell, to get correct values of the mask, you should write the following:

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

Here's an alternative version:

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

Another similar bug was found here: [V629](https://pvs-studio.com/en/docs/warnings/v629/) Consider inspecting the '1 << k' expression\. Bit shifting of the 32\-bit value with a subsequent expansion to the 64\-bit type\. bigint\.hpp 779

**Bug 2**

```cpp
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 diagnostic message: [V571](https://pvs-studio.com/en/docs/warnings/v571/) Recurring check\. The 'if \(begin\_ \!\= last\_\)' condition was already verified in line 1138\. unicode\_traits\.hpp 1140

This is a strange duplicate check\. I suspect the second condition contains a typo and was meant to check some other value\.

### clipp

Brief description of the [clipp](https://github.com/muellan/clipp) library:

> clipp \- command line interfaces for modern C\+\+\. Easy to use, powerful and expressive command line argument handling for C\+\+11/14/17 contained in a single header file\.

```cpp
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 diagnostic message: [V547](https://pvs-studio.com/en/docs/warnings/v547/) Expression 's\[0\] \=\= '\-'' is always false\. clipp\.h 303

This one isn't actually a bug – just redundant code\. The element is checked twice for being the minus character\.

### SimpleIni

Brief description of the [SimpleIni](https://github.com/brofield/simpleini) library:

> A cross\-platform library that provides a simple API to read and write INI\-style configuration files\. It supports data files in ASCII, MBCS and Unicode\.

```cpp
#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
```

PVS\-Studio diagnostic message: [V1040](https://pvs-studio.com/en/docs/warnings/v1040/) Possible typo in the spelling of a pre\-defined macro name\. The '\_linux' macro is similar to '\_\_linux'\. SimpleIni\.h 2923

It seems an underscore is missing in the _\_linux_ macro's name: _\_\_linux_\. Anyway, this macro is deprecated in POSIX, so you should use _\_\_linux\_\__ instead\.

### CSV Parser

Brief description of the [CSV Parser](https://github.com/vincentlaucsb/csv-parser) library:

> A modern C\+\+ library for reading, writing, and analyzing CSV \(and similar\) files\.

```cpp
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 diagnostic message: [V769](https://pvs-studio.com/en/docs/warnings/v769/) The 'buffer\.get\(\)' pointer in the 'line\_buffer \- buffer\.get\(\)' expression equals nullptr\. The resulting value is senseless and it should not be used\. csv\.hpp 4957

It's an interesting case, which calls for careful investigation, so I decided to write a small separate [post about it](https://pvs-studio.com/en/blog/posts/cpp/0779/)\. Besides, while experimenting with similar code, I discovered a flaw in the code of PVS\-Studio itself :\)\. Because of that flaw, the analyzer will sometimes keep silent when it must issue a warning\.

In a nutshell, whether or not this code will work depends on the order of argument evaluation – and that depends on the compiler\.

### PPrint

Brief description of the [PPrint](https://github.com/p-ranav/pprint) library:

> Pretty Printer for Modern C\+\+\.

```cpp
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 diagnostic message: [V523](https://pvs-studio.com/en/docs/warnings/v523/) The 'then' statement is equivalent to the 'else' statement\. pprint\.hpp 715

It's very strange to have the same logic executed regardless of the check's result\. No clarifying comment is provided either\. It looks very much like a copy\-paste mistake\.

Similar warnings:

* V523 The 'then' statement is equivalent to the 'else' statement\. pprint\.hpp 780
* V523 The 'then' statement is equivalent to the 'else' statement\. pprint\.hpp 851
* V523 The 'then' statement is equivalent to the 'else' statement\. pprint\.hpp 927
* V523 The 'then' statement is equivalent to the 'else' statement\. pprint\.hpp 1012

### Strf

Brief description of the [Strf](https://github.com/robhz786/strf) library:

> A fast C\+\+ formatting library that supports encoding conversion\.

**Bug 1**

```cpp
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 diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. numpunct\.hpp 402

The "return \*this;" statement is missing at the end\.

**Bug 2 \(of the same nature\)**

```cpp
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 diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. numpunct\.hpp 528\.

### Indicators

Brief description of the [Indicators](https://github.com/p-ranav/indicators) library:

> Activity Indicators for Modern C\+\+\.

```cpp
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 diagnostic message: [V524](https://pvs-studio.com/en/docs/warnings/v524/) It is odd that the body of 'move\_down' function is fully equivalent to the body of 'move\_up' function\. indicators\.hpp 983

I'm not sure this one is an error, but the code is highly suspicious\. The developer must have copied the _move\_up_ function and changed the copy's name to _move\_down_ but forgotten to delete the minus character\. In any case, this snippet needs checking\.

**Note\.** If the code is correct, you should understand that it's going to confuse not only static analyzers but third\-party developers as well, who may want to use or develop it\. Make sure you leave a comment to clarify your point\.

### manif

Brief description of the [manif](https://github.com/artivis/manif) library:

> **manif** is a header\-only C\+\+11 Lie theory library for state\-estimation targeted at robotics applications\.

```cpp
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 diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. lie\_group\_base\.h 347

The non\-constant function is implemented properly, while the constant one is not\. I wonder how it came to be so\.\.\.

### FakeIt

Brief description of the [FakeIt](https://github.com/eranpeer/FakeIt) library:

> FakeIt is a simple mocking framework for C\+\+\. It supports GCC, Clang and MS Visual C\+\+\. FakeIt is written in C\+\+11 and can be used for testing both C\+\+11 and C\+\+ projects\.

```cpp
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 diagnostic message: [V522](https://pvs-studio.com/en/docs/warnings/v522/) There might be dereferencing of a potential null pointer 'matcher'\. fakeit\.hpp 6720

The _matcher_ pointer is initialized with the value returned by _dynamic\_cast_\. Yet that operator can return _nullptr,_ which is very likely\. Otherwise, use the more efficient _static\_cast _instead of _dynamic\_cast_\. 

I suspect the condition contains a typo and was actually meant to look like this:

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

### GuiLite

Brief description of the [GuiLite](https://github.com/idea4good/GuiLite) library:

> The smallest header\-only GUI library\(4 KLOC\) for all platforms\.

```cpp
#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 diagnostic message: [V529](https://pvs-studio.com/en/docs/warnings/v529/) Odd semicolon ';' after 'while' operator\. GuiLite\.h 3413

This error in the macro doesn't cause any specific problem, but it's still an error, so I included it\.

The macro was meant to use the classic pattern _do \{ \.\.\.\. \} while\(\.\.\.\.\)_\. This allows executing several operations in one block while enabling you to write a nice semicolon after the macro as if it were a function call\.

This macro, however, lacks the _do_ keyword\. As a result, it splits into two parts, so to speak: a block of code and an empty, never\-running _while_ _\(0\);_ loop\.

But why is it bad, actually?

Well, for one thing, you can't use this macro in constructs like this:

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

This code won't compile as it will expand into the following:

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

I think you'll agree that it's better to find and fix defects like that while the library is still in development than after the release\. To ensure this, use static analysis :\)\.

[![getTrialImageLink](https://wcdn.pvs-studio.com/media/get_trial_insert.png)](https://pvs-studio.com/en/pvs-studio-download/)

### PpluX

Brief description of the [PpluX](https://github.com/pplux/px) library:

> Single header C\+\+ Libraries for Thread Scheduling, Rendering, and so on\.\.\.

```cpp
struct DisplayList {
  DisplayList& operator=(DisplayList &&d) {
    data_ = d.data_;
    d.data_ = nullptr;
  }
  ....
}
```

PVS\-Studio diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. px\_render\.h 398

### Universal

Brief description of the Universal library:

> The goal of Universal Numbers, or unums, is to replace IEEE floating\-point with a number system that is more efficient and mathematically consistent in concurrent execution environments\.

**Bug 1**

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

PVS\-Studio diagnostic message: [V1001](https://pvs-studio.com/en/docs/warnings/v1001/) The 'scaledVector' variable is assigned but is not used by the end of the function\. vector\.hpp 124

This is a typo\. The function must return the new _scaledVector_ vector rather than the original _v_ vector\.

Another similar typo: V1001 The 'normalizedVector' variable is assigned but is not used by the end of the function\. vector\.hpp 131

**Bug 2**

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

PVS\-Studio diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. matrix\.hpp 109

**Bug 3**

```cpp
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 diagnostic message: [V581](https://pvs-studio.com/en/docs/warnings/v581/) The conditional expressions of the 'if' statements situated alongside each other are identical\. Check lines: 789, 790\. value\.hpp 790

It's a classic copy\-paste bug\. The programmer cloned the following line:

```cpp
if (r1_sign) r1 = twos_complement(r1);
```

Changed _r1_ to _r2_:

```cpp
if (r1_sign) r2 = twos_complement(r2);
```

But forgot to change _r1\_sign_\. Here's the correct version:

```cpp
if (r2_sign) r2 = twos_complement(r2);
```

### Chobo Single\-Header Libraries

Brief description of the [Chobo Single\-Header Libraries](https://github.com/Chobolabs/chobo-shl) library:

> A collection of small single\-header C\+\+11 libraries by Chobolabs\.

**Bug 1**

```cpp
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 diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. vector\_view\.hpp 163

**Bug 2**

```cpp
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 diagnostic message: [V591](https://pvs-studio.com/en/docs/warnings/v591/) Non\-void function should return a value\. vector\_view\.hpp 184

### PGM\-index

Brief description of the [PGM\-index](https://github.com/gvinciguerra/PGM-index) library:

> The Piecewise Geometric Model index \(PGM\-index\) is a data structure that enables fast lookup, predecessor, range searches and updates in arrays of billions of items using orders of magnitude less space than traditional indexes while providing the same worst\-case query time guarantees\.

**Bug 1**

```cpp
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 diagnostic message: [V665](https://pvs-studio.com/en/docs/warnings/v665/) Possibly, the usage of '\#pragma warning\(default: X\)' is incorrect in this context\. The '\#pragma warning\(push/pop\)' should be used instead\. Check lines: 9170, 9172\. sdsl\.hpp 9172

This code temporarily disables a compiler warning but does that in an incorrect way\. Such mistakes can be tolerated in user code, but certainly not in header\-only libraries\.

**Bug 2**

```cpp
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 diagnostic message: [V629](https://pvs-studio.com/en/docs/warnings/v629/) Consider inspecting the '1 << log\_s' expression\. Bit shifting of the 32\-bit value with a subsequent expansion to the 64\-bit type\. sdsl\.hpp 1350

Here's one correct version:

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

### Hnswlib

Brief description of the [Hnswlib](https://github.com/nmslib/hnswlib) library:

> Header\-only C\+\+ HNSW implementation with python bindings\. Paper's code for the HNSW 200M SIFT experiment\.

```cpp
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 diagnostic message: [V596](https://pvs-studio.com/en/docs/warnings/v596/) The object was created but it is not being used\. The 'throw' keyword could be missing: throw runtime\_error\(FOO\); bruteforce\.h 26

The _throw _operator is missing before _std::runtime\_error_\.

A similar problem: [V596](https://pvs-studio.com/en/docs/warnings/v596/) The object was created but it is not being used\. The 'throw' keyword could be missing: throw runtime\_error\(FOO\); bruteforce\.h 161

### tiny\-dnn

Brief description of the [tiny\-dnn](https://github.com/tiny-dnn/tiny-dnn) library:

> tiny\-dnn is a C\+\+14 implementation of deep learning\. It is suitable for deep learning on limited computational resource, embedded systems and IoT devices\.

**Bug 1**

```cpp
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 diagnostic message: [V596](https://pvs-studio.com/en/docs/warnings/v596/) The object was created but it is not being used\. The 'throw' keyword could be missing: throw nn\_error\(FOO\); device\.h 68

_nn\_error_ is not an exception\-throwing function but simply a class, and the correct way of using it is as follows:

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

Here's another case of improper use of this class: V596 The object was created but it is not being used\. The 'throw' keyword could be missing: throw nn\_error\(FOO\); conv2d\_op\_opencl\.h 136

**Bug 2**

```cpp
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 diagnostic message: [V665](https://pvs-studio.com/en/docs/warnings/v665/) Possibly, the usage of '\#pragma warning\(default: X\)' is incorrect in this context\. The '\#pragma warning\(push/pop\)' should be used instead\. Check lines: 139, 146\. util\.h 146

### Dlib

Brief description of the [Dlib](http://dlib.net/) library:

> Dlib is a modern C\+\+ toolkit containing machine learning algorithms and tools for creating complex software in C\+\+ to solve real world problems\.

**Bug 1**

To keep things interesting, I dare you to find the bug on your own\.

```cpp
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;
    }
  ....
};
```

Any luck?

![0770_check_awesome_hpp/image2.png](https://import.viva64.com/docx/blog/0770_check_awesome_hpp/image2.png)

Here it is:

```cpp
if ( res & NO_KEYWORD )
```

PVS\-Studio diagnostic message: [V616](https://pvs-studio.com/en/docs/warnings/v616/) The 'NO\_KEYWORD' named constant with the value of 0 is used in the bitwise operation\. fonts\.cpp 288

The value of the named constant _NO\_KEYWORD_ is 0\. Therefore, the condition doesn't make sense\. This is what the correct check should look like:

```cpp
if ( res == NO_KEYWORD )
```

Another incorrect check: V616 The 'NO\_KEYWORD' named constant with the value of 0 is used in the bitwise operation\. fonts\.cpp 334

**Bug 2**

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

PVS\-Studio diagnostic message: [V1023](https://pvs-studio.com/en/docs/warnings/v1023/) A pointer without owner is added to the 'epa' container by the 'emplace\_back' method\. A memory leak will occur in case of an exception\. tensor\_tools\.h 1665

To figure out what's wrong here, see the [V1023](https://pvs-studio.com/en/docs/warnings/v1023/) documentation\.

**Bug 3**

```cpp
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 diagnostic message: [V547](https://pvs-studio.com/en/docs/warnings/v547/) Expression 'samples\.size\(\) \> 0' is always true\. svm\.h 360

It's a very, very strange piece of code\! If the loop starts, then the _\(samples\.size\(\) \> 0\)_ condition is always true\. And that means the loop can be simplified:

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

But now it becomes clear that you don't need the loop at all\. The snippet could be rewritten in a much simpler and more efficient way:

```cpp
unsigned long num_nonzero_elements = samples.size();
```

But was it really the developer's intention? This code certainly needs close inspection\.

**Bug 4**

```cpp
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 diagnostic message: [V601](https://pvs-studio.com/en/docs/warnings/v601/) The bool type is implicitly cast to the double type\. console\_progress\_indicator\.h 136

The value _true_ is stored to a class member of type _double_\. Hmm\.\.\.\.

**Bug 5**

```cpp
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 diagnostic message: [V773](https://pvs-studio.com/en/docs/warnings/v773/) The exception was thrown without closing the file referenced by the 'ffind' handle\. A resource leak is possible\. dir\_nav\_kernel\_1\.cpp 60

An exception is thrown if the directory is found\. But how about closing the file handle?

**Bug 6**

Another extremely strange spot\.

```cpp
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 diagnostic message: [V521](https://pvs-studio.com/en/docs/warnings/v521/) Such expressions using the ',' operator are dangerous\. Make sure the expression is correct\. optimization\_line\_search\.h 211

The plan was to have the matrices initialized\. But all those _aa2_, _f\_x1_, _d0_, etc\. are simply variables of type _double_\. And that means the commas don't separate the arguments, which are used to form the matrices, but simply act as the [comma operator](https://en.wikipedia.org/wiki/Comma_operator), which returns the value of the right operand\.

## Conclusion

At the beginning of this article, I gave you an example of how you can pursue several goals at once\. Using a static analyzer is, too, beneficial for several reasons:

1. It helps you improve your qualification\. You learn lots of new and useful things while handling analyzer warnings\. For example, see [memset](https://pvs-studio.com/en/docs/warnings/v597/), [\#pragma warning](https://pvs-studio.com/en/docs/warnings/v665/), [emplace\_back](https://pvs-studio.com/en/docs/warnings/v1023/), [strictly aligned](https://pvs-studio.com/en/docs/warnings/v1032/)\.
1. Typos, mistakes, and potential vulnerabilities are detected at earlier development stages\. 
1. The code gradually grows more high\-quality, simple, and clear\.
1. You can feel proud and boast of using modern technologies in software development :\)\. Well, it's only half\-joke\. Static analysis does give you a significant competitive edge\.

The only question left is how to get started with static analysis, integrate it smoothly, and use it properly\. The following articles will give you all the answers you need:

1. [How to quickly check out interesting warnings given by the PVS\-Studio analyzer for C and C\+\+ code?](https://pvs-studio.com/en/blog/posts/cpp/0633/)
1. [How to introduce a static code analyzer in a legacy project and not to discourage the team](https://pvs-studio.com/en/blog/posts/0743/)\.
1. [ Introduce Static Analysis in the Process, Don't Just Search for Bugs with It](https://habr.com/en/post/440610/)\.