Dritter Qt 5 Test mit PVS-Studio

PVS-Studio & Qt

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 :).

Zeit zum Nachdenken


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 Diagnosehinweis

Der 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 N7

Und 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-N21

Betrachten 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-N33

Es 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-N70

Wie 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); // Erase carriage return and line feed buffer = buffer.replace('\r', '\0').replace('\n', '\0'); // Replace non-printable characters with dash for (int i = 0; i < buffer.count(); ++i) { if (buffer[i] < '\040' && buffer[i] > '\176') buffer[i] = '-'; } return QString::fromLatin1(buffer.trimmed()); } 

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 N72

Ein ä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 N74

Der 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.

 // Re-engineered from the inline function _com_error::ErrorMessage(). // We cannot use it directly since it uses swprintf_s(), which is not // present in the MSVCRT.DLL found on Windows XP (QTBUG-35617). static inline QString errorMessageFromComError(const _com_error &comError) { TCHAR *message = nullptr; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, DWORD(comError.Error()), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), message, 0, NULL); if (message) { const QString result = QString::fromWCharArray(message).trimmed(); LocalFree(static_cast<HLOCAL>(message)); return result; } if (const WORD wCode = comError.WCode()) return QString::asprintf("IDispatch error #%u", uint(wCode)); return QString::asprintf("Unknown error 0x0%x", uint(comError.Error())); } 

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); // equiv. to int((totalHeight*elapsed) / duration + 0.5) done = (currentHeight >= totalHeight); } done = (currentHeight >= totalHeight) && (currentWidth >= totalWidth); .... } 

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:
  1. VK.com: pvsstudio_rus
  2. "Old School" RSS: viva64-blog-ru
  3. Twitter: @pvsstudio_rus
  4. Instagram: @pvsstudio_rus
  5. 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

Source: https://habr.com/ru/post/de426485/


All Articles