De tempos em tempos, nossa equipe verifica novamente os projetos sobre os quais já escrevemos artigos. Outro projeto verificado novamente foi o Qt. A última vez que testamos com o PVS-Studio em 2014. Desde 2014, o projeto começou a ser verificado regularmente com a ajuda da Coverity. Isso é interessante. Vamos ver se agora podemos encontrar erros interessantes usando o PVS-Studio.
Qt
Artigos anteriores:
Desta vez, o
Qt Base (Core, Gui, Widgets, Rede, ...) e o
super módulo Qt5 foram testados . Sobre o Qt Creator, planejamos escrever um artigo separado posteriormente. Para verificação, usamos o analisador estático PVS-Studio, cuja versão de teste pode ser
baixada do site.
Na minha opinião subjetiva, o código Qt se tornou melhor. Ao longo dos anos desde o último teste, muitos novos diagnósticos apareceram no analisador PVS-Studio. Apesar disso, durante o estudo de revisão dos avisos, não encontrei muitos erros para um projeto desse tamanho. Repito mais uma vez que esta é minha impressão individual. Não fiz nenhuma pesquisa especial sobre a densidade de erros naquele momento ou agora.
Provavelmente, verificações regulares usando o analisador estático do Coverity provavelmente afetaram a qualidade do código. Em 2014, com a ajuda do Coverity, o projeto Qt (
qt-project ) começou a ser verificado e, em 2016, o Qt Creator (
qt-creator ). Minha opinião: se você estiver desenvolvendo um projeto de código aberto, o
Coverity Scan pode ser uma boa solução gratuita que melhorará significativamente a qualidade e a confiabilidade de seus projetos.
No entanto, como o leitor pode adivinhar, se eu não tivesse notado algo interessante no relatório do PVS-Studio, não haveria artigo :). E como existe um artigo, isto é, defeitos. Vamos olhar para eles. No total, escrevi 96 erros.
Copiar e colar malsucedido
Vamos começar com os clássicos do gênero, quando a causa do erro é a falta de atenção. Esses erros são subestimados pelos programadores. Para quem ainda não leu, recomendo que você analise estes dois artigos:
Esses erros são interlíngua. Por exemplo, o segundo artigo fornece muitos exemplos de erros nas funções de comparação escritas em C, C ++ e C #. Agora, ao implementar o suporte à linguagem Java no PVS-Studio, encontramos os mesmos padrões de erro. Aqui, por exemplo, está um erro que encontramos recentemente na biblioteca do
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; } }
Se você observar atentamente, o campo
purchaseSequence será comparado a si mesmo. A opção correta:
return that.purchaseSequence.equals(this.purchaseSequence) && that.purchaseNumber == this.purchaseNumber;
Em geral, tudo está como sempre, e o analisador PVS-Studio terá que "vasculhar os estábulos augianos" em projetos Java. A propósito, convidamos todos a participar do teste da versão Beta do PVS-Studio for Java, que deve aparecer em um futuro próximo. Para fazer isso,
escreva-nos (selecione "Quero o analisador para Java").
Agora, de volta aos erros no projeto Qt.
Defeito N1 static inline int windowDpiAwareness(HWND hwnd) { return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1; }
PVS-Studio Warning: V501 CWE-571 Existem subexpressões idênticas 'QWindowsContext :: user32dll.getWindowDpiAwarenessContext' à esquerda e à direita do operador '&&'. qwindowscontext.cpp 150
Nenhuma explicação especial além da mensagem do analisador não é necessária aqui. Parece-me que a expressão deveria ter sido assim:
return QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext( QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd)) : -1;
Defeito N2, N3 void QReadWriteLockPrivate::release() { Q_ASSERT(!recursive); Q_ASSERT(!waitingReaders && !waitingReaders && !readerCount && !writerCount); freelist->release(id); }
PVS-Studio Warning: V501 CWE-571 Existem subexpressões idênticas à esquerda e à direita do operador '&&' :! WaitingReaders &&! WaitingReaders qreadwritelock.cpp 632
O erro está dentro da
condição da macro
Q_ASSERT , portanto, não é significativo. Mas ainda assim, isso é um erro. A variável
waitingReaders é verificada duas vezes. E, aparentemente, eles se esqueceram de verificar alguma outra variável.
Um erro idêntico foi encontrado na linha 625 do arquivo qreadwritelock.cpp. Vida longa Copiar e colar! :)
Defeito 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); } .... }
Aviso do PVS-Studio: V523 CWE-691 A instrução 'then' é equivalente à instrução 'else'. qgraphicsscene_bsp.cpp 179
Provavelmente, o bloco de texto foi copiado, mas eles esqueceram de corrigi-lo.
Defeito N5 enum FillRule { OddEvenFill, WindingFill }; QDataStream &operator>>(QDataStream &s, QPainterPath &p) { .... int fillRule; s >> fillRule; Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill); .... }
PVS-Studio Warning: V768 CWE-571 A constante de enumeração 'WindingFill' é usada como uma variável de um tipo booleano. qpainterpath.cpp 2479
Concordo, este é um belo erro de gravação!
Q_ASSERT não verifica nada, pois a condição é sempre verdadeira. A condição é verdadeira porque a constante nomeada
Qt :: WindingFill é 1.
Defeito 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 ler o aviso, tente identificar um erro de digitação. Ao adicionar uma imagem, ajudarei você a não ler a mensagem do analisador imediatamente :).
Aviso do PVS-Studio: V560 CWE-570 Uma parte da expressão condicional é sempre falsa: currentType == QMetaType :: Char. qvariant.cpp 3529
A condição "currentType == QMetaType :: Char" é verificada no primeiro
se . Se a condição for atendida, a variável
currentType receberá o valor
QMetaType :: UInt . Portanto, a variável
currentType não pode mais ser igual a
QMetaType :: Char . Portanto, o analisador relata que, no segundo
caso, a subexpressão "currentType == QMetaType :: Char" é sempre falsa.
De fato, o segundo
se deve ser assim:
if (targetTypeId == QMetaType::SChar || targetTypeId == QMetaType::Char) targetTypeId = QMetaType::UInt;
Nota de diagnóstico do V560O relatório encontrou muitos avisos do V560. No entanto, não os observei mais assim que encontrei um caso interessante para o artigo, que foi considerado acima como um defeito N6.
A grande maioria das mensagens V560 não pode ser chamada de falsa, mas não há uso delas. Em outras palavras, descrevê-los em um artigo não é interessante. Para deixar claro o que exatamente eu quero dizer, considere um desses 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()) {
Aviso PVS-Stuidio: V560 CWE-571 Uma parte da expressão condicional é sempre verdadeira: doc. qtextdocument.cpp 2992
O analisador está absolutamente correto que o ponteiro do
documento nem sempre é
nullptr quando é verificado novamente. Mas isso não é um erro, apenas o programador estava seguro. Você pode simplificar o código escrevendo:
if (doc->docHandle()) {
Defeito N7E o último caso, que pode ser classificado como erro de digitação. O erro ocorre devido a confusão nos nomes das constantes, que diferem apenas no caso da primeira 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) .... }
Aviso do PVS-Studio: V616 CWE-480 A constante nomeada 'CursorShowing' com o valor 0 é usada na operação bit a bit. qwindowscursor.cpp 669
Mais detalhadamente, eu já analisei esse erro em uma pequena nota separada: "
Mais uma vez, o analisador PVS-Studio mostrou-se mais atento que uma
pessoa ".
Falhas de segurança
De fato, todos os erros discutidos neste artigo podem ser chamados de defeitos de segurança. Todos eles são classificados de acordo com a
Enumeração de fraqueza comum (consulte ID do CWE nas mensagens do analisador). Se os erros são classificados como CWEs, eles são potencialmente um risco de segurança. Isso é explicado em mais detalhes na página
PVS-Studio SAST .
No entanto, gostaria de destacar uma série de erros em um grupo separado. Vamos dar uma olhada neles.
Defeito N8, N9 bool QLocalServerPrivate::addListener() { .... SetSecurityDescriptorOwner(pSD.data(), pTokenUser->User.Sid, FALSE); SetSecurityDescriptorGroup(pSD.data(), pTokenGroup->PrimaryGroup, FALSE); .... }
Avisos do PVS-Studio:
- V530 CWE-252 O valor de retorno da função 'SetSecurityDescriptorOwner' deve ser utilizado. qlocalserver_win.cpp 167
- V530 CWE-252 O valor de retorno da função 'SetSecurityDescriptorGroup' deve ser utilizado. qlocalserver_win.cpp 168
Existem várias funções relacionadas ao controle de acesso. As funções
SetSecurityDescriptorOwner e
SetSecurityDescriptorGroup estão entre elas.
Com essas funções, você precisa trabalhar com muito cuidado. Por exemplo, você deve verificar o status que eles retornam. O que acontece se a chamada para essas funções falhar? Adivinhar não é necessário, é necessário escrever código para lidar com esse caso.
Não é necessário tirar proveito da falta de verificação e transformar esses erros em vulnerabilidades. No entanto, este não é, em nenhum caso, um local de risco e você precisa escrever um código mais seguro.
Defeito N10 bool QLocalServerPrivate::addListener() { .... InitializeAcl(acl, aclSize, ACL_REVISION_DS); .... }
PVS-Studio Warning: V530 CWE-252 O valor de retorno da função 'InitializeAcl' deve ser utilizado. qlocalserver_win.cpp 144
A situação é semelhante à discutida acima.
Defeito N11, N12 static inline void sha1ProcessChunk(....) { .... quint8 chunkBuffer[64]; .... #ifdef SHA1_WIPE_VARIABLES .... memset(chunkBuffer, 0, 64); #endif }
PVS-Studio Warning: V597 CWE-14 O compilador pode excluir a chamada de função 'memset', usada para liberar o buffer 'chunkBuffer'. A função RtlSecureZeroMemory () deve ser usada para apagar os dados particulares. sha1.cpp 189
O compilador removerá a chamada de função
memset . Já muitas vezes em artigos analisei essa situação. Não tenho vontade de me repetir. Refiro-me ao artigo "
Limpeza segura de dados particulares ".
E outro erro está no mesmo arquivo sha1.cpp, na linha 247.
Ponteiros nulos
É hora de falar sobre indicadores. Houve muitos erros neste tópico.
Defeito N13 QByteArray &QByteArray::append(const char *str, int len) { if (len < 0) len = qstrlen(str); if (str && len) { .... }
Aviso do PVS-Studio: V595 CWE-476 O ponteiro 'str' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 2118, 2119. qbytearray.cpp 2118
A situação clássica é quando um ponteiro é usado no início e depois verificado quanto à igualdade
nullptr . Esse é um padrão de erro muito comum e o
vemos regularmente em quase todos os projetos.
Defeito 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; }
Aviso do PVS-Studio: V595 CWE-476 O ponteiro 'mobj' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 2671, 2672. qmetaobject.cpp 2671
Por precaução, trago o corpo da função
privada . Por alguma razão, às vezes os leitores começam a apresentar situações nas quais o código funcionará. Não entendo de onde vem essa desconfiança e o desejo de ver um recurso complicado por engano :). Por exemplo, alguém pode sugerir nos comentários que
priv é uma macro do formulário:
#define priv(A) foo(sizeof(A))
Então tudo vai funcionar.
Para evitar essas discussões, tento citar fragmentos de código onde todas as informações que confirmam a existência de um erro são fornecidas.
Portanto, o ponteiro
modj é desreferenciado e depois verificado.
Mais adiante, aparece o Copy-Paste "poderoso e terrível". Por causa do que exatamente o mesmo erro é detectado na função
isScoped :
bool QMetaEnum::isScoped() const { const int offset = priv(mobj->d.data)->revision >= 8 ? 2 : 1; return mobj && mobj->d.data[handle + offset] & EnumIsScoped; }
Aviso do PVS-Studio: V595 CWE-476 O ponteiro 'mobj' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 2683, 2684. qmetaobject.cpp 2683
Defeito N16-N21Considere outro exemplo e, penso, 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()); }
Aviso do PVS-Studio: V595 CWE-476 O ponteiro 'fragment.d' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 2238, 2241. qtextcursor.cpp 2238
Tudo a mesma coisa. Preste atenção na sequência do trabalho com o ponteiro armazenado na variável
fragment.d .
Outros erros deste tipo:
- V595 CWE-476 O ponteiro da 'janela' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 1846, 1848. qapplication.cpp 1846
- V595 CWE-476 O ponteiro da 'janela' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 1858, 1860. qapplication.cpp 1858
- V595 CWE-476 O ponteiro 'reply' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 492, 502. qhttpnetworkconnectionchannel.cpp 492
- V595 CWE-476 O ponteiro 'newHandle' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 877, 883. qsplitter.cpp 877
- V595 CWE-476 O ponteiro 'widget' foi utilizado antes de ser verificado no nullptr. Verifique as linhas: 2320, 2322. qwindowsvistastyle.cpp 2320
- De fato, há mais erros. Eu rapidamente me cansei de aprender os avisos do V595 e, para o artigo, já escrevi fragmentos de código suficientes.
Defeito N22-N33Há um código no qual um ponteiro é verificado e o
novo operador retorna. Isso é especialmente engraçado, devido ao fato de que existem muitos locais onde o resultado da função
malloc não é verificado (consulte o grupo de erros a seguir).
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; } .... }
Aviso do PVS-Studio: V668 CWE-571 Não há sentido em testar o ponteiro 'd-> unmap Pointer' contra nulo, pois a memória foi alocada usando o operador 'new'. A exceção será gerada no caso de erro de alocação de memória. qtranslator.cpp 596
A verificação do ponteiro não faz sentido, porque, no caso de um erro de alocação de memória, será
lançada uma exceção
std :: bad_alloc . Se você deseja que o
novo operador retorne
nullptr quando não houver memória suficiente, escreva:
d->unmapPointer = new (std::nothrow) char[d->unmapLength];
O analisador conhece esse uso do
novo operador e não emitirá um aviso nesse caso.
Outros erros: darei a eles o
arquivo qt-V668.txt .
Defeito N34-N70Como prometido, agora é a vez dos erros quando eles não verificam o resultado da chamada das funções
malloc ,
calloc ,
strdup , etc. Esses erros são mais graves do que parecem à primeira vista. Mais detalhes: "
Por que é importante verificar o que a função malloc retornou ."
SourceFiles::SourceFiles() { nodes = (SourceFileNode**)malloc(sizeof(SourceFileNode*)*(num_nodes=3037)); for(int n = 0; n < num_nodes; n++) nodes[n] = nullptr; }
Aviso do PVS-Studio: V522 CWE-690 Pode haver desreferenciação de um potencial 'nodo' de ponteiro nulo. Verifique as linhas: 138, 136. makefiledeps.cpp 138
O ponteiro é usado sem verificação prévia.
Todos esses erros são do mesmo tipo, por isso não vou me aprofundar neles com mais detalhes. Vou dar o restante da lista de aviso:
qt-V522-V575.txt .
Erros lógicos nas condições
Defeito N71 QString QEdidParser::parseEdidString(const quint8 *data) { QByteArray buffer(reinterpret_cast<const char *>(data), 13);
Aviso do PVS-Studio: V547 CWE-570 Expressão 'buffer [i] <' \ 040 '&& buffer [i]>' \ 176 '' é sempre falso. qedidparser.cpp 169
A função deve executar a seguinte ação “Substituir caracteres não imprimíveis pelo traço”. No entanto, ela não faz. Vamos dar uma olhada mais de perto nesta condição:
if (buffer[i] < '\040' && buffer[i] > '\176')
Isso não faz sentido. Um caractere não pode ser menor que '\ 040' e maior que '\ 176' ao mesmo tempo. Na condição, você deve usar o operador '||'. O código correto é:
if (buffer[i] < '\040' || buffer[i] > '\176')
Defeito N72Um erro semelhante, devido ao qual os usuários do Windows não têm sorte.
#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
O analisador gera dois avisos ao mesmo tempo:
- V590 CWE-571 Considere examinar a expressão 'c <' a '&& c>' z '&& c <' A '&& c>' Z ''. A expressão é excessiva ou contém uma impressão incorreta. qdir.cpp 77
- V560 CWE-570 Uma parte da expressão condicional é sempre falsa: c> 'z'. qdir.cpp 77
Um erro lógico está na condição:
if (c < 'a' && c > 'z' && c < 'A' && c > 'Z')
Pelo que entendi, o programador queria encontrar um caractere que não seja uma letra do alfabeto latino. Nesse caso, a condição deve ser assim:
if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z'))
Defeito N73 enum SelectionMode { NoSelection, SingleSelection, MultiSelection, ExtendedSelection, ContiguousSelection }; void QAccessibleTableCell::unselectCell() { QAbstractItemView::SelectionMode selectionMode = view->selectionMode(); if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection)) return; .... }
Aviso PVS-Studio: V616 CWE-480 A constante denominada 'QAbstractItemView :: NoSelection' com o valor 0 é usada na operação bit a bit. itemviews.cpp 976
A constante nomeada
QAbstractItemView :: NoSelection é zero. Portanto, a subexpressão
(selectionMode & QAbstractItemView :: NoSelection) não faz sentido. Será sempre 0.
Eu acho que deveria ser escrito aqui:
if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
Defeito N74O código a seguir é difícil de entender. Ele está errado, mas eu não sei o que ele deveria ser. Comentar sobre uma função também não me ajuda.
PVS-Studio Warning: V547 CWE-570 A expressão 'message' é sempre falsa. qwindowscontext.cpp 802
O programador provavelmente assume que a função
FormatMessage alterará o valor do ponteiro da
mensagem . Mas isso não é verdade. A
função FormatMessage não pode alterar o valor de um ponteiro, pois é passado para a função por valor. Aqui está um protótipo dessa função:
DWORD __stdcall FormatMessageW( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments );
Potenciais vazamentos de memória
Defeito 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; } };
Aviso do PVS-Studio: V701 CWE-401 realloc () possível vazamento: quando realloc () falha na alocação de memória, o ponteiro original 'filhos' é perdido. Considere atribuir realloc () a um ponteiro temporário. makefiledeps.cpp 103
A expansão do buffer é implementada de maneira perigosa. Se a função
realloc não puder alocar memória, ela retornará
NULL . Este
NULL será imediatamente colocado na variável
filhos e não haverá possibilidade de alguma forma liberar o buffer alocado anteriormente. Um vazamento de memória ocorrerá.
Erros semelhantes:
qt-701.txt .
Diversos
Defeito 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 Warning: V610 CWE-758 Comportamento não especificado. Verifique o operador de turno '>>'. O operando esquerdo '(- 2147483647 - 1)' é negativo. qdrawhelper.cpp 4015
O valor negativo de
INT_MIN não pode ser alterado. Esse é um comportamento não especificado e você não pode confiar no resultado dessa operação. Os bits mais significativos podem ser iguais a 0 ou 1.
Defeito 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 O valor da variável 'signal' é verificado após ser utilizado. Talvez haja um erro na lógica do programa. Verifique as linhas: 397, 413. qobject.cpp 397
Uma verificação
(sinal <0) indica que o valor do argumento do
sinal pode ser negativo. No entanto, esse argumento foi usado anteriormente para indexar a matriz. Acontece que a verificação é realizada tarde demais. O programa já será interrompido.
Defeito 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 Warning: V519 CWE-563 A variável 'lastNamespaceDeclaration' recebe valores duas vezes sucessivos. Talvez isso seja um erro. Verifique as linhas: 3188, 3194. qxmlstream.cpp 3194
Vou destacar a essência do erro:
if (inEmptyElement) { lastNamespaceDeclaration = tag.namespaceDeclarationsSize; } lastNamespaceDeclaration = namespaceDeclarations.size();
Defeito N96 void QRollEffect::scroll() { .... if (currentHeight != totalHeight) { currentHeight = totalHeight * (elapsed/duration) + (2 * totalHeight * (elapsed%duration) + duration) / (2 * duration);
V519 CWE-563 A variável 'done' recebe valores duas vezes sucessivamente. Talvez isso seja um erro. Verifique as linhas: 509, 511. qeffects.cpp 511
Tudo é o mesmo que no caso anterior. Observe a variável
concluída .
Conclusão
Mesmo analisando superficialmente o relatório, escrevi quase 100 erros. Estou satisfeito com os resultados do PVS-Studio.
Obviamente, essas verificações raras de código não têm nada a ver com a melhoria da qualidade e confiabilidade do código. Eles demonstram apenas os recursos do analisador de código. As ferramentas de análise estática devem ser aplicadas regularmente. Nesse caso, eles reduzem o custo de correção de bugs e protegem os aplicativos de muitas possíveis vulnerabilidades.
Obrigado pela atenção. Para acompanhar nossas novas publicações, convido você a se inscrever em um de nossos canais:
- VK.com: pvsstudio_rus
- RSS da “velha escola”: viva64-blog-ru
- Twitter: @pvsstudio_rus
- Instagram: @pvsstudio_rus
- Telegrama: @pvsstudio_rus

Se você deseja compartilhar este artigo com um público que fala inglês, use o link para a tradução: Andrey Karpov.
Uma terceira verificação do Qt 5 com o PVS-Studio