
Durch einen Schicksalsschlag haben wir die meisten Bibliotheken in der Sammlung "Awesome hpp" überprüft. Dies sind kleine C ++ - Projekte, die nur aus Header-Dateien bestehen. Hoffentlich helfen die gefundenen Fehler dabei, diese Bibliotheken ein wenig besser zu machen. Wir freuen uns auch, wenn ihre Autoren den PVS-Studio-Analysator regelmäßig kostenlos nutzen.
Ich mache Sie auf einen Überblick über die Ergebnisse der Überprüfung verschiedener Bibliotheken aufmerksam, die in der Liste awesome-hpp (Eine kuratierte Liste fantastischer C ++ - Bibliotheken nur für Header) aufgeführt sind.
Diese Liste habe ich zum ersten Mal aus dem Podcast " Cross Platform Mobile Telephony " kennengelernt . Bei dieser Gelegenheit empfehle ich allen C ++ - Programmierern, sich mit CppCast vertraut zu machen . CppCast ist der erste Podcast für C ++ - Entwickler von C ++ - Entwicklern!
Trotz der großen Anzahl von Projekten auf der Liste gab es nur sehr wenige Fehler. Dafür gibt es drei Gründe:
- Dies sind sehr kleine Projekte. Viele bestehen buchstäblich aus einer einzigen Header-Datei.
- Wir haben nicht alle Projekte überprüft. Es gab Probleme bei der Zusammenstellung einiger von ihnen und wir beschlossen, sie zu überspringen.
- Um zu verstehen, ob Fehler in Vorlagenklassen / -funktionen vorliegen oder nicht, müssen diese häufig instanziiert werden. Dementsprechend können viele Fehler vom Analysator nur in einem realen Projekt erkannt werden, wenn die Bibliothek aktiv verwendet wird. Wir haben gerade die Header-Dateien in eine leere CPP-Datei aufgenommen und überprüft, wodurch die Überprüfung unwirksam wird.
Während des Studiums der Warnungen gab es jedoch genug davon, um diesen Artikel und einige weitere zu schreiben.
Hinweis an meine Kollegen
Hinweis für Bibliotheksentwickler. Interessenten können den PVS-Studio Analyzer kostenlos nutzen, um Open Source-Projekte zu überprüfen. Um eine Lizenz für Ihr Open Source-Projekt zu erhalten, füllen Sie bitte dieses Formular aus .
Schauen wir uns nun endlich an, was in einigen Bibliotheken gefunden wurde.
Fehler gefunden
Iutest Bibliothek
Kurzbeschreibung der aktuellsten Bibliothek :
iutest ist ein Framework zum Schreiben von C ++ - Tests.
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- Warnung : V1023 Ein Zeiger ohne Eigentümer wird durch die Methode 'emplace_back' zum Container 'pools' hinzugefügt. Im Ausnahmefall tritt ein Speicherverlust auf. entt.hpp 17114
Dieser Code kann zu Speicherverlusten führen. Wenn der Container eine Neuzuweisung benötigt und keinen Speicher für ein neues Array zuweisen kann, wird eine Ausnahme ausgelöst und der Zeiger geht verloren.
Für Tests ist diese Situation möglicherweise unwahrscheinlich und nicht kritisch. Ich habe mich jedoch entschlossen, dieses Manko zu Bildungszwecken zu erwähnen :).
Richtige Option:
pools.emplace_back(std::make_unique<pool_handler<Event>>{})
Ein weiterer ähnlicher Ort: V1023 Ein Zeiger ohne Eigentümer wird durch die Methode 'emplace_back' zum Container 'pools' hinzugefügt. Im Ausnahmefall tritt ein Speicherverlust auf. entt.hpp 17407
Jsoncons Bibliothek
Eine kurze Beschreibung der jsoncons- Bibliothek :
Eine C ++ - Nur-Header-Bibliothek zum Erstellen von JSON- und JSON-ähnlichen Datenformaten mit JSON-Zeiger, JSON-Patch, JSONPath, JMESPath, CSV, MessagePack, CBOR, BSON, UBJSON.Der erste Fehler
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- Warnung : V629 Überprüfen Sie den Ausdruck '1 << k'. Bitverschiebung des 32-Bit-Werts mit anschließender Erweiterung auf den 64-Bit-Typ. bigint.hpp 744
Dieser Fehler wurde bereits im Artikel " Warum es wichtig ist, statische Analysen von Open Source-Bibliotheken durchzuführen, die Sie Ihrem Projekt hinzufügen " ausführlich besprochen . Kurz gesagt, um die richtigen Maskenwerte zu erhalten, müssen Sie wie folgt schreiben:
uint64_t mask = (static_cast<uint64_t>(1) << k) - 1;
Oder so:
uint64_t mask = (1ull << k) - 1;
Der exakt gleiche Fehler wie beim ersten ist hier zu sehen: V629 Überprüfen Sie den Ausdruck '1 << k'. Bitverschiebung des 32-Bit-Werts mit anschließender Erweiterung auf den 64-Bit-Typ. bigint.hpp 779
Zweiter Fehler
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- Warnung : V571 Wiederkehrende Prüfung. Die Bedingung 'if (begin_! = Last_)' wurde bereits in Zeile 1138 überprüft. Unicode_traits.hpp 1140
Seltsamer Wiederholungstest . Es besteht der Verdacht, dass hier ein Tippfehler vorliegt und die zweite Bedingung etwas anders aussehen sollte.
Clipp Bibliothek
Eine kurze Beschreibung der Clipp- Bibliothek :
clipp - Befehlszeilenschnittstellen für modernes C ++. Einfach zu bedienende, leistungsstarke und aussagekräftige Befehlszeilenargumentbehandlung für C ++ 14.11.17 in einer einzigen Header-Datei.
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- Warnung : V547 Ausdruck 's [0] ==' - '' ist immer falsch. clipp.h 303
Nun, in der Tat ist dies kein Fehler, sondern einfach redundanter Code. Die Minusprüfung wird zweimal durchgeführt.
SimpleIni-Bibliothek
Eine kurze Beschreibung der SimpleIni- Bibliothek :
Eine plattformübergreifende Bibliothek, die eine einfache API zum Lesen und Schreiben von Konfigurationsdateien im INI-Stil bietet. Es unterstützt Datendateien in ASCII, MBCS und Unicode.
#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
PVS-Studio- Warnung : V1040 Möglicher Tippfehler bei der Schreibweise eines vordefinierten Makronamens . Das Makro '_linux' ähnelt '__linux'. SimpleIni.h 2923
Wahrscheinlich fehlt dem Namen des _linux- Makros ein Unterstrich, und der Name __linux sollte verwendet werden . In POSIX ist dieses Makro jedoch veraltet und es ist besser, __linux__ zu verwenden .
CSV-Parser-Bibliothek
Eine kurze Beschreibung der CSV-Parser- Bibliothek :
Eine moderne C ++ - Bibliothek zum Lesen, Schreiben und Analysieren von CSV-Dateien (und ähnlichen Dateien).
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- Warnung : V769 Der Zeiger 'buffer.get ()' im Ausdruck 'line_buffer - buffer.get ()' entspricht nullptr. Der resultierende Wert ist sinnlos und sollte nicht verwendet werden. csv.hpp 4957
Eine interessante Situation, die sorgfältige Überlegungen erfordert. Deshalb habe ich beschlossen, eine separate kleine Notiz darüber zu schreiben. Außerdem habe ich beim Experimentieren mit ähnlichem Code einen Fehler in PVS-Studio selbst gefunden :). In einigen Fällen ist es still, obwohl es Warnungen ausgeben sollte.
Kurz gesagt, ob dieser Code funktioniert oder nicht, hängt von der Reihenfolge ab, in der die Argumente ausgewertet werden. Die Reihenfolge, in der die Argumente ausgewertet werden, hängt vom Compiler ab.
PPrint-Bibliothek
Kurzbeschreibung der Bibliothek PPRINT :.
Hübscher Drucker für modernes 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- Warnung : V523 Die Anweisung 'then' entspricht der Anweisung 'else'. pprint.hpp 715
Es ist sehr seltsam, dass dieselbe Aktion unabhängig von der Bedingung ausgeführt wird. Es gibt auch keinen speziellen erklärenden Kommentar. Dies alles ist dem Fehler Kopieren-Einfügen sehr ähnlich.
Ähnliche Warnungen:
- V523 Die Anweisung 'then' entspricht der Anweisung 'else'. pprint.hpp 780
- V523 Die Anweisung 'then' entspricht der Anweisung 'else'. pprint.hpp 851
- V523 Die Anweisung 'then' entspricht der Anweisung 'else'. pprint.hpp 927
- V523 Die Anweisung 'then' entspricht der Anweisung 'else'. pprint.hpp 1012
Strf Bibliothek
Eine kurze Beschreibung der Strf- Bibliothek :
Eine schnelle C ++ - Formatierungsbibliothek, die die Codierungskonvertierung unterstützt.Der erste Fehler
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- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. numpunct.hpp 402
Wir haben vergessen, am Ende der Funktion "return * this;" zu schreiben.
Der zweite ähnliche Fehler
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- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. numpunct.hpp 528.
Indikatorbibliothek
Kurzbeschreibung der Indikatorbibliothek :
Aktivitätsindikatoren für modernes 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- Warnung : V524 Es ist merkwürdig, dass der Hauptteil der Funktion 'move_down' dem Hauptteil der Funktion 'move_up' vollständig entspricht. Indikatoren.hpp 983
Ich bin nicht sicher, ob dies ein Fehler ist. Aber der Code ist sehr verdächtig. Es ist sehr wahrscheinlich, dass die Funktion move_up kopiert und ihr Name in move_down geändert wurde . Aber sie haben vergessen, das Minus zu entfernen. Es lohnt sich, diesen Code zu überprüfen.
Hinweis. Wenn der Code korrekt ist, müssen Sie verstehen, dass er nicht nur Codeanalysatoren, sondern auch Programmierer von Drittanbietern, die diesen Code verwenden oder entwickeln möchten, in die Irre führt. Es ist nützlich, diesem Code Kommentare hinzuzufügen.
Manif Bibliothek
Eine kurze Beschreibung der Manifest- Bibliothek :
manifest ist eine reine Header-C ++ 11 Lie-Theoriebibliothek zur Zustandsschätzung für Robotikanwendungen.
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- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. lie_group_base.h 347 Die
nicht konstante Funktion ist korrekt implementiert, die konstante Funktion jedoch nicht. Es ist sogar interessant, wie es passiert ist ...
FakeIt-Bibliothek
Eine kurze Beschreibung der FakeIt- Bibliothek :
FakeIt ist ein einfaches Mocking-Framework für C ++. Es unterstützt GCC, Clang und MS Visual C ++. FakeIt ist in C ++ 11 geschrieben und kann zum Testen von C ++ 11- und C ++ - Projekten verwendet werden.
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- Warnung : V522 Möglicherweise wird ein potenzieller Nullzeiger 'Matcher' dereferenziert. fakeit.hpp 6720
Der Matcher- Zeiger wird mit dem vom Operator dynamic_cast zurückgegebenen Wert initialisiert . Dieser Operator kann nullptr zurückgeben, und dies ist ein sehr wahrscheinliches Szenario. Andernfalls ist es effizienter, static_cast anstelle von dynamic_cast zu verwenden . Es besteht der Verdacht, dass der Zustand einen Tippfehler enthält, und tatsächlich sollte er geschrieben werden:
if (matcher)
_matching = matcher->matches(actualArg);
GuiLite-Bibliothek
Eine kurze Beschreibung der GuiLite- Bibliothek :
Die kleinste Nur-Header-GUI-Bibliothek (4 KLOC) für alle Plattformen.
#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- Warnung : V529 Ungerades Semikolon ';' nach 'while'-Operator. GuiLite.h 3413
Ein Fehler in einem Makro führt nicht zu einem Problem. Aber es ist immer noch ein Fehler, deshalb habe ich beschlossen, ihn im Artikel zu beschreiben.
Es war geplant, das klassische Muster do {...} while (....) im Makro zu verwenden . Auf diese Weise können Sie mehrere Aktionen in einem Block ausführen und gleichzeitig ein Semikolon ';' nach dem Makro für Schönheit schreiben, als wäre es ein Funktionsaufruf.
In dem betrachteten Makro haben sie jedoch versehentlich vergessen, das Schlüsselwort do zu schreiben . Infolgedessen schien das Makro in zwei Teile geteilt zu sein. Der erste ist der Block. Die zweite ist eine leere, nicht laufende Schleife: while (0); ...
Und was ist das Problem?
Ein solches Makro kann beispielsweise nicht in einer Konstruktion wie der folgenden verwendet werden:
if (A)
CORRECT(y_min, m_wave_bottom, m_wave_top);
else
Foo();
Dieser Code wird nicht kompiliert, da er erweitert wird in:
if (A)
{ ..... }
while(0);
else
Foo();
Stimmen Sie zu, es ist besser, ein solches Problem in der Phase der Bibliotheksentwicklung zu finden und zu beheben, und nicht in der Phase seiner Verwendung. Statische Code-Analyse anwenden :).

PpluX-Bibliothek
Kurzbeschreibung der PpluX- Bibliothek :
Einzelne Header-C ++ - Bibliotheken für die Thread-Planung, das Rendern usw.
struct DisplayList {
DisplayList& operator=(DisplayList &&d) {
data_ = d.data_;
d.data_ = nullptr;
}
....
}
PVS-Studio- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. px_render.h 398
Universelle Bibliothek
Eine kurze Beschreibung der Universalbibliothek:
Das Ziel von Universal Numbers oder Unums ist es, IEEE-Gleitkomma durch ein Zahlensystem zu ersetzen, das in Umgebungen mit gleichzeitiger Ausführung effizienter und mathematisch konsistenter ist.Der erste Fehler
template<typename Scalar>
vector<Scalar> operator*(double scalar, const vector<Scalar>& v) {
vector<Scalar> scaledVector(v);
scaledVector *= scalar;
return v;
}
PVS-Studio- Warnung : V1001 Die Variable 'scaledVector' wird zugewiesen, aber am Ende der Funktion nicht verwendet. vector.hpp 124 Tippfehler
. Anstelle des ursprünglichen Vektors v muss die Funktion einen neuen Vektor, scaledVector , zurückgeben .
Ein ähnlicher Tippfehler ist hier zu sehen: V1001 Die Variable 'normalizedVector' wird zugewiesen, aber am Ende der Funktion nicht verwendet. vector.hpp 131
Zweiter Fehler
template<typename Scalar>
class matrix {
....
matrix& diagonal() {
}
....
};
PVS-Studio- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. matrix.hpp 109
Dritter Fehler
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- Warnung : V581 Die bedingten Ausdrücke der nebeneinander angeordneten if-Anweisungen sind identisch. Überprüfen Sie die Zeilen: 789, 790. value.hpp 790
Ein klassischer Fehler , der durch Kopieren und Einfügen verursacht wird. Sie nahmen und multiplizierten die Linie:
if (r1_sign) r1 = twos_complement(r1);
Wir haben darin r1 in r2 geändert :
if (r1_sign) r2 = twos_complement(r2);
Und sie haben vergessen, r1_sign zu ändern . Richtige Option:
if (r2_sign) r2 = twos_complement(r2);
Chobo-Einzelkopfbibliotheken
Eine kurze Beschreibung der Chobo Single-Header-Bibliotheken :
Eine Sammlung kleiner C ++ 11-Bibliotheken mit einem Header von Chobolabs.Der erste Fehler
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- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. vector_view.hpp 163
Zweiter Fehler
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- Warnung : Die Funktion V591 Non-void sollte einen Wert zurückgeben. vector_view.hpp 184
Bibliothek PGM-Index
Kurzbeschreibung der PGM-Indexbibliothek :
Der Piecewise Geometric Model Index (PGM-Index) ist eine Datenstruktur, die eine schnelle Suche, Vorgänger-, Bereichssuche und Aktualisierung in Arrays von Milliarden von Elementen mit um Größenordnungen weniger Speicherplatz als herkömmliche Indizes ermöglicht und gleichzeitig die gleichen Garantien für die Abfragezeit im ungünstigsten Fall bietet ...Der erste Fehler
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- Warnung : V665 Möglicherweise ist die Verwendung der '# Pragma-Warnung (Standard: X)' in diesem Zusammenhang falsch. Stattdessen sollte die '# Pragma-Warnung (Push / Pop)' verwendet werden. Überprüfen Sie die Zeilen: 9170, 9172. sdsl.hpp 9172
Falsche Warnung zum vorübergehenden Deaktivieren des Compilers. Solche Ungenauigkeiten sind für den Benutzercode irgendwie verzeihbar. Dies ist jedoch in Nur-Header-Bibliotheken definitiv nicht zulässig.
Zweiter Fehler
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- Warnung : V629 Überprüfen Sie den Ausdruck '1 << log_s'. Bitverschiebung des 32-Bit-Werts mit anschließender Erweiterung auf den 64-Bit-Typ. sdsl.hpp 1350
Eine der richtigen Optionen:
mask = ((uint64_t)(1)<<log_s)-1;
Hnswlib Bibliothek
Eine kurze Beschreibung der Hnswlib- Bibliothek :
Nur-Header-C ++ - HNSW-Implementierung mit Python-Bindungen. Papiercode für das HNSW 200M SIFT-Experiment.
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- Warnung : V596 Das Objekt wurde erstellt, wird jedoch nicht verwendet. Das Schlüsselwort 'throw' könnte fehlen: throw runtime_error (FOO); bruteforce.h 26 Ich habe
vergessen , eine throw- Anweisung vor std :: runtime_error zu schreiben . Ein weiterer solcher Fehler: V596 Das Objekt wurde erstellt, wird aber nicht verwendet. Das Schlüsselwort 'throw' könnte fehlen: throw runtime_error (FOO); bruteforce.h 161
Die winzige Bibliothek
Eine kurze Beschreibung der tiny-dnn-Bibliothek :
tiny-dnn ist eine C ++ 14-Implementierung von Deep Learning. Es eignet sich für tiefes Lernen auf begrenzten Rechenressourcen, eingebetteten Systemen und IoT-Geräten.Der erste Fehler
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- Warnung : V596 Das Objekt wurde erstellt, wird jedoch nicht verwendet. Das Schlüsselwort 'throw' könnte fehlen: throw nn_error (FOO); device.h 68
nn_error ist keine Funktion, die eine Ausnahme auslöst , sondern nur eine Klasse. Daher ist es richtig, es so zu verwenden:
throw nn_error("TinyDNN has not been compiled with OpenCL or CUDA support.");
Ein weiterer Missbrauch dieser Klasse: V596 Das Objekt wurde erstellt, wird aber nicht verwendet. Das Schlüsselwort 'throw' könnte fehlen: throw nn_error (FOO); conv2d_op_opencl.h 136
Zweiter Fehler
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- Warnung : V665 Möglicherweise ist die Verwendung der '# Pragma-Warnung (Standard: X)' in diesem Zusammenhang falsch. Stattdessen sollte die '# Pragma-Warnung (Push / Pop)' verwendet werden. Überprüfen Sie die Zeilen: 139, 146. util.h 146
Dlib-Bibliothek
Eine kurze Beschreibung der Dlib- Bibliothek :
Dlib ist ein modernes C ++ - Toolkit, das Algorithmen und Tools für maschinelles Lernen zum Erstellen komplexer Software in C ++ zur Lösung realer Probleme enthält.Erster Fehler
Versuchen Sie zum Spaß, diesen Fehler selbst zu finden.
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;
}
....
};
Fand es?

Sie ist da:
if ( res & NO_KEYWORD )
PVS-Studio- Warnung : V616 Die benannte Konstante 'NO_KEYWORD' mit dem Wert 0 wird in der bitweisen Operation verwendet. fonts.cpp 288 Die
benannte Konstante NO_KEYWORD hat den Wert 0. Daher ist die Bedingung bedeutungslos. Es wäre richtig zu schreiben:
if ( res == NO_KEYWORD )
Eine weitere falsche Prüfung wird hier gefunden: V616 Die Konstante 'NO_KEYWORD' mit dem Wert 0 wird in der bitweisen Operation verwendet. fonts.cpp 334
Zweiter Fehler
void set(std::vector<tensor*> items)
{
....
epa.emplace_back(new enable_peer_access(*g[0], *g[i]));
....
}
PVS-Studio- Warnung : V1023 Ein Zeiger ohne Eigentümer wird dem 'epa'-Container durch die' emplace_back'-Methode hinzugefügt. Im Ausnahmefall tritt ein Speicherverlust auf. tensor_tools.h 1665
Um zu verstehen, wo sich der Haken befindet, sollten Sie sich mit der Dokumentation für die V1023- Diagnose vertraut machen .
Dritter Fehler
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- Warnung : V547 Ausdruck 'samples.size ()> 0' ist immer wahr. svm.h 360
Das ist sehr, sehr seltsamer Code! Wenn eine Schleife startet, ist die Bedingung (samples.size ()> 0) immer wahr. Daher kann die Schleife vereinfacht werden:
for (unsigned long i = 0; i < samples.size(); ++i)
{
++num_nonzero_elements;
}
Danach wird klar, dass die Schleife überhaupt nicht benötigt wird. Es kann viel einfacher und effizienter geschrieben werden:
unsigned long num_nonzero_elements = samples.size();
Aber war es geplant, getan zu werden? Der Code verdient eindeutig eine sorgfältige Prüfung durch einen Programmierer.
Der vierte Fehler
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- Warnung : V601 Der Bool- Typ wird implizit in den Double-Typ umgewandelt. console_progress_indicator.h 136
Der Wert true wird in ein Mitglied der Klasse vom Typ double geschrieben . Hmm ... Fünfter Fehler
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- Warnung : V773 Die Ausnahme wurde ausgelöst, ohne die Datei zu schließen, auf die das Handle 'ffind' verweist. Ein Ressourcenleck ist möglich. dir_nav_kernel_1.cpp 60
Wenn ein Verzeichnis gefunden wird, wird eine Ausnahme ausgelöst. Aber wer wird den Griff schließen?
Der sechste Fehler
Ein weiterer sehr seltsamer Ort.
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- Warnung : V521 Solche Ausdrücke mit dem Operator ',' sind gefährlich. Stellen Sie sicher, dass der Ausdruck korrekt ist. Optimization_line_search.h 211
Geplant zum Initialisieren von Matrizen. Aber alle diese AA2 , f_x1 , d0 und so weiter sind nur Variablen des Doppel Typ . Dies bedeutet, dass die Kommas nicht die Argumente trennen, die zum Erstellen von Matrizen vorgesehen sind, sondern gewöhnliche Kommaoperatoren sind , die den Wert der rechten Seite zurückgeben.
Fazit
Am Anfang des Artikels habe ich ein Beispiel gegeben, wie Sie mehrere nützliche Dinge gleichzeitig kombinieren können. Die Verwendung eines statischen Analysators ist aus mehreren Gründen gleichzeitig nützlich:
- Die Weiterbildung. Wenn Sie die Warnungen des Analysators studieren, können Sie viele neue und nützliche Dinge lernen. Beispiele: Memset , # Pragma-Warnung , emplace_back , streng ausgerichtet .
- Früherkennung von Tippfehlern, Fehlern und potenziellen Schwachstellen.
- Der Code wird allmählich besser, einfacher und verständlicher.
- Sie können stolz sein und allen sagen, dass Sie bei der Entwicklung von Projekten moderne Technologien verwenden :). Und das ist nur teilweise Humor. Dies ist ein echter Wettbewerbsvorteil.
Die Frage ist nur, wie man anfängt, wie man es schmerzlos implementiert und wie man es richtig benutzt. Die folgenden Artikel helfen Ihnen dabei:
- Wie kann man schnell interessante Warnungen anzeigen, die vom PVS-Studio Analyzer für C- und C ++ - Code generiert wurden?
- So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt und demotivieren das Team nicht .
- Führen Sie statische Analysen in Ihren Prozess ein, anstatt nach Fehlern zu suchen .

Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Übersetzungslink: Andrey Karpov. Überprüfen einer C ++ - Bibliothekssammlung nur für Header (awesome-hpp) .