Tercera prueba Qt 5 con PVS-Studio

PVS-Studio y Qt

De vez en cuando, nuestro equipo revisa los proyectos sobre los cuales ya hemos escrito artículos. Otro de estos proyectos revisados ​​fue Qt. La última vez que lo probamos con PVS-Studio en 2014. Desde 2014, el proyecto comenzó a verificarse regularmente con la ayuda de Coverity. Esto es interesante Veamos si ahora podemos encontrar errores interesantes usando PVS-Studio.

Qt


Artículos anteriores:


Esta vez se probaron Qt Base (Core, Gui, Widgets, Network, ...) y Qt5 super module . Acerca de Qt Creator, planeamos escribir un artículo separado más adelante. Para la verificación, utilizamos el analizador estático PVS-Studio, una versión de prueba que puede descargar del sitio.

En mi opinión subjetiva, el código Qt ha mejorado. Durante los años transcurridos desde la última prueba, han aparecido muchos diagnósticos nuevos en el analizador PVS-Studio. A pesar de esto, durante el estudio de revisión de las advertencias, no encontré tantos errores para un proyecto de este tamaño. Repito una vez más que esta es mi impresión individual. No hice ninguna investigación especial sobre la densidad de errores ni entonces ni ahora.

Lo más probable es que las comprobaciones periódicas utilizando el analizador estático Coverity probablemente hayan afectado la calidad del código. En 2014, con la ayuda de Coverity, el proyecto Qt ( qt-project ) comenzó a comprobarse, y en 2016, el Qt Creator ( qt-creator ). Mi opinión: si está desarrollando un proyecto abierto, Coverity Scan puede ser una buena solución gratuita que mejorará significativamente la calidad y la confiabilidad de sus proyectos.

Sin embargo, como el lector puede adivinar, si no hubiera notado nada interesante en el informe de PVS-Studio, entonces no habría habido ningún artículo :). Y como hay un artículo, es decir, defectos. Miremos a ellos. En total, escribí 96 errores.

Copiar y pegar errores tipográficos


Comencemos con los clásicos del género, cuando la causa del error es la falta de atención. Estos errores son subestimados por los programadores. Para aquellos que aún no han leído, les recomiendo que miren estos dos artículos:


Estos errores son interlenguaje. Por ejemplo, el segundo artículo ofrece muchos ejemplos de errores en las funciones de comparación escritas en C, C ++ y C #. Ahora, al implementar el soporte de lenguaje Java en PVS-Studio, encontramos los mismos patrones de error. Aquí, por ejemplo, hay un error que encontramos recientemente en la biblioteca de 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 observa de cerca, resulta que el campo de compraSecuencia se compara con él mismo. La opción correcta:

 return that.purchaseSequence.equals(this.purchaseSequence) && that.purchaseNumber == this.purchaseNumber; 

En general, todo es como siempre, y el analizador PVS-Studio tendrá que "rastrillar los establos de Augean" en proyectos Java. Por cierto, invitamos a todos a participar en la prueba de la versión Beta de PVS-Studio para Java, que aparecerá en un futuro próximo. Para hacer esto, escríbanos (seleccione "Quiero el analizador para Java").

Ahora volvamos a los errores en el proyecto Qt.

Defecto N1

 static inline int windowDpiAwareness(HWND hwnd) { return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; } 

Advertencia de PVS-Studio: V501 CWE-571 Hay subexpresiones idénticas 'QWindowsContext :: user32dll.getWindowDpiAwarenessContext' a la izquierda y a la derecha del operador '&&'. qwindowscontext.cpp 150

Aquí no se requiere ninguna explicación especial además del mensaje del analizador. Me parece que la expresión debería haber sido así:

 return QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; 

Defecto N2, N3

 void QReadWriteLockPrivate::release() { Q_ASSERT(!recursive); Q_ASSERT(!waitingReaders && !waitingReaders && !readerCount && !writerCount); freelist->release(id); } 

Advertencia de PVS-Studio: V501 CWE-571 Hay subexpresiones idénticas a la izquierda y a la derecha del operador '&&' :! WaitingReaders &&! WaitingReaders qreadwritelock.cpp 632

El error está dentro de la condición de macro Q_ASSERT , por lo que no es significativo. Pero aún así, esto es un error. La variable waitingReaders se verifica dos veces . Y aparentemente se olvidaron de verificar alguna otra variable.

Se encuentra un error idéntico en la línea 625 del archivo qreadwritelock.cpp. ¡Viva Copy-Paste! :)

Defecto 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); } .... } 

Advertencia de PVS-Studio: V523 CWE-691 La declaración 'then' es equivalente a la declaración 'else'. qgraphicsscene_bsp.cpp 179

Lo más probable es que se haya copiado el bloque de texto, pero se olvidaron de corregirlo.

Defecto N5

 enum FillRule { OddEvenFill, WindingFill }; QDataStream &operator>>(QDataStream &s, QPainterPath &p) { .... int fillRule; s >> fillRule; Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill); .... } 

Advertencia de PVS-Studio: V768 CWE-571 La constante de enumeración 'WindingFill' se usa como una variable de tipo booleano. qpainterpath.cpp 2479

De acuerdo, esta es una hermosa blooper! Q_ASSERT no verifica nada, ya que la condición siempre es verdadera. La condición es verdadera porque la constante nombrada Qt :: WindingFill es 1.

Defecto 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; .... } 

Antes de leer la advertencia, intente detectar un error tipográfico usted mismo. Al agregar una imagen, te ayudaré a no leer el mensaje del analizador de inmediato :).

Hora de pensar


Advertencia de PVS-Studio: V560 CWE-570 Una parte de la expresión condicional siempre es falsa: currentType == QMetaType :: Char. qvariant.cpp 3529

La condición "currentType == QMetaType :: Char" se verifica en el primer if . Si se cumple la condición, a la variable currentType se le asigna el valor QMetaType :: UInt . Por lo tanto, la variable currentType ya no puede ser igual a QMetaType :: Char . Por lo tanto, el analizador informa que en el segundo if, la subexpresión "currentType == QMetaType :: Char" siempre es falsa.

De hecho, el segundo si debería ser así:

 if (targetTypeId == QMetaType::SChar || targetTypeId == QMetaType::Char) targetTypeId = QMetaType::UInt; 


Nota de diagnóstico de V560

El informe encontró muchas advertencias V560. Sin embargo, ya no los miré tan pronto como encontré un caso interesante para el artículo, que se consideró anteriormente como un defecto N6.

La gran mayoría de los mensajes V560 no se pueden llamar falsos, pero no sirven de nada. En otras palabras, describirlos en un artículo no es interesante. Para aclarar lo que quiero decir exactamente, considere uno de esos casos.

 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()) { // <= .... } 

Advertencia PVS-Stuidio: V560 CWE-571 Una parte de la expresión condicional siempre es cierta: doc. qtextdocument.cpp 2992

El analizador tiene toda la razón de que el puntero doc no siempre es nullptr cuando se vuelve a comprobar. Pero esto no es un error, solo el programador estaba a salvo. Puede simplificar el código escribiendo:

 if (doc->docHandle()) { 

Defecto N7

Y el último caso, que se puede clasificar como un error tipográfico. El error ocurre debido a la confusión en los nombres de las constantes, que difieren solo en el caso de la primera letra.

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

Advertencia de PVS-Studio: V616 CWE-480 La constante con nombre 'CursorShowing' con el valor de 0 se utiliza en la operación bit a bit. qwindowscursor.cpp 669

Con más detalle, ya analicé este error en una pequeña nota separada: " Una vez más, el analizador PVS-Studio resultó ser más atento que una persona ".

Fallas de seguridad


De hecho, todos los errores que se analizan en este artículo pueden denominarse defectos de seguridad. Todos ellos se clasifican según la enumeración de debilidad común (ver ID de CWE en los mensajes del analizador). Si los errores se clasifican como CWE, son potencialmente un riesgo de seguridad. Esto se explica con más detalle en la página PVS-Studio SAST .

Sin embargo, me gustaría señalar una serie de errores en un grupo separado. Echemos un vistazo a ellos.

Defecto N8, N9

 bool QLocalServerPrivate::addListener() { .... SetSecurityDescriptorOwner(pSD.data(), pTokenUser->User.Sid, FALSE); SetSecurityDescriptorGroup(pSD.data(), pTokenGroup->PrimaryGroup, FALSE); .... } 

Advertencias de PVS-Studio:

  • V530 CWE-252 Se requiere el valor de retorno de la función 'SetSecurityDescriptorOwner'. qlocalserver_win.cpp 167
  • V530 CWE-252 Para poder utilizar el valor de retorno de la función 'SetSecurityDescriptorGroup'. qlocalserver_win.cpp 168

Hay varias funciones relacionadas con el control de acceso. Las funciones SetSecurityDescriptorOwner y SetSecurityDescriptorGroup se encuentran entre ellas.

Con tales funciones, debe trabajar con mucho cuidado. Por ejemplo, debe verificar el estado que devuelven. ¿Qué sucede si falla la llamada a estas funciones? No es necesario adivinar, es necesario escribir código para manejar este caso.

No es necesario aprovechar la falta de verificación y convertir dichos errores en vulnerabilidades. Sin embargo, este no es en ningún caso un lugar de riesgo, y debe escribir un código más seguro.

Defecto N10

 bool QLocalServerPrivate::addListener() { .... InitializeAcl(acl, aclSize, ACL_REVISION_DS); .... } 

Advertencia de PVS-Studio: V530 CWE-252 Para poder utilizar el valor de retorno de la función 'InitializeAcl'. qlocalserver_win.cpp 144

La situación es similar a la discutida anteriormente.

Defecto N11, N12

 static inline void sha1ProcessChunk(....) { .... quint8 chunkBuffer[64]; .... #ifdef SHA1_WIPE_VARIABLES .... memset(chunkBuffer, 0, 64); #endif } 

Advertencia de PVS-Studio: V597 CWE-14 El compilador podría eliminar la llamada a la función 'memset', que se utiliza para vaciar el búfer 'chunkBuffer'. La función RtlSecureZeroMemory () debe usarse para borrar los datos privados. sha1.cpp 189

El compilador eliminará la llamada a la función memset . Ya muchas veces en artículos analicé esta situación. No tengo ganas de repetirme. Me refiero al artículo " Limpieza segura de datos privados ".

Y otro error está en el mismo archivo sha1.cpp, en la línea 247.

Punteros nulos


Es hora de hablar sobre punteros. Hubo muchos errores en este tema.

Defecto N13

 QByteArray &QByteArray::append(const char *str, int len) { if (len < 0) len = qstrlen(str); if (str && len) { .... } 

Advertencia de PVS-Studio: V595 CWE-476 El puntero 'str' se utilizó antes de verificarlo con nullptr. Líneas de verificación: 2118, 2119. qbytearray.cpp 2118

La situación clásica es cuando se usa un puntero al principio y luego se verifica la igualdad nula . Este es un patrón de error muy común, y lo vemos regularmente en casi todos los proyectos.

Defecto 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; } 

Advertencia de PVS-Studio: V595 CWE-476 El puntero 'mobj' se utilizó antes de que se verificara contra nullptr. Líneas de verificación: 2671, 2672. qmetaobject.cpp 2671

Por si acaso, traigo el cuerpo de la función priv . Por alguna razón, a veces los lectores comienzan a pensar en situaciones en las que el código funcionará. No entiendo de dónde viene esta desconfianza y el deseo de ver una característica engañosa por error :). Por ejemplo, alguien puede sugerir en los comentarios que priv es una macro de la forma:

 #define priv(A) foo(sizeof(A)) 

Entonces todo funcionará.

Para evitar tales discusiones, trato de citar fragmentos de código donde se proporciona toda la información que confirma la existencia de un error.

Entonces, el puntero modj se desreferencia y luego se verifica.

Más adelante en la escena llega el "poderoso y terrible" Copy-Paste. Debido a que se detecta exactamente el mismo error en la función isScoped :

 bool QMetaEnum::isScoped() const { const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1; return mobj && mobj->d.data[handle + offset] & EnumIsScoped; } 

Advertencia de PVS-Studio: V595 CWE-476 El puntero 'mobj' se utilizó antes de que se verificara contra nullptr. Líneas de verificación: 2683, 2684. qmetaobject.cpp 2683

Defecto N16-N21

Considere otro ejemplo y, creo, suficiente.

 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()); } 

Advertencia de PVS-Studio: V595 CWE-476 El puntero 'fragment.d' se utilizó antes de verificarlo con nullptr. Líneas de verificación: 2238, 2241. qtextcursor.cpp 2238

De todos modos Preste atención a la secuencia de trabajo con el puntero almacenado en el fragmento variable.d.

Otros errores de este tipo:

  • V595 CWE-476 El puntero 'ventana' se utilizó antes de que se verificara contra nullptr. Líneas de verificación: 1846, 1848. qapplication.cpp 1846
  • V595 CWE-476 El puntero 'ventana' se utilizó antes de que se verificara contra nullptr. Líneas de verificación: 1858, 1860. qapplication.cpp 1858
  • V595 CWE-476 El puntero de 'respuesta' se utilizó antes de verificarlo con nullptr. Verifique las líneas: 492, 502. qhttpnetworkconnectionchannel.cpp 492
  • V595 CWE-476 El puntero 'newHandle' se utilizó antes de que se verificara contra nullptr. Líneas de verificación: 877, 883. qsplitter.cpp 877
  • V595 CWE-476 El puntero 'widget' se utilizó antes de que se verificara contra nullptr. Líneas de verificación: 2320, 2322. qwindowsvistastyle.cpp 2320
  • De hecho, hay más errores. Rápidamente me cansé de aprender las advertencias V595, y para el artículo ya escribí suficientes fragmentos de código.

Defecto N22-N33

Hay un código en el que se comprueba un puntero que devuelve el nuevo operador. Esto es especialmente divertido en medio del hecho de que hay muchos lugares donde no se verifica el resultado de la función malloc (consulte el siguiente grupo de errores).

 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; } .... } 

Advertencia de PVS-Studio: V668 CWE-571 No tiene sentido probar el puntero 'd-> unmap Pointer' contra nulo, ya que la memoria se asignó utilizando el operador 'nuevo'. La excepción se generará en caso de error de asignación de memoria. qtranslator.cpp 596

Comprobar el puntero no tiene sentido, porque en caso de un error de asignación de memoria, se lanzará una excepción std :: bad_alloc . Si desea que el nuevo operador devuelva nullptr cuando no hay suficiente memoria, debe escribir:

 d->unmapPointer = new (std::nothrow) char[d->unmapLength]; 

El analizador conoce este uso del nuevo operador y no daría una advertencia en este caso.

Otros errores: les daré el archivo qt-V668.txt .

Defecto N34-N70

Como se prometió, ahora es el turno de los errores cuando no verifican el resultado de llamar a las funciones malloc , calloc , strdup , etc. Estos errores son más graves de lo que parece a primera vista. Más detalles: " ¿Por qué es importante verificar qué devolvió la función malloc ?"

 SourceFiles::SourceFiles() { nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037)); for(int n = 0; n < num_nodes; n++) nodes[n] = nullptr; } 

Advertencia de PVS-Studio: V522 CWE-690 Puede haber una desreferenciación de un potencial 'nodo' de puntero nulo. Líneas de verificación: 138, 136. makefiledeps.cpp 138

El puntero se usa sin verificación previa.

Todos estos errores son del mismo tipo, por lo que no me detendré en ellos con más detalle. Daré el resto de la lista de advertencia: qt-V522-V575.txt .

Errores lógicos en las condiciones.


Defecto 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()); } 

Advertencia de PVS-Studio: V547 CWE-570 Expresión 'buffer [i] <' \ 040 '&& buffer [i]>' \ 176 '' siempre es falso. qedidparser.cpp 169

La función debe realizar la siguiente acción "Reemplazar caracteres no imprimibles con guión". Sin embargo, ella no. Echemos un vistazo más de cerca a esta condición:

 if (buffer[i] < '\040' && buffer[i] > '\176') 

No tiene sentido Un carácter no puede ser menor que '\ 040' y mayor que '\ 176' al mismo tiempo. En esta condición, debe usar el operador '||'. El código correcto es:

 if (buffer[i] < '\040' || buffer[i] > '\176') 

Defecto N72

Un error similar, debido a que los usuarios de Windows no tienen suerte.

 #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 

El analizador genera dos advertencias a la vez:

  • V590 CWE-571 Considere inspeccionar la expresión 'c <' a '&& c>' z '&& c <' A '&& c>' Z ''. La expresión es excesiva o contiene un error de imprenta. qdir.cpp 77
  • V560 CWE-570 Una parte de la expresión condicional siempre es falsa: c> 'z'. qdir.cpp 77

Un error lógico está en la condición:

 if (c < 'a' && c > 'z' && c < 'A' && c > 'Z') 

Según tengo entendido, el programador quería encontrar un personaje que no sea una letra del alfabeto latino. En este caso, la condición debería ser así:

 if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) 

Defecto N73

 enum SelectionMode { NoSelection, SingleSelection, MultiSelection, ExtendedSelection, ContiguousSelection }; void QAccessibleTableCell::unselectCell() { QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection)) return; .... } 

Advertencia de PVS-Studio: V616 CWE-480 La constante denominada 'QAbstractItemView :: NoSelection' con el valor de 0 se utiliza en la operación bit a bit. itemviews.cpp 976

La constante nombrada QAbstractItemView :: NoSelection es cero. Por lo tanto, la subexpresión (selectionMode & QAbstractItemView :: NoSelection) no tiene sentido. Siempre será 0.

Creo que debería escribirse aquí:

 if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection)) 

Defecto N74

El siguiente código es difícil de entender para mí. Está equivocado, pero no sé qué debería ser. Comentar una función tampoco me ayuda.

 // 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())); } 

Advertencia de PVS-Studio: V547 CWE-570 La expresión 'mensaje' siempre es falsa. qwindowscontext.cpp 802

El programador probablemente asume que la función FormatMessage cambiará el valor del puntero del mensaje . Pero esto no es así. La función FormatMessage no puede cambiar el valor de un puntero, ya que se pasa a la función por valor. Aquí hay un prototipo de esta función:

 DWORD __stdcall FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments ); 


Posibles fugas de memoria


Defecto 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; } }; 

Advertencia de PVS-Studio: V701 CWE-401 realloc () posible fuga: cuando realloc () falla al asignar memoria, se pierde el puntero original 'hijos'. Considere asignar realloc () a un puntero temporal. makefiledeps.cpp 103

La expansión de la memoria intermedia se implementa de manera peligrosa. Si la función realloc no puede asignar memoria, devolverá NULL . Este NULL se colocará inmediatamente en la variable secundaria y no habrá posibilidad de liberar de alguna manera el búfer asignado anteriormente. Se producirá una pérdida de memoria.

Errores similares: qt-701.txt .

Misceláneo


Defecto 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))) { .... } 

Advertencia de PVS-Studio: V610 CWE-758 Comportamiento no especificado. Verifique el operador de turno '>>'. El operando izquierdo '(- 2147483647 - 1)' es negativo. qdrawhelper.cpp 4015

El valor negativo de INT_MIN no se puede desplazar. Este es un comportamiento no especificado, y no puede confiar en el resultado de dicha operación. Los bits más significativos pueden ser iguales a 0 o 1.

Defecto N94

 void QObjectPrivate::addConnection(int signal, Connection *c) { .... if (signal >= connectionLists->count()) connectionLists->resize(signal + 1); ConnectionList &connectionList = (*connectionLists)[signal]; .... if (signal < 0) { .... } 

Advertencia de PVS-Studio: V781 CWE-129 El valor de la variable 'señal' se verifica después de su uso. Quizás haya un error en la lógica del programa. Verifique las líneas: 397, 413. qobject.cpp 397

Una comprobación (señal <0) indica que el valor del argumento de la señal puede ser negativo. Sin embargo, este argumento se utilizó anteriormente para indexar la matriz. Resulta que la verificación se realiza demasiado tarde. El programa ya estará interrumpido.

Defecto 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; } 

Advertencia de PVS-Studio: V519 CWE-563 La variable 'lastNamespaceDeclaration' recibe valores asignados dos veces sucesivamente. Quizás esto sea un error. Verifique las líneas: 3188, 3194. qxmlstream.cpp 3194

Destacaré la esencia del error:

 if (inEmptyElement) { lastNamespaceDeclaration = tag.namespaceDeclarationsSize; } lastNamespaceDeclaration = namespaceDeclarations.size(); 

Defecto 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 A la variable 'hecho' se le asignan valores dos veces sucesivas. Quizás esto sea un error. Verifique las líneas: 509, 511. qeffects.cpp 511

Todo es igual que en el caso anterior. Tenga en cuenta la variable hecha .

Conclusión


Incluso mirando el informe superficialmente, escribí casi 100 errores. Estoy satisfecho con los resultados de PVS-Studio.

Por supuesto, tales comprobaciones de códigos raros no tienen nada que ver con mejorar la calidad y la confiabilidad del código. Solo demuestran las capacidades del analizador de código. Las herramientas de análisis estático deben aplicarse regularmente. En este caso, reducen el costo de corregir errores y protegen las aplicaciones de muchas vulnerabilidades potenciales.

Gracias por su atencion Para mantenerse al tanto de nuestras nuevas publicaciones, lo invito a suscribirse a uno de nuestros canales:
  1. VK.com: pvsstudio_rus
  2. RSS "Vieja escuela": viva64-blog-ru
  3. Twitter: @pvsstudio_rus
  4. Instagram: @pvsstudio_rus
  5. Telegrama: @pvsstudio_rus



Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace a la traducción: Andrey Karpov. Una tercera comprobación de Qt 5 con PVS-Studio

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


All Articles