Date handling attracts bugs or 77 defects in Qt 6

PVS-Studio checks Qt 6







The Qt 6 framework was released relatively recently, and this was the reason to check it again using PVS-Studio. The article will discuss various interesting errors, for example, related to handling dates. Finding all these errors clearly demonstrates the benefits that a project can get from using tools such as PVS-Studio, especially if they are used regularly.







This is a classic article about checking an open source project, which will add to our " evidence base " of the usefulness and effectiveness of using PVS-Studio for code quality control. Although we have already written about validating a Qt project ( in 2011 , 2014, and 2018 ), it is very useful to do it again. So, in practice, we demonstrate a simple but very important idea: static analysis should be used regularly!







Our articles show that the PVS-Studio analyzer is able to find a wide variety of errors. And, as a rule, the authors of projects quickly fix the errors we have described. However, all this has nothing to do with the correct and useful technique of regular use of static analyzers. When the analyzer is built into the development process, it allows you to quickly find bugs in new or changed code and, thus, it is as cheap as possible to fix them.







That's it, the theory ends. Let's see what interesting things await us in the code. In the meantime, you are reading the article, I suggest downloading PVS-Studio and requesting a demo key to see what is interesting in your own projects :).







Dates



, , . , , , . , . , , . " PVS-Studio ".







Qt. .







N1:







, , .







static const char qt_shortMonthNames[][4] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

static int fromShortMonthName(QStringView monthName)
{
  for (unsigned int i = 0;
       i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i)
  {
    if (monthName == QLatin1String(qt_shortMonthNames[i], 3))
      return i + 1;
  }
  return -1;
}
      
      





( 1 12). , (-1). , 0.







, , , . , fromShortMonthName:







QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
{
  ....
  month = fromShortMonthName(parts.at(1));
  if (month)
    day = parts.at(2).toInt(&ok);

  // If failed, try day then month
  if (!ok || !month || !day) {
    month = fromShortMonthName(parts.at(2));
    if (month) {
      QStringView dayPart = parts.at(1);
      if (dayPart.endsWith(u'.'))
        day = dayPart.chopped(1).toInt(&ok);
    }
  }
  ....
}
      
      





, . PVS-Studio , :







  • V547 [CWE-571] Expression 'month' is always true. qdatetime.cpp 4907
  • V560 [CWE-570] A part of conditional expression is always false: !month. qdatetime.cpp 4911
  • V547 [CWE-571] Expression 'month' is always true. qdatetime.cpp 4913
  • V560 [CWE-570] A part of conditional expression is always false: !month. qdatetime.cpp 4921


N2:







, .







enum {
  ....
  MSECS_PER_DAY = 86400000,
  ....
  SECS_PER_MIN = 60,
};

int QTime::second() const
{
    if (!isValid())
        return -1;

    return (ds() / 1000)%SECS_PER_MIN;
}
      
      





[0..59] -1.







:







static qint64 qt_mktime(QDate *date, QTime *time, ....)
{
  ....
  } else if (yy == 1969 && mm == 12 && dd == 31
             && time->second() == MSECS_PER_DAY - 1) {
      // There was, of course, a last second in 1969, at time_t(-1); we won't
      // rescue it if it's not in normalised form, and we don't know its DST
      // status (unless we did already), but let's not wantonly declare it
      // invalid.
  } else {
  ....
}
      
      





PVS-Studio: V560 [CWE-570] A part of conditional expression is always false: time->second() == MSECS_PER_DAY — 1. qdatetime.cpp 2488







, - , . , , else-.







:







time->second() == MSECS_PER_DAY - 1
      
      





MSECS_PER_DAY — 1 86399999. second, , . , - .







, , . , - .









N3: , … HTML!







QString QPixelTool::aboutText() const
{
  const QList<QScreen *> screens = QGuiApplication::screens();
  const QScreen *windowScreen = windowHandle()->screen();

  QString result;
  QTextStream str(&result);
  str << "<html></head><body><h2>Qt Pixeltool</h2><p>Qt " << QT_VERSION_STR
    << "</p><p>Copyright (C) 2017 The Qt Company Ltd.</p><h3>Screens</h3><ul>";
  for (const QScreen *screen : screens)
    str << "<li>" << (screen == windowScreen ? "* " : "  ")
        << screen << "</li>";
  str << "<ul></body></html>";
  return result;
}
      
      





PVS-Studio: V735 Possibly an incorrect HTML. The "</ body>" closing tag was encountered, while the "</ ul>" tag was expected. qpixeltool.cpp 707







PVS-Studio , , . . , .







. . , , – . :







str << "</ul></body></html>";
      
      





N4:







class Node
{
  ....
  bool isGroup() const { return m_nodeType == Group; }
  ....
};

void DocBookGenerator::generateDocBookSynopsis(const Node *node)
{
  ....
  if (node->isGroup() || node->isGroup()
      || node->isSharedCommentNode() || node->isModule()
      || node->isJsModule() || node->isQmlModule() || node->isPageNode())
    return;
  ....
}
      
      





PVS-Studio: V501 [CWE-570] There are identical sub-expressions to the left and to the right of the '||' operator: node->isGroup() || node->isGroup() docbookgenerator.cpp 2599







, , . , . : - .







N5:







void MainWindow::addToPhraseBook()
{
  ....
  QString selectedPhraseBook;
  if (phraseBookList.size() == 1) {
    selectedPhraseBook = phraseBookList.at(0);
    if (QMessageBox::information(this, tr("Add to phrase book"),
          tr("Adding entry to phrasebook %1").arg(selectedPhraseBook),
           QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok)
                          != QMessageBox::Ok)
      return;
  } else {
    bool okPressed = false;
    QString selectedPhraseBook = 
      QInputDialog::getItem(this, tr("Add to phrase book"),
                            tr("Select phrase book to add to"),
                            phraseBookList, 0, false, &okPressed);
    if (!okPressed)
      return;
  }

  MessageItem *currentMessage = m_dataModel->messageItem(m_currentIndex);
  Phrase *phrase = new Phrase(currentMessage->text(),
                              currentMessage->translation(),
                              QString(), nullptr);

  phraseBookHash.value(selectedPhraseBook)->append(phrase);
}
      
      





, , . , . , :).







Unicorn from old collection







PVS-Studio: V561 [CWE-563] It's probably better to assign value to 'selectedPhraseBook' variable than to declare it anew. Previous declaration: mainwindow.cpp, line 1303. mainwindow.cpp 1313







, selectedPhraseBook. , . , . :







QString selectedPhraseBook =
      
      





else- , , . .







N6:







, .







bool QQmlImportInstance::resolveType(....)
{
  ....
  if (int icID = containingType.lookupInlineComponentIdByName(typeStr) != -1)
  {
    *type_return = containingType.lookupInlineComponentById(icID);
  } else {
    auto icType = createICType();
    ....
  }
  ....
}
      
      





PVS-Studio: V593 [CWE-783] Consider reviewing the expression of the 'A = B != C' kind. The expression is calculated as following: 'A = (B != C)'. qqmlimport.cpp 754







icID 0 1. , . : -1, icID.







C++ :







if (int icID = containingType.lookupInlineComponentIdByName(typeStr);
    icID != -1)
      
      





, Qt:







char ch;
while (i < dataLen && ((ch = data.at(i) != '\n') && ch != '\r'))
  ++i;
      
      





, PVS-Studio, . . , PVS-Studio :).







N7:







, 2 . — :







if (A % 2 == 1)
      
      





- :







if (A % 1 == 1)
      
      





, – . Qt:







bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd)
{
  ....
  case Tag_Translation: {
    int len = read32(m);
    if (len % 1) {                                             // <=
      cd.appendError(QLatin1String("QM-Format error"));
      return false;
    }
    m += 4;
    QString str = QString((const QChar *)m, len/2);
  ....
}
      
      





PVS-Studio: V1063 The modulo by 1 operation is meaningless. The result will always be zero. qm.cpp 549







N8:







QString Node::qualifyQmlName()
{
  QString qualifiedName = m_name;
  if (m_name.startsWith(QLatin1String("QML:")))
    qualifiedName = m_name.mid(4);
  qualifiedName = logicalModuleName() + "::" + m_name;
  return qualifiedName;
}
      
      





PVS-Studio: V519 [CWE-563] The 'qualifiedName' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1227, 1228. node.cpp 1228







, . , :







QString qualifiedName = m_name;
if (m_name.startsWith(QLatin1String("QML:")))
  qualifiedName = m_name.mid(4);
qualifiedName = logicalModuleName() + "::" + qualifiedName;
return qualifiedName;
      
      





N9: copy-paste







class Q_CORE_EXPORT QJsonObject
{
  ....
  bool operator<(const iterator& other) const
  { Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
  bool operator<=(const iterator& other) const
  { Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
  ....
}
      
      





PVS-Studio: V524 It is odd that the body of '<=' function is fully equivalent to the body of '<' function. qjsonobject.h 155







, , . . code review. . . .







< <= . . , Copy-Paste, . :







bool operator<(const iterator& other) const
{ Q_ASSERT(item.o == other.item.o); return item.index < other.item.index; }
bool operator<=(const iterator& other) const
{ Q_ASSERT(item.o == other.item.o); return item.index <= other.item.index; }
      
      





N10: static_cast / dynamic_cast







void QSGSoftwareRenderThread::syncAndRender()
{
  ....
  bool canRender = wd->renderer != nullptr;

  if (canRender) {
     auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(wd->renderer);
     if (softwareRenderer)
       softwareRenderer->setBackingStore(backingStore);
  ....
}
      
      





PVS-Studio: V547 [CWE-571] Expression 'softwareRenderer' is always true. qsgsoftwarethreadedrenderloop.cpp 510







:







bool canRender = wd->renderer != nullptr;
if (canRender) {
      
      





, wd->renderer . , ?







auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(wd->renderer);
if (softwareRenderer)
      
      





wd->renderer , softwareRenderer . , , , dynamic_cast. . , dynamic_cast nullptr, , , . , , .







N11:







void *QQuickPath::qt_metacast(const char *_clname)
{
  if (!_clname) return nullptr;
  if (!strcmp(_clname, qt_meta_stringdata_QQuickPath.stringdata0))
    return static_cast<void*>(this);
  if (!strcmp(_clname, "QQmlParserStatus"))
    return static_cast< QQmlParserStatus*>(this);
  if (!strcmp(_clname, "org.qt-project.Qt.QQmlParserStatus"))   // <=
    return static_cast< QQmlParserStatus*>(this);
  if (!strcmp(_clname, "org.qt-project.Qt.QQmlParserStatus"))   // <=
    return static_cast< QQmlParserStatus*>(this);
  return QObject::qt_metacast(_clname);
}
      
      





PVS-Studio: V581 [CWE-670] The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 2719, 2721. moc_qquickpath_p.cpp 2721







:







if (!strcmp(_clname, "org.qt-project.Qt.QQmlParserStatus"))
  return static_cast< QQmlParserStatus*>(this);
      
      





Copy-Paste. .







N12: -







int m_offsetFromUtc;
....
void QDateTime::setMSecsSinceEpoch(qint64 msecs)
{
  ....
  if (!add_overflow(msecs, qint64(d->m_offsetFromUtc * 1000), &msecs))
    status |= QDateTimePrivate::ValidWhenMask;
  ....
}
      
      





PVS-Studio: V1028 [CWE-190] Possible overflow. Consider casting operands of the 'd->m_offsetFromUtc * 1000' operator to the 'qint64' type, not the result. qdatetime.cpp 3922







, int 1000 . , 64- qint64. .







. . . :







add_overflow(msecs, qint64(d->m_offsetFromUtc) * 1000, &msecs)
      
      





N13:







class QPathEdge
{
  ....
private:
  int m_next[2][2];
  ....
};

inline QPathEdge::QPathEdge(int a, int b)
    : flag(0)
    , windingA(0)
    , windingB(0)
    , first(a)
    , second(b)
    , angle(0)
    , invAngle(0)
{
    m_next[0][0] = -1;
    m_next[1][0] = -1;
    m_next[0][0] = -1;
    m_next[1][0] = -1;
}
      
      





PVS-Studio:







  • V1048 [CWE-1164] The 'm_next[0][0]' variable was assigned the same value. qpathclipper_p.h 301
  • V1048 [CWE-1164] The 'm_next[1][0]' variable was assigned the same value. qpathclipper_p.h 302


2x2. , . :







m_next[0][0] = -1;
m_next[0][1] = -1;
m_next[1][0] = -1;
m_next[1][1] = -1;
      
      





, . . , , . , , , :). 10 "", , , . , :).







Be wise - use a static code analyzer









N14:







void QmlProfilerApplication::tryToConnect()
{
  Q_ASSERT(!m_connection->isConnected());
  ++ m_connectionAttempts;

  if (!m_verbose && !(m_connectionAttempts % 5)) {// print every 5 seconds
    if (m_verbose) {
      if (m_socketFile.isEmpty())
        logError(
          QString::fromLatin1("Could not connect to %1:%2 for %3 seconds ...")
          .arg(m_hostName).arg(m_port).arg(m_connectionAttempts));
      else
        logError(
          QString::fromLatin1("No connection received on %1 for %2 seconds ...")
          .arg(m_socketFile).arg(m_connectionAttempts));
    }
  }
  ....
}
      
      





PVS-Studio: V547 [CWE-570] Expression 'm_verbose' is always false. qmlprofilerapplication.cpp 495







. :







if (!m_verbose && ....) {
  if (m_verbose) {
      
      





N15:







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





PVS-Studio: V519 [CWE-563] The 'done' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 509, 511. qeffects.cpp 511







, done . , else.







N16-N20:







.







bool QXmlStreamWriterPrivate::finishStartElement(bool contents)
{
  ....
  if (inEmptyElement) {
    ....
    lastNamespaceDeclaration = tag.namespaceDeclarationsSize;   // <=
    lastWasStartElement = false;
  } else {
    write(">");
  }
  inStartElement = inEmptyElement = false;
  lastNamespaceDeclaration = namespaceDeclarations.size();      // <=
  return hadSomethingWritten;
}
      
      





PVS-Studio: V519 [CWE-563] The 'lastNamespaceDeclaration' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 3030, 3036. qxmlstream.cpp 3036







, lastNamespaceDeclaration . , .







4 , :







  • V519 [CWE-563] The 'last' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 609, 637. qtextengine.cpp 637
  • V519 [CWE-563] The 'm_dirty' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1014, 1017. qquickshadereffect.cpp 1017
  • V519 [CWE-563] The 'changed' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 122, 128. qsgdefaultspritenode.cpp 128
  • V519 [CWE-563] The 'eaten' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 299, 301. qdesigner.cpp 301


N21:







// this could become a list of all languages used for each writing
// system, instead of using the single most common language.
static const char languageForWritingSystem[][6] = {
    "",     // Any
    "en",  // Latin
    "el",  // Greek
    "ru",  // Cyrillic

    ...... //   .    .

    "", // Symbol
    "sga", // Ogham
    "non", // Runic
    "man" // N'Ko
};

static void populateFromPattern(....)
{
  ....
  for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) {
    const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j];
    if (lang) {
  ....
}
      
      





PVS-Studio: V547 [CWE-571] Expression 'lang' is always true. qfontconfigdatabase.cpp 462







languageForWritingSystem . if(lang) . . , ? , :







if (strlen(lang) != 0) {
      
      





:







if (lang[0] != '\0') {
      
      





N22:







bool QNativeSocketEnginePrivate::createNewSocket(....)
{
  ....
  int socket = qt_safe_socket(domain, type, protocol, O_NONBLOCK);
  ....
  if (socket < 0) {
    ....
    return false;
  }

  socketDescriptor = socket;

  if (socket != -1) {
    this->socketProtocol = socketProtocol;
    this->socketType = socketType;
  }
  return true;
}
      
      





PVS-Studio: V547 [CWE-571] Expression 'socket != — 1' is always true. qnativesocketengine_unix.cpp 315







socket != -1 , , socket .







N23: - ?







bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
  Q_D(QSqlTableModel);
  if (parent.isValid() || row < 0 || count <= 0)
    return false;
  else if (row + count > rowCount())
    return false;
  else if (!count)
    return true;
  ....
}
      
      





PVS-Studio: V547 [CWE-570] Expression '!count' is always false. qsqltablemodel.cpp 1110







:







if (.... || count <= 0)
  return false;
....
else if (!count)
  return true;
      
      





, count 0, false. , -: true.







- . , <=, <. :







bool QSqlTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
  Q_D(QSqlTableModel);
  if (parent.isValid() || row < 0 || count < 0)
    return false;
  else if (row + count > rowCount())
    return false;
  else if (!count)
    return true;
  ....
}
      
      





N24: ?







identifierWithEscapeChars . ? ? true.







int Lexer::scanToken()
{
  ....
  bool identifierWithEscapeChars = false;
  ....
  if (!identifierWithEscapeChars) {
    identifierWithEscapeChars = true;
    ....
  }
  ....
  if (identifierWithEscapeChars) {    // <=
    ....
  }
  ....
}
      
      





PVS-Studio: V547 [CWE-571] Expression 'identifierWithEscapeChars' is always true. qqmljslexer.cpp 817







N25: ?







bool QFont::fromString(const QString &descrip)
{
  ....
  const int count = l.count();
  if (!count || (count > 2 && count < 9) || count == 9 || count > 17 ||
      l.first().isEmpty()) {
    qWarning("QFont::fromString: Invalid description '%s'",
             descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
    return false;
  }

  setFamily(l[0].toString());
  if (count > 1 && l[1].toDouble() > 0.0)
    setPointSizeF(l[1].toDouble());
  if (count == 9) {                           // <=
    setStyleHint((StyleHint) l[2].toInt());
    setWeight(QFont::Weight(l[3].toInt()));
    setItalic(l[4].toInt());
    setUnderline(l[5].toInt());
    setStrikeOut(l[6].toInt());
    setFixedPitch(l[7].toInt());
  } else if (count >= 10) {
  ....
}
      
      





PVS-Studio: V547 [CWE-570] Expression 'count == 9' is always false. qfont.cpp 2142







, count 9? , . :







if (.... || count == 9 || ....) {
  qWarning(....);
  return false;
}
      
      





, 9 :







if (count == 9) {
  setStyleHint((StyleHint) l[2].toInt());
  setWeight(QFont::Weight(l[3].toInt()));
  setItalic(l[4].toInt());
  ....
}
      
      





, , . , :).









N26-N42:







class __attribute__((visibility("default"))) QMetaType {
  ....
  const QtPrivate::QMetaTypeInterface *d_ptr = nullptr;
};

QPartialOrdering QMetaType::compare(const void *lhs, const void *rhs) const
{
    if (!lhs || !rhs)
        return QPartialOrdering::Unordered;
    if (d_ptr->flags & QMetaType::IsPointer)
        return threeWayCompare(*reinterpret_cast<const void * const *>(lhs),
                               *reinterpret_cast<const void * const *>(rhs));
    if (d_ptr && d_ptr->lessThan) {
        if (d_ptr->equals && d_ptr->equals(d_ptr, lhs, rhs))
            return QPartialOrdering::Equivalent;
        if (d_ptr->lessThan(d_ptr, lhs, rhs))
            return QPartialOrdering::Less;
        if (d_ptr->lessThan(d_ptr, rhs, lhs))
            return QPartialOrdering::Greater;
        if (!d_ptr->equals)
            return QPartialOrdering::Equivalent;
    }
    return QPartialOrdering::Unordered;
}
      
      





PVS-Studio: V595 [CWE-476] The 'd_ptr' pointer was utilized before it was verified against nullptr. Check lines: 710, 713. qmetatype.cpp 710







. . , d_ptr:







if (d_ptr->flags & ....)
if (d_ptr && ....)
      
      





, . , , , .







C ++. . Qt :







  • V595 [CWE-476] The 'self' pointer was utilized before it was verified against nullptr. Check lines: 1346, 1351. qcoreapplication.cpp 1346
  • V595 [CWE-476] The 'currentTimerInfo' pointer was utilized before it was verified against nullptr. Check lines: 636, 641. qtimerinfo_unix.cpp 636
  • V595 [CWE-476] The 'lib' pointer was utilized before it was verified against nullptr. Check lines: 325, 333. qlibrary.cpp 325
  • V595 [CWE-476] The 'fragment.d' pointer was utilized before it was verified against nullptr. Check lines: 2262, 2266. qtextcursor.cpp 2262
  • V595 [CWE-476] The 'window' pointer was utilized before it was verified against nullptr. Check lines: 1581, 1583. qapplication.cpp 1581
  • V595 [CWE-476] The 'window' pointer was utilized before it was verified against nullptr. Check lines: 1593, 1595. qapplication.cpp 1593
  • V595 [CWE-476] The 'newHandle' pointer was utilized before it was verified against nullptr. Check lines: 873, 879. qsplitter.cpp 873
  • V595 [CWE-476] The 'targetModel' pointer was utilized before it was verified against nullptr. Check lines: 454, 455. qqmllistmodel.cpp 454
  • V595 [CWE-476] The 'childIface' pointer was utilized before it was verified against nullptr. Check lines: 102, 104. qaccessiblequickitem.cpp 102
  • V595 [CWE-476] The 'e' pointer was utilized before it was verified against nullptr. Check lines: 94, 98. qquickwindowmodule.cpp 94
  • V595 [CWE-476] The 'm_texture' pointer was utilized before it was verified against nullptr. Check lines: 235, 239. qsgplaintexture.cpp 235
  • V595 [CWE-476] The 'm_unreferencedPixmaps' pointer was utilized before it was verified against nullptr. Check lines: 1140, 1148. qquickpixmapcache.cpp 1140
  • V595 [CWE-476] The 'camera' pointer was utilized before it was verified against nullptr. Check lines: 263, 264. assimpimporter.cpp 263
  • V595 [CWE-476] The 'light' pointer was utilized before it was verified against nullptr. Check lines: 273, 274. assimpimporter.cpp 273
  • V595 [CWE-476] The 'channel' pointer was utilized before it was verified against nullptr. Check lines: 337, 338. assimpimporter.cpp 337
  • V595 [CWE-476] The 'm_fwb' pointer was utilized before it was verified against nullptr. Check lines: 2492, 2500. designerpropertymanager.cpp 2492


N43:







, . . , - code-review.







void QFormLayoutPrivate::updateSizes()
{
  ....
  QFormLayoutItem *field = m_matrix(i, 1);
  ....
  if (userHSpacing < 0 && !wrapAllRows && (label || !field->fullRow) && field)
  ....
}
      
      





PVS-Studio: V713 [CWE-476] The pointer 'field' was utilized in the logical expression before it was verified against nullptr in the same logical expression. qformlayout.cpp 405













. , . , :). . - 12- . .







, . , Qt PVS-Studio. . – . , , , . :).







Relax with a unicorn







N44-N72: , malloc







void assignData(const QQmlProfilerEvent &other)
{
  if (m_dataType & External) {
    uint length = m_dataLength * (other.m_dataType / 8);
    m_data.external = malloc(length);                          // <=
    memcpy(m_data.external, other.m_data.external, length);    // <=
  } else {
    memcpy(&m_data, &other.m_data, sizeof(m_data));
  }
}
      
      





PVS-Studio: V575 [CWE-628] The potential null pointer is passed into 'memcpy' function. Inspect the first argument. Check lines: 277, 276. qqmlprofilerevent_p.h 277







, malloc. , , . 4 , " , malloc".







, . , - . , 28 : qt6-malloc.txt. , , . .







, . new, std::bad_alloc. :







static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(....)
{
  ....
  QImageScaleInfo *isi;
  ....
  isi = new QImageScaleInfo;
  if (!isi)
    return nullptr;
  ....
}
      
      





PVS-Studio: V668 [CWE-570] There is no sense in testing the 'isi' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. qimagescale.cpp 245







P.S. , placement new "new (std::nothrow) T"? , .







(" ")



, , , . , . , . , .







, , " ". , , . , , .







. . Qt . , . . , . , , .







, .







N73: " " —







void QQuick3DSceneManager::setWindow(QQuickWindow *window)
{
  if (window == m_window)
    return;

  if (window != m_window) {
    if (m_window)
      disconnect(....);
    m_window = window;
    connect(....);
    emit windowChanged();
  }
}
      
      





PVS-Studio: V547 [CWE-571] Expression 'window != m_window' is always true. qquick3dscenemanager.cpp 60







window==m_window, . .







N74: " " –







QModelIndex QTreeView::moveCursor(....)
{
  ....
  int vi = -1;
  if (vi < 0)
    vi = qMax(0, d->viewIndex(current));
  ....
}
      
      





PVS-Stduio: V547 [CWE-571] Expression 'vi < 0' is always true. qtreeview.cpp 2219







What is it?  Why write like that?







? ? :







int vi = qMax(0, d->viewIndex(current));
      
      





N75: " " –







bool copyQtFiles(Options *options)
{
  ....
  if (unmetDependencies.isEmpty()) {
    if (options->verbose) {
      fprintf(stdout, "  -- Skipping %s, architecture mismatch.\n",
              qPrintable(sourceFileName));
    }
  } else {
    if (unmetDependencies.isEmpty()) {
      if (options->verbose) {
        fprintf(stdout, "  -- Skipping %s, architecture mismatch.\n",
                  qPrintable(sourceFileName));
      }
    } else {
      fprintf(stdout, "  -- Skipping %s. It has unmet dependencies: %s.\n",
              qPrintable(sourceFileName),
              qPrintable(unmetDependencies.join(QLatin1Char(','))));
    }
  }
  ....
}
      
      





PVS-Studio: V571 [CWE-571] Recurring check. The 'if (unmetDependencies.isEmpty())' condition was already verified in line 2203. main.cpp 2209







, . . unmetDependencies.isEmpty() , . , . , . :







bool copyQtFiles(Options *options)
{
  ....
  if (unmetDependencies.isEmpty()) {
    if (options->verbose) {
      fprintf(stdout, "  -- Skipping %s, architecture mismatch.\n",
              qPrintable(sourceFileName));
    }
  } else {
    fprintf(stdout, "  -- Skipping %s. It has unmet dependencies: %s.\n",
            qPrintable(sourceFileName),
            qPrintable(unmetDependencies.join(QLatin1Char(','))));
  }
  ....
}
      
      





N76: " " –







bool QDockAreaLayoutInfo::insertGap(....)
{
  ....
  QDockAreaLayoutItem new_item
    = widgetItem == nullptr
      ? QDockAreaLayoutItem(subinfo)
      : widgetItem ? QDockAreaLayoutItem(widgetItem) 
                   : QDockAreaLayoutItem(placeHolderItem);
  ....
}
      
      





PVS-Studio: V547 [CWE-571] Expression 'widgetItem' is always true. qdockarealayout.cpp 1167







, . , (). :







  QDockAreaLayoutItem new_item
    = widgetItem == nullptr
      ? QDockAreaLayoutItem(subinfo) : QDockAreaLayoutItem(widgetItem);
      
      





N77: " " –







typedef unsigned int uint;

ReturnedValue TypedArrayCtor::virtualCallAsConstructor(....)
{
  ....
  qint64 l = argc ? argv[0].toIndex() : 0;
  if (scope.engine->hasException)
    return Encode::undefined();
  // ### lift UINT_MAX restriction
  if (l < 0 || l > UINT_MAX)
    return scope.engine->throwRangeError(QLatin1String("Index out of range."));
  uint len = (uint)l;
  if (l != len)
    scope.engine->throwRangeError(
      QStringLiteral("Non integer length for typed array."));
  ....
}
      
      





PVS-Studio: V547 [CWE-570] Expression 'l != len' is always false. qv4typedarray.cpp 306







- , 64- 32- unsigned. . .







:







if (l < 0 || l > UINT_MAX)
      
      





, :







uint len = (uint)l;
if (l != len)
  scope.engine->throwRangeError(
    QStringLiteral("Non integer length for typed array."));
      
      





. , .







: PVS-Studio , .









, 77 . , . , , PVS-Studio. , , :).







, , .









– ! PVS-Studio , . code review , . , , . , .







, " PVS-Studio". 90 % :). 10 % , :).







, : Andrey Karpov. Date Processing Attracts Bugs or 77 Defects in Qt 6.








All Articles