Von Zeit zu Zeit überprüft unser Team erneut Projekte, über die wir bereits Artikel geschrieben haben. Ein weiteres solches erneut geprüftes Projekt war Qt. Das letzte Mal haben wir es 2014 mit PVS-Studio getestet. Seit 2014 wird das Projekt regelmäßig mit Hilfe von Coverity überprüft. Das ist interessant. Mal sehen, ob wir jetzt mit PVS-Studio interessante Fehler finden können.
Qt
Vorherige Artikel:
Diesmal wurden
Qt Base (Core, Gui, Widgets, Network, ...) und
Qt5 Super Module getestet . Über Qt Creator planen wir, später einen separaten Artikel zu schreiben. Zur Überprüfung haben wir den statischen Analysator PVS-Studio verwendet, dessen Testversion Sie von der Website
herunterladen können.
Meiner subjektiven Meinung nach ist der Qt-Code besser geworden. Im Laufe der Jahre seit dem letzten Test sind im PVS-Studio-Analysegerät viele neue Diagnosen erschienen. Trotzdem habe ich bei der Überprüfung der Warnungen nicht so viele Fehler für ein Projekt dieser Größe gefunden. Ich wiederhole noch einmal, dass dies mein individueller Eindruck ist. Ich habe damals oder heute keine speziellen Untersuchungen zur Fehlerdichte durchgeführt.
Höchstwahrscheinlich wirkten sich regelmäßige Überprüfungen mit dem statischen Analysegerät Coverity höchstwahrscheinlich auf die Qualität des Codes aus. 2014 wurde mit Hilfe von Coverity das Qt-Projekt (
qt-project ) und 2016 der Qt Creator (
qt-creator ) überprüft. Meine Meinung: Wenn Sie ein Open Source-Projekt entwickeln, kann
Coverity Scan eine gute kostenlose Lösung sein, die die Qualität und Zuverlässigkeit Ihrer Projekte erheblich verbessert.
Wie der Leser jedoch erraten kann, hätte es keinen Artikel gegeben, wenn ich im PVS-Studio-Bericht nichts Interessantes bemerkt hätte :). Und da es einen Artikel gibt, also Mängel. Schauen wir sie uns an. Insgesamt habe ich 96 Fehler ausgeschrieben.
Erfolgloses Kopieren, Einfügen und Tippfehler
Beginnen wir mit den Klassikern des Genres, wenn die Ursache des Fehlers Unaufmerksamkeit ist. Diese Fehler werden von Programmierern unterschätzt. Für diejenigen, die noch nicht gelesen haben, empfehle ich, dass Sie sich diese beiden Artikel ansehen:
Diese Fehler sind interlanguage. Zum Beispiel enthält der zweite Artikel viele Beispiele für Fehler in Vergleichsfunktionen, die in C, C ++ und C # geschrieben wurden. Bei der Implementierung der Java-Sprachunterstützung in PVS-Studio treten dieselben Fehlermuster auf. Hier ist zum Beispiel ein Fehler, den wir kürzlich in der
Hibernate- Bibliothek gefunden haben:
public boolean equals(Object other) { if (other instanceof Id) { Id that = (Id) other; return purchaseSequence.equals(this.purchaseSequence) && that.purchaseNumber == this.purchaseNumber; } else { return false; } }
Wenn Sie genau hinschauen, stellt sich heraus, dass das Feld
purchaseSequence mit sich selbst verglichen wird. Die richtige Option:
return that.purchaseSequence.equals(this.purchaseSequence) && that.purchaseNumber == this.purchaseNumber;
Im Allgemeinen ist alles wie immer, und der PVS-Studio-Analysator muss die Augean-Ställe in Java-Projekten "harken". Übrigens laden wir alle ein, am Testen der Beta-Version von PVS-Studio für Java teilzunehmen, die in naher Zukunft erscheinen wird.
Schreiben Sie uns dazu (wählen Sie "Ich möchte den Analysator für Java").
Nun zurück zu den Fehlern im Qt-Projekt.
Defekt N1 static inline int windowDpiAwareness(HWND hwnd) { return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; }
PVS-Studio Warnung: V501 CWE-571 Links und rechts vom Operator '&&' befinden sich identische Unterausdrücke 'QWindowsContext :: user32dll.getWindowDpiAwarenessContext'. qwindowscontext.cpp 150
Eine spezielle Erklärung neben der Analysatormeldung ist hier nicht erforderlich. Es scheint mir, dass der Ausdruck so hätte sein sollen:
return QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1;
Defekt N2, N3 void QReadWriteLockPrivate::release() { Q_ASSERT(!recursive); Q_ASSERT(!waitingReaders && !waitingReaders && !readerCount && !writerCount); freelist->release(id); }
PVS-Studio Warnung: V501 CWE-571 Links und rechts vom Operator '&&' befinden sich identische Unterausdrücke:! WaitingReaders &&! WaitingReaders qreadwritelock.cpp 632
Der Fehler befindet sich innerhalb der
Makrobedingung Q_ASSERT und ist daher nicht signifikant. Trotzdem ist dies ein Fehler. Die Variable
waitReaders ist doppelt geprüft. Und anscheinend haben sie vergessen, eine andere Variable zu überprüfen.
Ein identischer Fehler wird in der Zeile 625 der Datei qreadwritelock.cpp gefunden. Es lebe das Kopieren und Einfügen! :) :)
Defekt N4 QString QGraphicsSceneBspTree::debug(int index) const { .... if (node->type == Node::Horizontal) { tmp += debug(firstChildIndex(index)); tmp += debug(firstChildIndex(index) + 1); } else { tmp += debug(firstChildIndex(index)); tmp += debug(firstChildIndex(index) + 1); } .... }
PVS-Studio Warnung: V523 CWE-691 Die Anweisung 'then' entspricht der Anweisung 'else'. qgraphicsscene_bsp.cpp 179
Höchstwahrscheinlich wurde der Textblock kopiert, aber sie haben vergessen, ihn zu korrigieren.
Defekt N5 enum FillRule { OddEvenFill, WindingFill }; QDataStream &operator>>(QDataStream &s, QPainterPath &p) { .... int fillRule; s >> fillRule; Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill); .... }
PVS-Studio Warnung: V768 CWE-571 Die Aufzählungskonstante 'WindingFill' wird als Variable eines Booleschen Typs verwendet. qpainterpath.cpp 2479
Stimmen Sie zu, das ist ein wunderschöner Blooper!
Q_ASSERT überprüft nichts, da die Bedingung immer wahr ist. Die Bedingung ist wahr, da die benannte Konstante
Qt :: WindingFill 1 ist.
Defekt N6 bool QVariant::canConvert(int targetTypeId) const { .... if (currentType == QMetaType::SChar || currentType == QMetaType::Char) currentType = QMetaType::UInt; if (targetTypeId == QMetaType::SChar || currentType == QMetaType::Char) targetTypeId = QMetaType::UInt; .... }
Versuchen Sie vor dem Lesen der Warnung, selbst einen Tippfehler zu erkennen. Durch Hinzufügen eines Bildes helfe ich Ihnen, die Analysatormeldung nicht sofort zu lesen :).
PVS-Studio Warnung: V560 CWE-570 Ein Teil des bedingten Ausdrucks ist immer falsch: currentType == QMetaType :: Char. qvariant.cpp 3529
Die Bedingung "currentType == QMetaType :: Char" wird im ersten
if überprüft. Wenn die Bedingung erfüllt ist, wird die Variable
currentType auf
QMetaType :: UInt gesetzt . Daher kann die Variable
currentType nicht mehr gleich
QMetaType :: Char sein . Daher meldet der Analysator, dass im zweiten
if der Unterausdruck "currentType == QMetaType :: Char" immer falsch ist.
In der Tat sollte das zweite
if so sein:
if (targetTypeId == QMetaType::SChar || targetTypeId == QMetaType::Char) targetTypeId = QMetaType::UInt;
V560 DiagnosehinweisDer Bericht fand viele V560-Warnungen. Ich habe sie mir jedoch nicht mehr angesehen, sobald ich einen interessanten Fall für den Artikel gefunden habe, der oben als Defekt N6 angesehen wurde.
Die überwiegende Mehrheit der Nachrichten V560 kann nicht als falsch bezeichnet werden, sie werden jedoch nicht verwendet. Mit anderen Worten, es ist nicht interessant, sie in einem Artikel zu beschreiben. Um klar zu machen, was ich genau meine, betrachten Sie einen solchen Fall.
QString QTextHtmlExporter::findUrlForImage(const QTextDocument *doc, ....) { QString url; if (!doc) return url; if (QTextDocument *parent = qobject_cast<QTextDocument *>(doc->parent())) return findUrlForImage(parent, cacheKey, isPixmap); if (doc && doc->docHandle()) {
Warnung PVS-Stuidio: V560 CWE-571 Ein Teil des bedingten Ausdrucks ist immer wahr: doc. qtextdocument.cpp 2992
Der Analysator ist absolut korrekt, dass der
doc- Zeiger nicht immer
nullptr ist, wenn er erneut überprüft wird. Dies ist jedoch kein Fehler, nur der Programmierer war in Sicherheit. Sie können den Code vereinfachen, indem Sie Folgendes schreiben:
if (doc->docHandle()) {
Defekt N7Und der letzte Fall, der als Tippfehler eingestuft werden kann. Der Fehler tritt aufgrund von Verwechslungen in den Namen der Konstanten auf, die sich nur im Fall des ersten Buchstabens unterscheiden.
class QWindowsCursor : public QPlatformCursor { public: enum CursorState { CursorShowing, CursorHidden, CursorSuppressed }; .... } QWindowsCursor::CursorState QWindowsCursor::cursorState() { enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; CURSORINFO cursorInfo; cursorInfo.cbSize = sizeof(CURSORINFO); if (GetCursorInfo(&cursorInfo)) { if (cursorInfo.flags & CursorShowing) .... }
PVS-Studio Warnung: V616 CWE-480 Die benannte Konstante 'CursorShowing' mit dem Wert 0 wird in der bitweisen Operation verwendet. qwindowscursor.cpp 669
Im Detail habe ich diesen Fehler bereits in einem separaten kleinen Hinweis analysiert: "
Der PVS-Studio-Analysator erwies sich erneut als aufmerksamer als eine
Person ."
Sicherheitslücken
Tatsächlich können alle in diesem Artikel beschriebenen Fehler als Sicherheitsmängel bezeichnet werden. Alle von ihnen sind nach der
Common Weakness Enumeration klassifiziert (siehe CWE ID in den Analysatormeldungen). Wenn Fehler als CWEs klassifiziert werden, stellen sie möglicherweise ein Sicherheitsrisiko dar. Dies wird auf der Seite
PVS-Studio SAST näher erläutert.
Ich möchte jedoch einige Fehler in einer separaten Gruppe zusammenfassen. Schauen wir sie uns an.
Defekt N8, N9 bool QLocalServerPrivate::addListener() { .... SetSecurityDescriptorOwner(pSD.data(), pTokenUser->User.Sid, FALSE); SetSecurityDescriptorGroup(pSD.data(), pTokenGroup->PrimaryGroup, FALSE); .... }
PVS-Studio-Warnungen:
- V530 CWE-252 Der Rückgabewert der Funktion 'SetSecurityDescriptorOwner' muss verwendet werden. qlocalserver_win.cpp 167
- V530 CWE-252 Der Rückgabewert der Funktion 'SetSecurityDescriptorGroup' muss verwendet werden. qlocalserver_win.cpp 168
Es gibt verschiedene Funktionen in Bezug auf die Zugangskontrolle.
Dazu gehören die Funktionen
SetSecurityDescriptorOwner und
SetSecurityDescriptorGroup .
Mit solchen Funktionen müssen Sie sehr sorgfältig arbeiten. Sie müssen beispielsweise den Status überprüfen, den sie zurückgeben. Was passiert, wenn der Aufruf dieser Funktionen fehlschlägt? Raten ist nicht erforderlich, es ist erforderlich, Code zu schreiben, um diesen Fall zu behandeln.
Es ist nicht erforderlich, den Mangel an Überprüfung auszunutzen und solche Fehler in Schwachstellen umzuwandeln. Dies ist jedoch in keinem Fall ein Ort für Risiken, und Sie müssen sichereren Code schreiben.
Defekt N10 bool QLocalServerPrivate::addListener() { .... InitializeAcl(acl, aclSize, ACL_REVISION_DS); .... }
PVS-Studio Warnung: V530 CWE-252 Der Rückgabewert der Funktion 'InitializeAcl' muss verwendet werden. qlocalserver_win.cpp 144
Die Situation ist ähnlich wie oben beschrieben.
Defekt N11, N12 static inline void sha1ProcessChunk(....) { .... quint8 chunkBuffer[64]; .... #ifdef SHA1_WIPE_VARIABLES .... memset(chunkBuffer, 0, 64); #endif }
PVS-Studio Warnung: V597 CWE-14 Der Compiler könnte den Funktionsaufruf 'memset' löschen, mit dem der 'chunkBuffer'-Puffer geleert wird. Die Funktion RtlSecureZeroMemory () sollte verwendet werden, um die privaten Daten zu löschen. sha1.cpp 189
Der Compiler entfernt den
Memset- Funktionsaufruf. Bereits oft in Artikeln habe ich diese Situation analysiert. Ich habe keine Lust, mich zu wiederholen. Ich verweise auf den Artikel "
Sichere Bereinigung privater Daten ".
Ein weiterer Fehler befindet sich in derselben Datei sha1.cpp in Zeile 247.
Nullzeiger
Es ist Zeit, über Hinweise zu sprechen. Es gab viele Fehler zu diesem Thema.
Defekt N13 QByteArray &QByteArray::append(const char *str, int len) { if (len < 0) len = qstrlen(str); if (str && len) { .... }
PVS-Studio Warnung: V595 CWE-476 Der Zeiger 'str' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2118, 2119. qbytearray.cpp 2118
Die klassische Situation ist, wenn am Anfang ein Zeiger verwendet und dann auf
Nullptr- Gleichheit überprüft wird. Dies ist ein sehr häufiges Fehlermuster, das wir regelmäßig in fast allen Projekten sehen.
Defekt N14, N15 static inline const QMetaObjectPrivate *priv(const uint* data) { return reinterpret_cast<const QMetaObjectPrivate*>(data); } bool QMetaEnum::isFlag() const { const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1; return mobj && mobj->d.data[handle + offset] & EnumIsFlag; }
PVS-Studio Warnung: V595 CWE-476 Der 'mobj'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2671, 2672. qmetaobject.cpp 2671
Nur für den Fall, ich bringe den Körper der
Priv- Funktion. Aus irgendeinem Grund kommen Leser manchmal auf Situationen, in denen der Code funktioniert. Ich verstehe nicht, woher dieses Misstrauen kommt und der Wunsch, eine knifflige Funktion irrtümlich zu sehen :). Zum Beispiel kann jemand in den Kommentaren vorschlagen, dass
priv ein Makro des Formulars ist:
#define priv(A) foo(sizeof(A))
Dann wird alles funktionieren.
Um solche Diskussionen zu vermeiden, versuche ich, Codefragmente zu zitieren, in denen alle Informationen enthalten sind, die das Vorhandensein eines Fehlers bestätigen.
Der
modj- Zeiger
wird also dereferenziert und dann überprüft.
Weiter auf der Bühne kommt die "mächtige und schreckliche" Copy-Paste. Aufgrund dessen, was genau der gleiche Fehler in der
isScoped- Funktion
erkannt wird:
bool QMetaEnum::isScoped() const { const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1; return mobj && mobj->d.data[handle + offset] & EnumIsScoped; }
PVS-Studio Warnung: V595 CWE-476 Der 'mobj'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2683, 2684. qmetaobject.cpp 2683
Defekt N16-N21Betrachten Sie ein anderes Beispiel und ich denke genug.
void QTextCursor::insertFragment(const QTextDocumentFragment &fragment) { if (!d || !d->priv || fragment.isEmpty()) return; d->priv->beginEditBlock(); d->remove(); fragment.d->insert(*this); d->priv->endEditBlock(); if (fragment.d && fragment.d->doc) d->priv->mergeCachedResources(fragment.d->doc->docHandle()); }
PVS-Studio Warnung: V595 CWE-476 Der Zeiger 'fragment.d' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2238, 2241. qtextcursor.cpp 2238
Trotzdem. Achten Sie auf die Reihenfolge der Arbeit mit dem in der Variablen
fragment.d gespeicherten Zeiger.
Andere Fehler dieses Typs:
- V595 CWE-476 Der 'Fenster'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 1846, 1848. qapplication.cpp 1846
- V595 CWE-476 Der 'Fenster'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 1858, 1860. qapplication.cpp 1858
- V595 CWE-476 Der 'Antwort'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 492, 502. qhttpnetworkconnectionchannel.cpp 492
- V595 CWE-476 Der Zeiger 'newHandle' wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 877, 883. qsplitter.cpp 877
- V595 CWE-476 Der 'Widget'-Zeiger wurde verwendet, bevor er gegen nullptr verifiziert wurde. Überprüfen Sie die Zeilen: 2320, 2322. qwindowsvistastyle.cpp 2320
- In der Tat gibt es mehr Fehler. Ich hatte es schnell satt, die V595-Warnungen zu lernen, und für den Artikel habe ich bereits genug Codefragmente geschrieben.
Defekt N22-N33Es gibt Code, in dem ein Zeiger überprüft wird, den der
neue Operator zurückgibt. Dies ist besonders lustig, da es viele Stellen gibt, an denen das Ergebnis der
Malloc- Funktion nicht überprüft wird (siehe folgende Fehlergruppe).
bool QTranslatorPrivate::do_load(const QString &realname, const QString &directory) { .... d->unmapPointer = new char[d->unmapLength]; if (d->unmapPointer) { file.seek(0); qint64 readResult = file.read(d->unmapPointer, d->unmapLength); if (readResult == qint64(unmapLength)) ok = true; } .... }
PVS-Studio Warnung: V668 CWE-571 Es macht keinen Sinn, den Zeiger 'd-> unmap Pointer' gegen Null zu testen, da der Speicher mit dem Operator 'new' zugewiesen wurde. Die Ausnahme wird bei einem Speicherzuordnungsfehler generiert. qtranslator.cpp 596
Das Überprüfen des Zeigers ist nicht sinnvoll, da im Falle eines Speicherzuordnungsfehlers eine Ausnahme
std :: bad_alloc ausgelöst wird . Wenn der
neue Operator
nullptr zurückgeben soll, wenn nicht genügend Speicher vorhanden ist, sollten Sie
Folgendes schreiben:
d->unmapPointer = new (std::nothrow) char[d->unmapLength];
Der Analysator kennt diese Verwendung des
neuen Operators und würde in diesem Fall keine Warnung geben.
Andere Fehler: Ich werde ihnen die
Datei qt-V668.txt geben .
Defekt N34-N70Wie versprochen sind jetzt Fehler an der Reihe, wenn sie das Ergebnis des Aufrufs der Funktionen
malloc ,
calloc ,
strdup usw. nicht überprüfen. Diese Fehler sind schwerwiegender, als es auf den ersten Blick scheint. Weitere Details: "
Warum ist es wichtig zu überprüfen, was die Malloc-Funktion zurückgegeben hat? "
SourceFiles::SourceFiles() { nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037)); for(int n = 0; n < num_nodes; n++) nodes[n] = nullptr; }
PVS-Studio Warnung: V522 CWE-690 Möglicherweise wird ein potenzieller Nullzeiger 'Knoten' dereferenziert. Überprüfen Sie die Zeilen: 138, 136. makefiledeps.cpp 138
Der Zeiger wird ohne vorherige Überprüfung verwendet.
Alle diese Fehler sind vom gleichen Typ, daher werde ich nicht näher darauf eingehen. Ich werde den Rest der Warnliste geben:
qt-V522-V575.txt .
Logische Fehler in Bedingungen
Defekt N71 QString QEdidParser::parseEdidString(const quint8 *data) { QByteArray buffer(reinterpret_cast<const char *>(data), 13);
PVS-Studio-Warnung: V547 CWE-570 Ausdruck 'buffer [i] <' \ 040 '&& buffer [i]>' \ 176 '' ist immer falsch. qedidparser.cpp 169
Die Funktion muss die folgende Aktion ausführen: "Nicht druckbare Zeichen durch Bindestrich ersetzen". Sie tut es jedoch nicht. Schauen wir uns diesen Zustand genauer an:
if (buffer[i] < '\040' && buffer[i] > '\176')
Es macht keinen Sinn. Ein Zeichen darf nicht kleiner als '\ 040' und gleichzeitig größer als '\ 176' sein. In der Bedingung müssen Sie den Operator '||' verwenden. Der richtige Code lautet:
if (buffer[i] < '\040' || buffer[i] > '\176')
Defekt N72Ein ähnlicher Fehler, aufgrund dessen Windows-Benutzer kein Glück haben.
#if defined(Q_OS_WIN) static QString driveSpec(const QString &path) { if (path.size() < 2) return QString(); char c = path.at(0).toLatin1(); if (c < 'a' && c > 'z' && c < 'A' && c > 'Z') return QString(); if (path.at(1).toLatin1() != ':') return QString(); return path.mid(0, 2); } #endif
Der Analysator generiert zwei Warnungen gleichzeitig:
- V590 CWE-571 Überprüfen Sie den Ausdruck 'c <' a '&& c>' z '&& c <' A '&& c>' Z ''. Der Ausdruck ist übertrieben oder enthält einen Druckfehler. qdir.cpp 77
- V560 CWE-570 Ein Teil des bedingten Ausdrucks ist immer falsch: c> 'z'. qdir.cpp 77
Ein logischer Fehler ist in der Bedingung:
if (c < 'a' && c > 'z' && c < 'A' && c > 'Z')
So wie ich es verstehe, wollte der Programmierer ein Zeichen finden, das kein Buchstabe des lateinischen Alphabets ist. In diesem Fall sollte die Bedingung folgendermaßen aussehen:
if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z'))
Defekt N73 enum SelectionMode { NoSelection, SingleSelection, MultiSelection, ExtendedSelection, ContiguousSelection }; void QAccessibleTableCell::unselectCell() { QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection)) return; .... }
PVS-Studio Warnung: V616 CWE-480 Die benannte Konstante 'QAbstractItemView :: NoSelection' mit dem Wert 0 wird in der bitweisen Operation verwendet. itemviews.cpp 976
Die benannte Konstante
QAbstractItemView :: NoSelection ist Null. Daher ist der Unterausdruck
(selectionMode & QAbstractItemView :: NoSelection) nicht sinnvoll. Es wird immer 0 sein.
Ich denke, es sollte hier geschrieben werden:
if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
Defekt N74Der folgende Code ist für mich schwer zu verstehen. Er liegt falsch, aber ich weiß nicht, was er sein soll. Das Kommentieren einer Funktion hilft mir auch nicht.
PVS-Studio Warnung: V547 CWE-570 Der Ausdruck 'message' ist immer falsch. qwindowscontext.cpp 802
Der Programmierer geht wahrscheinlich davon aus, dass die
FormatMessage- Funktion den Wert des
Nachrichtenzeigers ändert. Aber das ist nicht so. Die
FormatMessage-Funktion kann den Wert eines Zeigers nicht ändern, da er als Wert an die Funktion übergeben wird. Hier ist ein Prototyp dieser Funktion:
DWORD __stdcall FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments );
Mögliche Speicherlecks
Defekt N75-N92 struct SourceDependChildren { SourceFile **children; int num_nodes, used_nodes; SourceDependChildren() : children(nullptr), num_nodes(0), used_nodes(0) { } ~SourceDependChildren() { if (children) free(children); children = nullptr; } void addChild(SourceFile *s) { if(num_nodes <= used_nodes) { num_nodes += 200; children = (SourceFile**)realloc(children, sizeof(SourceFile*)*(num_nodes)); } children[used_nodes++] = s; } };
PVS-Studio-Warnung: V701 CWE-401 realloc () mögliches Leck: Wenn realloc () beim Zuweisen von Speicher fehlschlägt, geht der ursprüngliche Zeiger 'Kinder' verloren. Ziehen Sie in Betracht, einem temporären Zeiger realloc () zuzuweisen. makefiledeps.cpp 103
Die Puffererweiterung wird auf gefährliche Weise implementiert. Wenn die
Realloc- Funktion keinen Speicher zuweisen kann, wird
NULL zurückgegeben . Dieser
NULL- Wert wird sofort in die
untergeordnete Variable eingefügt, und es besteht keine Möglichkeit, den zuvor zugewiesenen Puffer irgendwie freizugeben. Ein Speicherverlust tritt auf.
Ähnliche Fehler:
qt-701.txt .
Verschiedenes
Defekt N93 template<class GradientBase, typename BlendType> static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template(....) { .... if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) { .... }
PVS-Studio Warnung: V610 CWE-758 Nicht angegebenes Verhalten. Überprüfen Sie den Schaltoperator '>>'. Der linke Operand '(- 2147483647 - 1)' ist negativ. qdrawhelper.cpp 4015
Der negative Wert von
INT_MIN kann nicht verschoben werden. Dies ist ein nicht angegebenes Verhalten, und Sie können sich nicht auf das Ergebnis einer solchen Operation verlassen. Die höchstwertigen Bits können gleich 0 oder 1 sein.
Defekt N94 void QObjectPrivate::addConnection(int signal, Connection *c) { .... if (signal >= connectionLists->count()) connectionLists->resize(signal + 1); ConnectionList &connectionList = (*connectionLists)[signal]; .... if (signal < 0) { .... }
PVS-Studio Warnung: V781 CWE-129 Der Wert der Variablen 'signal' wird nach ihrer Verwendung überprüft. Möglicherweise liegt ein Fehler in der Programmlogik vor. Überprüfen Sie die Zeilen: 397, 413. qobject.cpp 397
Eine Prüfung
(Signal <0) zeigt an, dass der Wert des
Signalarguments negativ sein kann. Dieses Argument wurde jedoch zuvor zum Indizieren des Arrays verwendet. Es stellt sich heraus, dass die Prüfung zu spät durchgeführt wird. Das Programm wird bereits unterbrochen.
Defekt N95 bool QXmlStreamWriterPrivate::finishStartElement(bool contents) { .... if (inEmptyElement) { write("/>"); QXmlStreamWriterPrivate::Tag &tag = tagStack_pop(); lastNamespaceDeclaration = tag.namespaceDeclarationsSize; lastWasStartElement = false; } else { write(">"); } inStartElement = inEmptyElement = false; lastNamespaceDeclaration = namespaceDeclarations.size(); return hadSomethingWritten; }
PVS-Studio Warnung: V519 CWE-563 Der Variablen 'lastNamespaceDeclaration' werden zweimal nacheinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 3188, 3194. qxmlstream.cpp 3194
Ich werde das Wesentliche des Fehlers hervorheben:
if (inEmptyElement) { lastNamespaceDeclaration = tag.namespaceDeclarationsSize; } lastNamespaceDeclaration = namespaceDeclarations.size();
Defekt N96 void QRollEffect::scroll() { .... if (currentHeight != totalHeight) { currentHeight = totalHeight * (elapsed/duration) + (2 * totalHeight * (elapsed%duration) + duration) / (2 * duration);
V519 CWE-563 Der Variablen 'done' werden zweimal hintereinander Werte zugewiesen. Vielleicht ist das ein Fehler. Überprüfen Sie die Zeilen: 509, 511. qeffects.cpp 511
Alles ist das gleiche wie im vorherigen Fall. Beachten Sie die Variable
done .
Fazit
Selbst wenn ich den Bericht oberflächlich durchgesehen habe, habe ich fast 100 Fehler geschrieben. Ich bin mit den Ergebnissen von PVS-Studio zufrieden.
Natürlich haben solche seltenen Codeprüfungen nichts mit der Verbesserung der Qualität und Zuverlässigkeit des Codes zu tun. Sie demonstrieren nur die Fähigkeiten des Code-Analysators. Statische Analysewerkzeuge sollten regelmäßig angewendet werden. In diesem Fall reduzieren sie die Kosten für die Behebung von Fehlern und schützen Anwendungen vor vielen potenziellen Schwachstellen.
Vielen Dank für Ihre Aufmerksamkeit. Um über unsere neuen Veröffentlichungen auf dem Laufenden zu bleiben, lade ich Sie ein, einen unserer Kanäle zu abonnieren:
- VK.com: pvsstudio_rus
- "Old School" RSS: viva64-blog-ru
- Twitter: @pvsstudio_rus
- Instagram: @pvsstudio_rus
- Telegramm: @pvsstudio_rus

Wenn Sie diesen Artikel einem englischsprachigen Publikum zugänglich machen möchten, verwenden Sie bitte den Link zur Übersetzung: Andrey Karpov.
Eine dritte Überprüfung von Qt 5 mit PVS-Studio