De temps en temps, notre équipe revérifie les projets sur lesquels nous avons déjà écrit des articles. Un autre projet revérifié était Qt. La dernière fois que nous l'avons testé avec PVS-Studio en 2014. Depuis 2014, le projet a commencé à être régulièrement contrôlé avec l'aide de Coverity. C'est intéressant. Voyons si nous pouvons maintenant trouver des erreurs intéressantes en utilisant PVS-Studio.
Qt
Articles précédents:
Cette fois,
Qt Base (Core, Gui, Widgets, Network, ...) et le
super module Qt5 ont été testés . À propos de Qt Creator, nous prévoyons d'écrire un article séparé plus tard. Pour vérification, nous avons utilisé l'analyseur statique PVS-Studio, dont vous pouvez
télécharger une version d'essai sur le site.
À mon avis, le code Qt est devenu meilleur. Au fil des ans depuis le dernier test, de nombreux nouveaux diagnostics sont apparus dans l'analyseur PVS-Studio. Malgré cela, lors de l'examen des avertissements, je n'ai pas trouvé autant d'erreurs pour un projet de cette taille. Je répète encore une fois que c'est mon impression individuelle. Je n'ai pas fait de recherche spéciale sur la densité des erreurs à ce moment-là ou maintenant.
Très probablement, des vérifications régulières à l'aide de l'analyseur statique Coverity ont très probablement affecté la qualité du code. En 2014, avec l'aide de Coverity, le projet Qt (
qt-project ) a commencé à être vérifié, et en 2016, le Qt Creator (
qt-creator ). Mon avis: si vous développez un projet ouvert,
Coverity Scan peut être une bonne solution gratuite qui améliorera considérablement la qualité et la fiabilité de vos projets.
Cependant, comme le lecteur peut le deviner, si je n'avais rien remarqué d'intéressant dans le rapport PVS-Studio, il n'y aurait pas eu d'article :). Et puisqu'il y a un article, c'est-à-dire des défauts. Regardons-les. Au total, j'ai écrit 96 erreurs.
Copier-coller et Typos infructueux
Commençons par les classiques du genre, lorsque la cause de l'erreur est l'inattention. Ces erreurs sont sous-estimées par les programmeurs. Pour ceux qui ne l'ont pas encore lu, je vous recommande de lire ces deux articles:
Ces erreurs sont interlangues. Par exemple, le deuxième article donne de nombreux exemples d'erreurs dans les fonctions de comparaison écrites en C, C ++ et C #. Maintenant, lors de l'implémentation de la prise en charge du langage Java dans PVS-Studio, nous rencontrons les mêmes modèles d'erreur. Voici, par exemple, un bug que nous avons récemment trouvé dans la bibliothèque
Hibernate :
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; } }
Si vous regardez attentivement, il s'avère que le champ
PurchaseSequence est comparé à lui-même. L'option correcte:
return that.purchaseSequence.equals(this.purchaseSequence) && that.purchaseNumber == this.purchaseNumber;
En général, tout est comme toujours, et l'analyseur PVS-Studio devra "ratisser les écuries Augean" dans les projets Java. Soit dit en passant, nous invitons tout le monde à prendre part aux tests de la version bêta de PVS-Studio pour Java, qui devrait apparaître prochainement. Pour ce faire,
écrivez-nous (sélectionnez "Je veux l'analyseur pour Java").
Revenons maintenant aux erreurs du projet Qt.
Défaut N1 static inline int windowDpiAwareness(HWND hwnd) { return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; }
Avertissement PVS-Studio: V501 CWE-571 Il existe des sous-expressions identiques «QWindowsContext :: user32dll.getWindowDpiAwarenessContext» à gauche et à droite de l'opérateur «&&». qwindowscontext.cpp 150
Aucune explication particulière en plus du message de l'analyseur n'est requise ici. Il me semble que l'expression aurait dû être comme ceci:
return QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1;
Défaut N2, N3 void QReadWriteLockPrivate::release() { Q_ASSERT(!recursive); Q_ASSERT(!waitingReaders && !waitingReaders && !readerCount && !writerCount); freelist->release(id); }
Avertissement PVS-Studio: V501 CWE-571 Il existe des sous-expressions identiques à gauche et à droite de l'opérateur '&&':! WaitingReaders &&! WaitingReaders qreadwritelock.cpp 632
L'erreur se trouve dans la
condition de macro
Q_ASSERT , elle n'est donc pas significative. Mais encore, c'est une erreur. La variable
waitReaders est vérifiée deux fois. Et apparemment, ils ont oublié de vérifier une autre variable.
Une erreur identique se trouve dans la ligne 625 du fichier qreadwritelock.cpp. Vive le copier-coller! :)
Défaut 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 Warning: V523 CWE-691 L'instruction 'then' est équivalente à l'instruction 'else'. qgraphicsscene_bsp.cpp 179
Très probablement, le bloc de texte a été copié, mais ils ont oublié de le corriger.
Défaut N5 enum FillRule { OddEvenFill, WindingFill }; QDataStream &operator>>(QDataStream &s, QPainterPath &p) { .... int fillRule; s >> fillRule; Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill); .... }
Avertissement PVS-Studio: V768 CWE-571 La constante d'énumération 'WindingFill' est utilisée comme variable de type booléen. qpainterpath.cpp 2479
D'accord, c'est un beau bêtisier!
Q_ASSERT ne vérifie rien, car la condition est toujours vraie. La condition est vraie car la constante nommée
Qt :: WindingFill est 1.
Défaut 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; .... }
Avant de lire l'avertissement, essayez de repérer une faute de frappe vous-même. En ajoutant une image, je vous aiderai à ne pas lire immédiatement le message de l'analyseur :).
Avertissement PVS-Studio: V560 CWE-570 Une partie de l'expression conditionnelle est toujours fausse: currentType == QMetaType :: Char. qvariant.cpp 3529
La condition "currentType == QMetaType :: Char" est vérifiée dans le premier
if . Si la condition est remplie, la variable
currentType reçoit la valeur
QMetaType :: UInt . Par conséquent, la variable
currentType ne peut plus être égale à
QMetaType :: Char . Par conséquent, l'analyseur signale que dans le second
if, la sous
- expression "currentType == QMetaType :: Char" est toujours fausse.
En fait, le deuxième
if devrait être comme ceci:
if (targetTypeId == QMetaType::SChar || targetTypeId == QMetaType::Char) targetTypeId = QMetaType::UInt;
Note de diagnostic V560Le rapport a trouvé de nombreux avertissements V560. Cependant, je ne les ai plus regardés dès que j'ai trouvé un cas intéressant pour l'article, qui était considéré ci-dessus comme un défaut N6.
La grande majorité des messages V560 ne peuvent pas être appelés faux, mais ils ne servent à rien. En d'autres termes, les décrire dans un article n'est pas intéressant. Pour bien comprendre ce que je veux dire exactement, considérons un de ces cas.
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()) {
Avertissement PVS-Stuidio: V560 CWE-571 Une partie de l'expression conditionnelle est toujours vraie: doc. qtextdocument.cpp 2992
L'analyseur est absolument correct que le pointeur de
doc n'est pas toujours
nullptr quand il est revérifié. Mais ce n'est pas une erreur, juste le programmeur était en sécurité. Vous pouvez simplifier le code en écrivant:
if (doc->docHandle()) {
Défaut N7Et le dernier cas, qui peut être classé comme une faute de frappe. L'erreur se produit en raison d'une confusion dans les noms des constantes, qui ne diffèrent que dans le cas de la première lettre.
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) .... }
Avertissement PVS-Studio: V616 CWE-480 La constante nommée 'CursorShowing' avec la valeur 0 est utilisée dans l'opération au niveau du bit. qwindowscursor.cpp 669
Plus en détail, j'ai déjà analysé cette erreur dans une petite note séparée: "
Encore une fois, l'analyseur PVS-Studio s'est avéré être plus attentif qu'une
personne ."
Failles de sécurité
En fait, toutes les erreurs discutées dans cet article peuvent être appelées défauts de sécurité. Tous sont classés selon l'
énumération commune des faiblesses (voir CWE ID dans les messages de l'analyseur). Si les erreurs sont classées comme CWE, elles constituent potentiellement un risque pour la sécurité. Ceci est expliqué plus en détail sur la page
PVS-Studio SAST .
Cependant, je voudrais signaler un certain nombre d'erreurs dans un groupe distinct. Jetons-y un œil.
Défaut N8, N9 bool QLocalServerPrivate::addListener() { .... SetSecurityDescriptorOwner(pSD.data(), pTokenUser->User.Sid, FALSE); SetSecurityDescriptorGroup(pSD.data(), pTokenGroup->PrimaryGroup, FALSE); .... }
Avertissements de PVS-Studio:
- V530 CWE-252 La valeur de retour de la fonction 'SetSecurityDescriptorOwner' doit être utilisée. qlocalserver_win.cpp 167
- V530 CWE-252 La valeur de retour de la fonction 'SetSecurityDescriptorGroup' doit être utilisée. qlocalserver_win.cpp 168
Il existe différentes fonctions liées au contrôle d'accès. Les fonctions
SetSecurityDescriptorOwner et
SetSecurityDescriptorGroup en font partie.
Avec de telles fonctions, vous devez travailler très soigneusement. Par exemple, vous devez vérifier le statut qu'ils renvoient. Que se passe-t-il si l'appel à ces fonctions échoue? Deviner n'est pas nécessaire, il est nécessaire d'écrire du code pour gérer un tel cas.
Il n'est pas nécessaire de tirer parti du manque de vérification et de transformer ces erreurs en vulnérabilités. Cependant, ce n'est en aucun cas un lieu de risque, et vous devez écrire du code plus sécurisé.
Défaut N10 bool QLocalServerPrivate::addListener() { .... InitializeAcl(acl, aclSize, ACL_REVISION_DS); .... }
PVS-Studio Warning: V530 CWE-252 La valeur de retour de la fonction 'InitializeAcl' doit être utilisée. qlocalserver_win.cpp 144
La situation est similaire à celle évoquée ci-dessus.
Défaut N11, N12 static inline void sha1ProcessChunk(....) { .... quint8 chunkBuffer[64]; .... #ifdef SHA1_WIPE_VARIABLES .... memset(chunkBuffer, 0, 64); #endif }
Avertissement PVS-Studio: V597 CWE-14 Le compilateur peut supprimer l'appel de fonction 'memset', qui est utilisé pour vider le tampon 'chunkBuffer'. La fonction RtlSecureZeroMemory () doit être utilisée pour effacer les données privées. sha1.cpp 189
Le compilateur supprimera l'appel de fonction
memset . Déjà plusieurs fois dans des articles, j'ai analysé cette situation. Je n'ai pas envie de me répéter. Je me réfère à l'article "
Nettoyage sécurisé des données privées ".
Et une autre erreur se trouve dans le même fichier sha1.cpp, à la ligne 247.
Pointeurs nuls
Il est temps de parler de pointeurs. Il y a eu beaucoup d'erreurs sur ce sujet.
Défaut N13 QByteArray &QByteArray::append(const char *str, int len) { if (len < 0) len = qstrlen(str); if (str && len) { .... }
Avertissement PVS-Studio: V595 CWE-476 Le pointeur 'str' a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 2118, 2119. qbytearray.cpp 2118
La situation classique est lorsqu'un pointeur est utilisé au début, puis vérifié l'égalité
nullptr . Il s'agit d'un modèle d'erreur très courant, et nous le
constatons régulièrement dans presque tous les projets.
Défaut 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; }
Avertissement PVS-Studio: V595 CWE-476 Le pointeur 'mobj' a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 2671, 2672. qmetaobject.cpp 2671
Au cas où, j'apporte le corps de la fonction
privée . Pour une raison quelconque, les lecteurs commencent parfois à trouver des situations dans lesquelles le code fonctionnera. Je ne comprends pas d'où vient cette méfiance et le désir de voir une fonctionnalité délicate par erreur :). Par exemple, quelqu'un peut suggérer dans les commentaires que
priv est une macro du formulaire:
#define priv(A) foo(sizeof(A))
Ensuite, tout fonctionnera.
Afin d'éviter de telles discussions, j'essaie de citer des fragments de code où toutes les informations confirmant l'existence d'une erreur sont fournies.
Ainsi, le pointeur
modj est déréférencé puis vérifié.
Plus loin sur la scène vient le copier-coller «puissant et terrible». En raison de la détection exacte de la même erreur dans la fonction
isScoped :
bool QMetaEnum::isScoped() const { const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1; return mobj && mobj->d.data[handle + offset] & EnumIsScoped; }
Avertissement PVS-Studio: V595 CWE-476 Le pointeur 'mobj' a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 2683, 2684. qmetaobject.cpp 2683
Défaut N16-N21Prenons un autre exemple et, je pense, assez.
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()); }
Avertissement PVS-Studio: V595 CWE-476 Le pointeur 'fragment.d' a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 2238, 2241. qtextcursor.cpp 2238
Tout de même. Faites attention à la séquence de travail avec le pointeur stocké dans la variable
fragment.d .
Autres erreurs de ce type:
- V595 CWE-476 Le pointeur "fenêtre" a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 1846, 1848. qapplication.cpp 1846
- V595 CWE-476 Le pointeur "fenêtre" a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 1858, 1860. qapplication.cpp 1858
- V595 CWE-476 Le pointeur de «réponse» a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 492, 502. qhttpnetworkconnectionchannel.cpp 492
- V595 CWE-476 Le pointeur 'newHandle' a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 877, 883. qsplitter.cpp 877
- V595 CWE-476 Le pointeur "widget" a été utilisé avant d'être vérifié par rapport à nullptr. Vérifiez les lignes: 2320, 2322. qwindowsvistastyle.cpp 2320
- En fait, il y a plus d'erreurs. Je me suis rapidement fatigué d'apprendre les avertissements de la V595, et pour l'article, j'ai déjà écrit suffisamment de fragments de code.
Défaut N22-N33Il y a du code où un pointeur est vérifié que le
nouvel opérateur retourne. C'est particulièrement drôle au milieu du fait qu'il y a beaucoup d'endroits où le résultat de la fonction
malloc n'est pas vérifié (voir le groupe d'erreurs suivant).
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 Warning: V668 CWE-571 Il est inutile de tester le pointeur 'd-> unmap Pointer' contre null, car la mémoire a été allouée à l'aide de l'opérateur 'new'. L'exception sera générée en cas d'erreur d'allocation de mémoire. qtranslator.cpp 596
Vérifier le pointeur n'a pas de sens, car en cas d'erreur d'allocation de mémoire, une exception
std :: bad_alloc sera
levée . Si vous voulez que le
nouvel opérateur retourne
nullptr quand il n'y a pas assez de mémoire, alors vous devez écrire:
d->unmapPointer = new (std::nothrow) char[d->unmapLength];
L'analyseur connaît cette utilisation du
nouvel opérateur et ne donnerait pas d'avertissement dans ce cas.
Autres erreurs: je leur donnerai le
fichier qt-V668.txt .
Défaut N34-N70Comme promis, c'est maintenant le tour des erreurs quand ils ne vérifient pas le résultat de l'appel des fonctions
malloc ,
calloc ,
strdup , etc. Ces erreurs sont plus graves qu'il n'y paraît à première vue. Plus de détails: "
Pourquoi est-il important de vérifier ce que la fonction malloc a renvoyé ."
SourceFiles::SourceFiles() { nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037)); for(int n = 0; n < num_nodes; n++) nodes[n] = nullptr; }
Avertissement PVS-Studio: V522 CWE-690 Il peut y avoir un déréférencement d'un "noeud" de pointeur nul potentiel. Vérifiez les lignes: 138, 136. makefiledeps.cpp 138
Le pointeur est utilisé sans vérification préalable.
Toutes ces erreurs sont du même type, je ne m'étendrai donc pas sur elles plus en détail. Je donnerai le reste de la liste d'avertissement:
qt-V522-V575.txt .
Erreurs logiques dans les conditions
Défaut N71 QString QEdidParser::parseEdidString(const quint8 *data) { QByteArray buffer(reinterpret_cast<const char *>(data), 13);
Avertissement PVS-Studio: V547 CWE-570 Expression 'buffer [i] <' \ 040 '&& buffer [i]>' \ 176 '' est toujours false. qedidparser.cpp 169
La fonction doit effectuer l'action suivante «Remplacer les caractères non imprimables par un tiret». Mais ce n'est pas le cas. Examinons de plus près cette condition:
if (buffer[i] < '\040' && buffer[i] > '\176')
Cela n'a aucun sens. Un caractère ne peut pas être inférieur à '\ 040' et supérieur à '\ 176' en même temps. Dans la condition, vous devez utiliser l'opérateur '||'. Le bon code est:
if (buffer[i] < '\040' || buffer[i] > '\176')
Défaut N72Une erreur similaire, à cause de laquelle les utilisateurs de Windows n'ont pas de chance.
#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
L'analyseur génère deux avertissements à la fois:
- V590 CWE-571 Envisagez d'inspecter l'expression 'c <' a '&& c>' z '&& c <' A '&& c>' Z ''. L'expression est excessive ou contient une erreur d'impression. qdir.cpp 77
- V560 CWE-570 Une partie de l'expression conditionnelle est toujours fausse: c> 'z'. qdir.cpp 77
Une erreur logique est dans la condition:
if (c < 'a' && c > 'z' && c < 'A' && c > 'Z')
Si je comprends bien, le programmeur voulait trouver un caractère qui n'est pas une lettre de l'alphabet latin. Dans ce cas, la condition doit être la suivante:
if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z'))
Défaut N73 enum SelectionMode { NoSelection, SingleSelection, MultiSelection, ExtendedSelection, ContiguousSelection }; void QAccessibleTableCell::unselectCell() { QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection)) return; .... }
Avertissement PVS-Studio: V616 CWE-480 La constante nommée 'QAbstractItemView :: NoSelection' avec la valeur 0 est utilisée dans l'opération au niveau du bit. itemviews.cpp 976
La constante nommée
QAbstractItemView :: NoSelection est nulle. Par conséquent, la sous-expression
(selectionMode & QAbstractItemView :: NoSelection) n'a pas de sens. Ce sera toujours 0.
Je pense que cela devrait être écrit ici:
if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
Défaut N74Le code suivant est difficile à comprendre pour moi. Il a tort, mais je ne sais pas ce qu'il devrait être. Commenter une fonction ne m'aide pas non plus.
PVS-Studio Warning: V547 CWE-570 Expression 'message' is always false. qwindowscontext.cpp 802
Le programmeur suppose probablement que la fonction
FormatMessage modifiera la valeur du pointeur de
message . Mais ce n'est pas le cas. La
fonction FormatMessage ne peut pas modifier la valeur d'un pointeur, car elle est transmise à la fonction par valeur. Voici un prototype de cette fonction:
DWORD __stdcall FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments );
Fuites potentielles de mémoire
Défaut 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; } };
Avertissement PVS-Studio: V701 CWE-401 possible fuite de realloc (): lorsque realloc () échoue dans l'allocation de mémoire, le pointeur d'origine «enfants» est perdu. Pensez à affecter realloc () à un pointeur temporaire. makefiledeps.cpp 103
L'expansion du tampon est implémentée de manière dangereuse. Si la fonction
realloc ne peut pas allouer de mémoire, elle renverra
NULL . Ce
NULL sera immédiatement placé dans la variable
enfants et il n'y aura aucune possibilité de libérer le tampon alloué plus tôt. Une fuite de mémoire se produira.
Erreurs similaires:
qt-701.txt .
Divers
Défaut 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))) { .... }
Avertissement PVS-Studio: V610 CWE-758 Comportement non spécifié. Vérifiez l'opérateur de décalage '>>'. L'opérande gauche «(- 2147483647 - 1)» est négatif. qdrawhelper.cpp 4015
La valeur négative de
INT_MIN ne peut pas être décalée. Il s'agit d'un comportement non spécifié et vous ne pouvez pas vous fier au résultat d'une telle opération. Les bits les plus significatifs peuvent être égaux à 0 ou 1.
Défaut 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 Warning: V781 CWE-129 La valeur de la variable 'signal' est vérifiée après son utilisation. Il y a peut-être une erreur dans la logique du programme. Vérifiez les lignes: 397, 413. qobject.cpp 397
Une vérification
(signal <0) indique que la valeur de l'argument
signal peut être négative. Cependant, cet argument était précédemment utilisé pour indexer le tableau. Il s'avère que la vérification est effectuée trop tard. Le programme sera déjà interrompu.
Défaut 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; }
Avertissement PVS-Studio: V519 CWE-563 La variable 'lastNamespaceDeclaration' reçoit des valeurs successives deux fois. C'est peut-être une erreur. Vérifiez les lignes: 3188, 3194. qxmlstream.cpp 3194
Je vais souligner l'essence de l'erreur:
if (inEmptyElement) { lastNamespaceDeclaration = tag.namespaceDeclarationsSize; } lastNamespaceDeclaration = namespaceDeclarations.size();
Défaut N96 void QRollEffect::scroll() { .... if (currentHeight != totalHeight) { currentHeight = totalHeight * (elapsed/duration) + (2 * totalHeight * (elapsed%duration) + duration) / (2 * duration);
V519 CWE-563 La variable 'done' reçoit des valeurs successives deux fois. C'est peut-être une erreur. Vérifiez les lignes: 509, 511. qeffects.cpp 511
Tout est le même que dans le cas précédent. Notez la variable
done .
Conclusion
Même en regardant superficiellement le rapport, j'ai écrit près de 100 erreurs. Je suis satisfait des résultats de PVS-Studio.
Bien sûr, ces vérifications de code rares n'ont rien à voir avec l'amélioration de la qualité et de la fiabilité du code. Ils ne montrent que les capacités de l'analyseur de code. Des outils d'analyse statique doivent être appliqués régulièrement. Dans ce cas, ils réduisent le coût de la correction des bogues et protègent les applications de nombreuses vulnérabilités potentielles.
Merci de votre attention. Pour être au courant de nos nouvelles publications, je vous invite à vous abonner à l'une de nos chaînes:
- VK.com: pvsstudio_rus
- «Old school» RSS: viva64-blog-ru
- Twitter: @pvsstudio_rus
- Instagram: @pvsstudio_rus
- Télégramme: @pvsstudio_rus

Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Andrey Karpov.
Une troisième vérification de Qt 5 avec PVS-Studio