日付処理はQt6のバグまたは77の欠陥を引き付けます

PVS-StudioはQt6をチェックします







Qt 6フレームワークは比較的最近リリースされたため、PVS-Studioを使用して再度チェックする必要がありました。この記事では、日付の処理など、さまざまな興味深いエラーについて説明します。これらすべてのエラーを見つけることは、特に定期的に使用する場合に、プロジェクトがPVS-Studioなどのツールを使用することから得られる利点を明確に示しています。







これは、オープンソースプロジェクトのチェックに関する古典的な記事であり、コード品質管理にPVS-Studioを使用することの有用性と有効性に関する証拠ベース」に追加されます。我々はすでに(Qtのプロジェクトの検証について書かれているが、2011年に2014年、および2018年)、再びそれを行うには非常に便利です。したがって、実際には、静的分析を定期的に使用する必要があるという、単純ですが非常に重要なアイデアを示します。







私たちの記事は、PVS-Studioアナライザーがさまざまなエラーを見つけることができることを示しています。そして、原則として、プロジェクトの作成者は、私たちが説明したエラーをすばやく修正します。ただし、これはすべて、静的アナライザーを定期的に使用するための正しくて便利な手法とは関係ありません。アナライザーが開発プロセスに組み込まれていると、新しいコードや変更されたコードのバグをすばやく見つけることができるため、可能な限り安価に修正できます。







以上で、理論は終わりです。コードで私たちを待っている興味深いものを見てみましょう。それまでの間、あなたは記事を読んでいます。PVS-Studioダウンロードし、デモキーを要求して、自分のプロジェクトで何が面白いかを確認することをお勧めします:)。







日付



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





, , . , . , :).







古いコレクションのユニコーン







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 "", , , . , :).







賢明です-静的コードアナライザーを使用してください









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. . – . , , , . :).







ユニコーンでリラックス







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







それは何ですか? なぜそのように書くのですか?







? ? :







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