2017-08-28 2 views
0

Ich verwende PVS-Studio für mein Projekt Torrent File Editor. Es gibt ein falsch positives Ergebnis. Here kein wirkliches Problem, aber ich bekomme solche Fehler:Falsch positiv V595 Der '_parent'-Zeiger wurde verwendet, bevor er mit nullptr verifiziert wurde

torrent-file-editor/abstracttreenode.h:138: error: V595 The '_parent' pointer was utilized before it was verified against nullptr. Check lines: 138, 139.

Code-Snippet:

inline T *sibling(int row) const 
{ 
    Q_ASSERT(_parent); 
    Q_ASSERT(row < _parent->childCount()); // -V595 PVS-Studio 
    return _parent ? _parent->child(row) : nullptr; 
} 

Hier Q_ASSERT ist nur Debug-Versionsprüfung. Eine solche Prüfung wird in der Release-Version nicht ausgeführt. Für Release verwende ich _parent ? ... : ..., um einen möglichen Absturz zu verhindern. Es ist also völlig in Ordnung, dass die Überprüfung in der Debug-Version dupliziert wurde.

Ich unterdrücke diese falsch positive mit speziellen Kommentar. Das ist also kein Problem, aber denken Sie, dass PVS-Studio diesen Fall behandeln sollte.

+0

Funktioniert es mit assert()? Ich erinnere mich, dass der statische Analysator von LLVM auch mit Q_ASSERT –

+0

mit assert() gleich verwechselt wurde. –

+0

Was ist, wenn: 'return _parent! = Nullptr? _parent-> Kind (Zeile): nullptr; '? – AlexanderVX

Antwort

1

V595 Diagnose Logik ist einfach. Eine Warnung wird ausgegeben, wenn am Anfang ein Zeiger dereferenziert wird und dann auf Gleichheit mit nullptr überprüft wird.

Natürlich gibt es eine Reihe von Situationen, in denen der Analysator ruhig sein wird und ein solches Muster erreicht hat. Wenn der Zeiger nicht ungleich nullptr ist, wird der Analysator ruhig bleiben.

Die Q_ASSERT(_parent) garantiert jedoch nicht, dass der Zeiger _parent ungleich Null ist. Wenn _parent Null ist, gibt die Q_ASSERT-Anweisung die folgende Meldung unter Verwendung der -Funktion aus. Wenn Sie den Standard-Message-Handler verwenden, wird diese Funktion zum Erstellen eines Core-Dumps abbrechen.

Sie können Ihren eigenen Handler installieren, der das Programm weiterhin ausführt. Also theoretisch hat der Analysator recht. Eine mögliche Dereferenzierung eines Nullzeigers kann auftreten.

Wir sind keine Theoretiker, sondern Praxen und wir erkennen, dass dieser Code als richtig angesehen werden sollte. Der Analyzer ist mit dieser Codeansicht nicht vertraut, in der das Makro Q_ASSERT noch verwendet wird. Wir werden den Analysator so modifizieren, dass er solche Code-Muster als richtig wahrnimmt. I.e. in Zukunft Analysator davon aus, dass hier:

Q_ASSERT(_parent); 
Q_ASSERT(row < _parent->childCount()); 

_parent->childCount() Funktionsaufruf nie ausgeführt wird, wenn der Zeiger _parent gleich nullptr. Wenn der Zeiger NULL ist, wird das Programm früher wegen dem Aufrufen von qFatal() nicht mehr funktionieren.

Natürlich, wie ich bereits oben gesagt habe, können Sie das Verhalten des Handlers ändern und es wird kein Abbruchprogramm verursachen. In der Praxis wird jedoch niemand den Handler ändern und einen solchen Code schreiben, den wir hier betrachten.

Dies könnte der Endpunkt der Antwort sein. Also, wir werden den Analysator verbessern und das ist alles. Es ist jedoch unmöglich, alle möglichen Optionen vorherzusehen. Wie kann man eine Warnung unterdrücken, wenn es unser eigenes Makro ist?

Nehmen wir an, dass dieses selbst erstellte Fehlerprotokollierungssystem und der Analysator nichts über die benutzerdefinierte Funktion Foo() wissen.

void Foo(bool expr); 
#define Q_ASSERT(expr) Foo(expr); 

inline T *sibling(int row) const 
{ 
    Q_ASSERT(_parent); 
    Q_ASSERT(row < _parent->childCount()) 
    return _parent ? _parent->child(row) : nullptr; 
} 

Die einfachste, aber nicht der beste Weg ist explizit als falsch-Kennzeichen-Warnung zu verwendet Kommentare:

Q_ASSERT(row < _parent->childCount()) //-V595 

Eine andere Möglichkeit ist es, den Stil des Schreibens Code zu ändern und schreiben, wie folgt:

inline T *sibling(int row) const 
{ 
    if (_parent == nullptr) 
    { 
    Q_ASSERT(false); 
    return nullptr; 
    } 
    Q_ASSERT(row < _parent->childCount()); 
    return _parent->child(row); 
} 

Für diesen Code gibt der Analysator keine Warnung V595 aus, da es keinen Grund dafür gibt. Der Code wurde etwas länger, aber meiner Meinung nach ist er jetzt logischer korrekt und sicherer. Ich empfehle diese Art des Umgangs mit dieser Art von Warnungen.

Und die letzte ist die Verwendung von Warnungen Unterdrückung Mechanismus in Makros. Um dies in der Header-Datei, wo das Makro definiert ist, zu tun, sollten Sie einen Kommentar schreiben:

Nach dieser Warnungen werden verschwinden. Natürlich ist es nicht immer möglich, die Datei zu ändern, in der das Makro deklariert ist. Dann können Sie eine der globalen Dateien verwenden. In Visual C++ - Projekten ist der stdafx.h ein guter Kandidat. Eine weitere Option ist die Verwendung der Diagnosekonfigurationsdateien (pvsconfig). All diese Methoden sind ausführlich in der Dokumentation im Abschnitt "Suppression of false alarms" beschrieben. Die markup base existiert auch.

Verwandte Themen