Checking the Qt 5 Framework

    Qt and PVS-Studio
    Static code analysis tools allow you to eliminate many errors even at the stage of writing the program text. For example, typos can be quickly identified and eliminated. Some programmers are sincerely sure that they do not make typos and silly mistakes. This is not true. Everyone makes such mistakes. This article will serve as a good demo. Typos can be found even in such a quality and tested project as Qt.

    Qt


    Qt is a cross-platform software development toolkit in the C ++ programming language. Allows you to run software written with its help in most modern operating systems by simply compiling a program for each OS without changing the source code. It includes all the main classes that may be required when developing application software, ranging from GUI elements to classes for working with the network, databases, and XML. Qt is fully object oriented, easily extensible, and supports component programming techniques. [source: Wikipedia]

    Links:We will work with Qt version 5.2.1. For analysis, we use PVS-Studio version 5.15.

    I want to draw attention to the fact that PVS-Studio managed to find errors, despite the fact that the Qt project was checked using the Klocwork and Coverity analyzers. I do not know how regularly these analyzers are used. However, Klocwork and Coverity are mentioned in bugtracker and ChangeLog-xxx files. I also found a mention on the Internet that Qt is regularly checked using PC-lint.

    Features of Qt project validation


    For a change, we tested Qt with the new mechanism introduced in PVS-Studio Standalone. Nobody knows about the mechanism yet, and from time to time we will remind in the articles about its existence. What is this new mysterious and beautiful mechanism?

    It is sometimes difficult to verify a project using PVS-Studio if it is built using nmake and the like. It is required to integrate PVS-Studio into the assembly, which is not so simple. At the very least, this clearly makes it difficult to quickly try and evaluate the tool.

    Now in PVS-Studio a new operating mode has appeared, which will greatly facilitate the work with such projects. The analyzer can monitor with what parameters the compiler is launched and collects all the information necessary for verification. It is enough to tell the analyzer when to start surveillance and when to stop it.

    Compiler tracking can be done both from the application GUI and from the command line. More details on how all this works and how to use the new mode are described in the article:

    Evgeny Ryzhkov. PVS-Studio now supports any build system on Windows and any compiler. Easy and out of the box .

    This article describes how the Qt project was tested in command-line monitoring start mode.

    Be sure to ask to read this article so that there are less misunderstandings. For example, while compilation of a project is being monitored, you cannot do programming in parallel. If you compile files from another project, information about them will be collected, and they will also be checked. As a result, messages related to another project will be included in the report. It will turn out a mess.

    Validation Results


    In general, I got the following impression about the code:

    Qt code is high-quality and practically does not contain errors associated with dangerous features of the C ++ language. But a lot of ordinary typos.

    This article will demonstrate well that regardless of professionalism, all developers make typos. The benefit of static code analysis was, is and will be. Suppose the analyzer found 10 typos on a single run. So, if you use it regularly, by now it would have prevented hundreds or thousands of mistakes. This is a huge time saver. It is much more profitable to detect an error immediately after it appears in the code than to find it when debugging the code or thanks to a user complaint.

    Plunge into the wonderful world of typos


    Welcome to a wondrous world of typos

    Typo N1
    bool QWindowsUser32DLL::initTouch()
    {
      QSystemLibrary library(QStringLiteral("user32"));
      registerTouchWindow   = ....;
      unregisterTouchWindow = ....;
      getTouchInputInfo     = ....;
      closeTouchInputHandle = ....;
      return registerTouchWindow &&
             unregisterTouchWindow &&
             getTouchInputInfo &&
             getTouchInputInfo;
    }

    PVS-Studio Warning: V501 There are identical sub-expressions 'getTouchInputInfo' to the left and to the right of the '&&' operator. qwindowscontext.cpp 216

    Four variables are assigned values. These four variables should be checked. But because of a typo only 3 is checked. In the last line, instead of 'getTouchInputInfo' should be written 'closeTouchInputHandle'.

    Typo N2
    QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(....)
    {
      ....
      int iw = gm.width.toInt();
      int ih = gm.height.toInt();
      if (iw <= 0 || iw <= 0)
        return 0;
      ....
    }

    PVS-Studio Warning: V501 There are identical sub-expressions to the left and to the right of the '||' operator: iw <= 0 || iw <= 0 qwindowsfontengine.cpp 1095

    There is no height check stored in the variable 'ih'.

    Typo N3, N4

    This error is related to tests. A good example of how static analysis complements unit tests. More on this topic: " How Static Analysis Supplements TDD ."
    inline bool qCompare(QImage const &t1, QImage const &t2, ....)
    {
      ....
      if (t1.width() != t2.width() || t2.height() != t2.height()) {
      ....
    }

    PVS-Studio warning: V501 There are identical sub-expressions to the left and to the right of the '! =' Operator: t2.height ()! = T2.height () qtest_gui.h 101

    The function of comparing two images incorrectly compares them height. Rather, it does not compare at all.

    Error propagated using Copy-Paste. Exactly the same comparison can be seen in the same file just below (line 135).

    Typo N5

    I'm sorry that I ugly formatted the code. The lines were too long.
    void QXmlSimpleReader::setFeature(
      const QString& name, bool enable)
    {
      ....
      } else if (   name == QLatin1String(
        "http://trolltech.com/xml/features/report-start-end-entity")
                 || name == QLatin1String(
        "http://trolltech.com/xml/features/report-start-end-entity"))
      {
      ....
    }

    PVS-Studio Warning: V501 There are identical sub-expressions to the left and to the right of the '||' operator. qxml.cpp 3249 The

    variable 'name' is compared twice to the same string. Above in the code, there is a similar comparison. There the variable is compared with these two with strings:
    • http: // trolltech.com / xml / features / report-whitespace-only-CharData
    • http: // qt-project.org / xml / features / report-whitespace-only-CharData
    By analogy, we can assume that in the above code the variable 'name' should have been compared with:
    • http: // trolltech.com / xml / features / report-start-end-entity
    • http: // qt-project.org / xml / features / report-start-end-entity
    Typo N6, N7, N8, N9
    QString DayTimeDuration::stringValue() const
    {
      ....
      if(!m_hours && !m_minutes && !m_seconds && !m_seconds)
      ....
    }

    PVS-Studio Warning: V501 There are identical sub-expressions '! M_seconds' to the left and to the right of the '&&' operator. qdaytimeduration.cpp 148

    Forgot about milliseconds. Milliseconds are stored in the variable 'm_mseconds'. The check should be like this:
    if(!m_hours && !m_minutes && !m_seconds && !m_mseconds)

    An identical error with milliseconds is in three more places:
    • qdaytimeduration.cpp 170
    • qduration.cpp 167
    • qduration.cpp 189
    Typo N10
    QV4::ReturnedValue
    QQuickJSContext2DPrototype::method_getImageData(
      QV4::CallContext *ctx)
    {
      ....
      qreal x = ctx->callData->args[0].toNumber();
      qreal y = ctx->callData->args[1].toNumber();
      qreal w = ctx->callData->args[2].toNumber();
      qreal h = ctx->callData->args[3].toNumber();
      if (!qIsFinite(x) || !qIsFinite(y) ||
          !qIsFinite(w) || !qIsFinite(w))
      ....
    }

    PVS-Studio Warning: V501 There are identical sub-expressions '! QIsFinite (w)' to the left and to the right of the '||' operator. qquickcontext2d.cpp 3305

    There is no verification of the variable 'h'. Instead, the variable 'w' is checked twice.

    Typo N11
    AtomicComparator::ComparisonResult
    IntegerComparator::compare(const Item &o1,
                               const AtomicComparator::Operator,
                               const Item &o2) const
    {
      const Numeric *const num1 = o1.as();
      const Numeric *const num2 = o1.as();
      if(num1->isSigned() || num2->isSigned())
      ....
    }

    V656 Variables 'num1', 'num2' are initialized through the call to the same function. It's probably an error or un-optimized code. Consider inspecting the 'o1.as <Numeric> ()' expression. Check lines: 220, 221. qatomiccomparators.cpp 221 The

    variables 'num1' and 'num2' are initialized with the same value. Both of these variables are checked below. This is suspicious. After all, it is enough to check the value of only one variable.

    Most likely, the variable 'num2' should be initialized with an expression where the argument 'o2' is used:
    const Numeric *const num1 = o1.as();
    const Numeric *const num2 = o2.as();

    Typo N12
    void Atlas::uploadBgra(Texture *texture)
    {
      const QRect &r = texture->atlasSubRect();
      QImage image = texture->image();
      if (image.format() != QImage::Format_ARGB32_Premultiplied ||
          image.format() != QImage::Format_RGB32) {
      ....
    }

    V547 Expression is always true. Probably the '&&' operator should be used here. qsgatlastexture.cpp 271 The

    condition in this code does not make sense. She is always true. To make it easier to understand what is wrong here, I will give a simplified example:
    int a = ...;
    if (a != 1 || a != 2)

    A variable will always be unequal to something.

    I do not know what the correct code should look like. Maybe it should be like this:
    if (image.format() == QImage::Format_ARGB32_Premultiplied ||
        image.format() == QImage::Format_RGB32) {

    Or so:
    if (image.format() != QImage::Format_ARGB32_Premultiplied &&
        image.format() != QImage::Format_RGB32) {

    Typo N13
    void QDeclarativeStateGroupPrivate::setCurrentStateInternal(
      const QString &state, 
      bool ignoreTrans)
    {
      ....
      QDeclarativeTransition *transition =
        (ignoreTrans || ignoreTrans) ?
          0 : findTransition(currentState, state);
      ....
    }

    PVS-Studio Warning: V501 There are identical sub-expressions to the left and to the right of the '||' operator: ignoreTrans || ignoreTrans qdeclarativestategroup.cpp 442

    Something is wrong here. How exactly they wanted to write a check is not clear to me.

    Typo N14
    QV4::ReturnedValue
    QQuickJSContext2DPrototype::method_createPattern(....)
    {
      ....
      if (repetition == QStringLiteral("repeat") ||
          repetition.isEmpty()) {
        pattern->patternRepeatX = true;
        pattern->patternRepeatY = true;
      } else if (repetition == QStringLiteral("repeat-x")) {
        pattern->patternRepeatX = true;
      } else if (repetition == QStringLiteral("repeat-y")) {
        pattern->patternRepeatY = true;
      } else if (repetition == QStringLiteral("no-repeat")) {
        pattern->patternRepeatY = false;
        pattern->patternRepeatY = false;
      } else {
        //TODO: exception: SYNTAX_ERR
      }
      ....
    }

    PVS-Studio warning: V519 The 'pattern-> patternRepeatY' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 1775, 1776. qquickcontext2d.cpp 1776

    Two times in a row the variable 'patternRepeatY' is assigned:
    pattern->patternRepeatY = false;
    pattern->patternRepeatY = false;

    I think it should be written here:
    } else if (repetition == QStringLiteral("no-repeat")) {
      pattern->patternRepeatX = false;
      pattern->patternRepeatY = false;
    } else {

    Misuse of C ++


    Misuse of the C ++ language

    As I said, most errors are ordinary typos. There are almost no errors associated with improper use of the C ++ language. But a couple of such errors were still found.

    Beautiful error related to operation priority
    bool QConfFileSettingsPrivate::readIniLine(....)
    {
      ....
      char ch;
      while (i < dataLen &&
             ((ch = data.at(i) != '\n') && ch != '\r'))
        ++i;
      ....
    }

    V593 Consider reviewing the expression of the 'A = B! = C' kind. The expression is calculated as following: 'A = (B! = C)'. qsettings.cpp 1702

    The loop is designed to find the end of a line. The end of line character is the character '\ n' or '\ r'.

    Inside the condition, a character must be taken and compared with '\ n' and '\ r'. The error occurs because the priority of the '! =' Operator is higher than the operator '='. Because of this, it is not the character code that is written to the variable 'ch', but 'true' or 'false'. As a result, the comparison '\ r' no longer plays a role.

    We place the brackets so that the error is better noticeable:
    while (i < dataLen &&
           ((ch = (data.at(i) != '\n')) && ch != '\r'))

    Due to an error, only the '\ n' character is considered the end of the line. If the lines end with the character '\ r', the function will not work correctly.

    The correct code is:
    while (i < dataLen &&
           (ch = data.at(i)) != '\n' && ch != '\r')

    Loss of accuracy
    bool QWindowsTabletSupport::translateTabletPacketEvent()
    {
      ....
      const double radAzim =
        (packet.pkOrientation.orAzimuth / 10) * (M_PI / 180);
      ....
    }

    V636 The 'packet.pkOrientation.orAzimuth / 10' expression was implicitly casted from 'int' type to 'double' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double) (X) / Y ;. qwindowstabletsupport.cpp 467 The

    variable 'packet.pkOrientation.orAzimuth' is of type 'int'. This integer variable is divided by the number 10. It is suspicious that then the result of division is used together with the values ​​of type 'double'. The final result is also placed in a variable of type 'double'.

    Such integer division is not necessarily a mistake. Perhaps the code is written exactly as intended. But as practice shows, often this is a flaw, leading to a loss in accuracy of calculations.

    For example, let the variable 'packet.pkOrientation.orAzimuth' be 55. Then the result of the calculations will be:

    ( 55/10 ) * (3.14159 ... / 180) = 5 * 0.01745 ... = 0.087266 ... The

    accuracy can be significantly increased. It is enough to declare constant 10 as a double type: "(packet.pkOrientation.orAzimuth / 10.0 ) * (M_PI / 180)". Now the result of the calculations is:

    (55 / 10.0) * (3.14159 ... / 180) = 5.5 * 0,01745 ... = 0,095993 ...

    Such inaccuracies often occur, since programmers are inattentive to expressions where variables of different types are mixed. Such inattention often also leads to 64-bit errors (see mixed arithmetic ).

    The analyzer detects another 51 suspicious integer divisions. Perhaps some of the expressions will be less accurate than the developers wanted. I list them: qt-v636.txt .

    Pointless pointer checks

    If memory is allocated using the 'new' operator, it has long been pointless to check the pointer for equality to zero. If memory cannot be allocated, an exception will be thrown. Of course, you can make the operator 'new' return 0, but now we are not talking about these cases.

    However, from time to time, programmers forget, and a meaningless check reappears in the code.
    HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(
      IEnumVARIANT **ppEnum)
    {
      QWindowsEnumerate *penum = 0;
      *ppEnum = 0;
      penum = new QWindowsEnumerate(array);
      if (!penum)
        return E_OUTOFMEMORY;
      ....
    }

    PVS-Studio Warning: V668 There is no sense in testing the 'penum' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. qwindowsmsaaaccessible.cpp 141

    There are several more of these checks: main.cpp 127, qaudiodevicefactory.cpp 236, qaudiodevicefactory.cpp 263, qaudiobuffer.cpp 488, mfvideorenderercontrol.cpp 143, mfvideorenderercontrol.cvpppreferendorcontrol.cvpppprerer, mcpppprerer, mcppprerer, mcvpprefrev, qaxserverbase.cpp 1006, positionpollfactory.cpp 60.

    Dark side


    The dark side

    There are two pieces of code about which I cannot say that this is definitely a mistake. I do not know the architecture of the project and the features of implementation. However, even if these are not errors, then this is the dark side of C ++ programming.
    class Q_CORE_EXPORT QObject
    {
      ....
      virtual ~QObject();
      virtual bool event(QEvent *);
      virtual bool eventFilter(QObject *, QEvent *);
      ....
    };
    QObject *QQmlVME::run(....)
    {
      ....
      QObject *o = (QObject *)operator
        new(instr.typeSize + sizeof(QQmlData));   
      ::memset(static_cast(o), 0,
               instr.typeSize + sizeof(QQmlData));
      ....
    }

    PVS-Studio Warning: V598 The 'memset' function is used to nullify the fields of 'QObject' class. Virtual method table will be damaged by this. qqmlvme.cpp 658

    The QObject class has virtual functions. This means that the object stores a pointer to a table of virtual methods. It seems to me not a good idea to initialize such objects using the memset () function.

    Another warning: V598 The 'memset' function is used to nullify the fields of 'QObject' class. Virtual method table will be damaged by this. qdeclarativevme.cpp 286

    Dereferencing null pointers


    Perhaps these errors could be attributed to typos. But I like to separate them into a separate group. So they seem darker and more serious.

    Note. The division of errors into groups is always fairly arbitrary. Often the same error can be classified as a typo, as a vulnerability, as going out of bounds of an array, and so on.

    Let's go back to the null pointers.

    Typo dereferencing due to typo
    QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(
      QV4::Managed *m, uint index, bool *hasProperty)
    {
      ....
      if (!m)
        return m->engine()->currentContext()->throwTypeError();
      ....
    }

    PVS-Studio Warning: V522 Dereferencing of the null pointer 'm' might take place. qquickcontext2d.cpp 3169

    Apparently, the operator '!' here is superfluous. A simple typo leading to a serious mistake.

    Null pointer dereference in an error handler
    void QDocIndexFiles::readIndexSection(....)
    {
      ....
      DocNode* dn = qdb_->findGroup(groupNames[i]);
      if (dn) {
        dn->addMember(node);
      }
      else {
        ....
        qDebug() << "DID NOT FIND GROUP:" << dn->name()
                 << "for:" << node->name();
      }
      ....
    }

    PVS-Studio Warning: V522 Dereferencing of the null pointer 'dn' might take place. qdocindexfiles.cpp 539

    If an error occurs, a diagnostic message should be printed. They will try to take a name from a nonexistent object in it: dn-> name ().

    82 potential dereferencing of the null pointer

    In almost all projects, including Qt, there are flaws in working with null pointers. Often, verification is carried out after the pointer has been used. This is not always a mistake. It happens that a pointer, in principle, cannot be equal to zero.

    In any case, such places deserve to be studied and refactored. Even if there is no error, an extra check on the pointer confuses the programmer when reading the code.

    Consider one of the fragments of dangerous code:
    static int gray_raster_render(....)
    {
      const QT_FT_Outline* outline =
        (const QT_FT_Outline*)params->source;
      ....
      /* return immediately if the outline is empty */
      if ( outline->n_points == 0 || outline->n_contours <= 0 )
        return 0;
      if ( !outline || !outline->contours || !outline->points )
        return ErrRaster_Invalid_Outline;  
      ....
    }

    PVS-Studio Warning: V595 The 'outline' pointer was utilized before it was verified against nullptr. Check lines: 1746, 1749. qgrayraster.c 1746

    I think the error appeared at the moment when they wanted to optimize the gray_raster_render () function. Most likely, in the already completed function code, these lines were inserted:
    /* return immediately if the outline is empty */
    if ( outline->n_points == 0 || outline->n_contours <= 0 )
      return 0;

    The trouble is that the 'outline' pointer may turn out to be null. Checking that the pointer is zero is a little lower.

    The analyzer found another 81 potential errors. Let me give you a list of diagnostic messages: qt-v595.txt .

    Unanswered questions


    Questions without answers

    There are strange code fragments that are hard to tell about how they appeared and what was actually planned to be written. Perhaps these are typos, possibly incomplete code, possibly unsuccessful refactoring.

    Double check
    QWindowsFontEngine::~QWindowsFontEngine()
    {
      ....
      if (QWindowsContext::verboseFonts)
        if (QWindowsContext::verboseFonts)
          qDebug("%s: font='%s", __FUNCTION__, qPrintable(_name));
      ....
    }

    PVS-Studio Warning: V571 Recurring check. The 'if (QWindowsContext :: verboseFonts)' condition was already verified in line 369. qwindowsfontengine.cpp 370

    Why double-check the same thing? Perhaps one check is unnecessary. Perhaps they forgot to check something else.

    Double assignment
    void Moc::parse()
    {
      ....
      index = def.begin + 1;
      namespaceList += def;
      index = rewind;
      ....
    }

    PVS-Studio Warning: V519 The 'index' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 568, 570. moc.cpp 570

    Why are the 'index' variable assigned different values?

    There are a few other similar weird code snippets:
    • V519 The 'exitCode' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 807, 815. qprocess.cpp 815
    • V519 The 'detecting' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 163, 164. qhoversensorgesturerecognizer.cpp 164
    • V519 The 'increaseCount' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 185, 186. qtwistsensorgesturerecognizer.cpp 186
    Suspected Missing Break Operator
    bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev)
    {
      ....
      switch (key) {
      case Qt::Key_Enter:
      case Qt::Key_Return:
        doneCompletion();
        consumed = true;
      case Qt::Key_Escape:
        editor->setFocus();
        popup->hide();
        consumed = true;
      case Qt::Key_Up:
      case Qt::Key_Down:
      case Qt::Key_Home:
      case Qt::Key_End:
      case Qt::Key_PageUp:
      case Qt::Key_PageDown:
        break;
      ....
    }

    PVS-Studio Warning: V519 The 'consumed' variable is assigned values ​​twice successively. Perhaps this is a mistake. Check lines: 110, 115. googlesuggest.cpp 115 Is the

    break statement forgotten here or not?

    It seemed strange to the analyzer that the variable 'consumed' could be assigned the value 'true' two times in a row. It is likely that the break statement is forgotten here. But I'm not so sure. Perhaps you just need to remove the first assignment: "consumed = true;".

    Suspicion of an extra 'break' statement
    bool QHelpGenerator::registerVirtualFolder(....)
    {
      ....
      while (d->query->next()) {
        d->namespaceId = d->query->value(0).toInt();
        break;
      }
      ....
    }

    PVS-Studio Warning: V612 An unconditional 'break' within a loop. qhelpgenerator.cpp 429

    Is it correct that the loop will stop immediately due to the 'break' statement?

    Another such piece of code lives here: qhelpgenerator.cpp 642

    Miscellaneous


    Be patient. The article will end soon. There are still a few motley errors.

    Incorrect use of the toLower () function
    int main(int argc, char **argv)
    {
      ....
      QByteArray arg(argv[a]);
      ....
      arg = arg.mid(1);
      arg.toLower();
      if (arg == "o")
      ....
    }

    PVS-Studio Warning: V530 The return value of function 'toLower' is required to be utilized. main.cpp 72

    The 'toLower ()' function does not modify the object. It returns a copy of the object, which will store lowercase characters.

    Another mistake: V530 The return value of function 'toLower' is required to be utilized. main.cpp 1522

    Going beyond the bounds of the array

    The situation is complicated. Please concentrate.

    There is such a numbered type:
    typedef enum {
        JNone,
        JCausing,
        JDual,
        JRight,
        JTransparent
    } Joining;

    Remember that JTransparent == 4.

    Now let's look at the getNkoJoining () function:
    static Joining getNkoJoining(unsigned short uc)
    {
      if (uc < 0x7ca)
        return JNone;
      if (uc <= 0x7ea)
        return JDual;
      if (uc <= 0x7f3)
        return JTransparent;
      if (uc <= 0x7f9)
        return JNone;
      if (uc == 0x7fa)
        return JCausing;
      return JNone;
    }

    What matters to us is that this function can return 'JTransparent'. That is, the function can return 4.

    The program has a two-dimensional array 'joining_table':
    static const JoiningPair joining_table[5][4] = { .... };

    And now the actual place where the error may occur:
    static void getNkoProperties(....)
    {
      ....
      Joining j = getNkoJoining(chars[0]);
      ArabicShape shape = joining_table[XIsolated][j].form2;
      ....
    }

    PVS-Studio Warning: V557 Array overrun is possible. The value of 'j' index could reach 4. harfbuzz-arabic.c 516

    As we recall, the getNkoJoining () function can return a value of 4. Thus, we refer to the cell of the joining_table [...] [4] array. It is unacceptable. The array will go beyond the bounds of the array.

    Same conditions
    void Node::setPageType(const QString& t)
    {
        if ((t == "API") || (t == "api"))
            pageType_ = ApiPage;
        else if (t == "howto")
            pageType_ = HowToPage;
        else if (t == "overview")
            pageType_ = OverviewPage;
        else if (t == "tutorial")
            pageType_ = TutorialPage;
        else if (t == "howto")
            pageType_ = HowToPage;
        else if (t == "article")
            pageType_ = ArticlePage;
        else if (t == "example")
            pageType_ = ExamplePage;
        else if (t == "ditamap")
            pageType_ = DitaMapPage;
    }

    PVS-Studio warning: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 386, 392. node.cpp 386

    The check is performed two times (t == "howto"). I think one of them is superfluous.

    Here are a couple more similar warnings:
    • V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 188, 195. qmaintainingreader_tpl_p.h 188
    • V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 299, 303. mfmetadatacontrol.cpp 299
    Performing the same action
    void
    QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscovered(
      const QBluetoothDeviceInfo &info)
    {
      if(mode == QBluetoothServiceDiscoveryAgent::FullDiscovery) {
        for(int i = 0; i < discoveredDevices.count(); i++){
          if(discoveredDevices.at(i).address() == info.address()){
            discoveredDevices.removeAt(i);
          }
        }
        discoveredDevices.prepend(info);
      }
      else {
        for(int i = 0; i < discoveredDevices.count(); i++){
          if(discoveredDevices.at(i).address() == info.address()){
            discoveredDevices.removeAt(i);
          }
        }
        discoveredDevices.prepend(info);
      }
    }

    PVS-Studio Warning: V523 The 'then' statement is equivalent to the 'else' statement. qbluetoothservicediscoveryagent.cpp 402

    Regardless of the condition, the same actions are performed.

    Similarly: pcre_exec.c 5577, ditaxmlgenerator.cpp 1722, htmlgenerator.cpp 388.

    Inherited Errors


    Qt uses several third-party libraries. These libraries also have errors. It turns out that these errors are also in Qt. I did not describe them in the article, but decided that I could mention them.

    I did not look carefully at the third-party libraries, but wrote out something: qt-3rdparty.txt .

    Note. However, you should not think that I watched Qt very carefully. A project of a large and even superficial inspection is enough to write such an article.

    conclusions


    PVS-Studio is an excellent, powerful analyzer that is able to find errors even in such high-quality and sleek projects as the Qt framework.

    It will help save a lot of time for the development team by detecting many errors at an early stage. If you use incremental analysis , errors will be detected immediately after compiling the files.

    Sitelinks


    1. We regularly check open-source projects. For example, Tor, Chromium, Clang, Firebird, OpenCV. Everyone who is interested, come here: "An updated list of open-source projects that we tested using PVS-Studio ."
    2. Here you can download a trial version of PVS-Studio . At the beginning, there are 20 clicks to navigate through the alerts. After reporting information about yourself, another 200 clicks.


    This article is in English.


    If you want to share this article with an English-speaking audience, then please use the link to the translation: Andrey Karpov. Checking the Qt 5 Framework .

    Slowpoke question

    Have you read the article and have a question?
    Often our articles are asked the same questions. We collected answers to them here: Answers to questions from readers of articles about PVS-Studio and CppCat, version 2014 . Please see the list.

    Also popular now: