Qt 5フレームワークの確認

QtおよびPVS-Studio
静的コード分析ツールを使用すると、プログラムテキストを記述する段階でも多くのエラーを排除できます。 たとえば、タイプミスをすばやく特定して排除できます。 一部のプログラマーは、タイプミスや愚かな間違いを犯さないことを心から確信しています。 そうではありません。 誰もがそのような過ちを犯します。 この記事は良いデモとして役立ちます。 タイプミスは、Qtのような高品質でテスト済みのプロジェクトでも見つかります。

Qt


Qtは、C ++プログラミング言語のクロスプラットフォームソフトウェア開発ツールキットです。 ソースコードを変更せずに各OSのプログラムをコンパイルするだけで、ほとんどの最新のオペレーティングシステムで、その助けを借りて書かれたソフトウェアを実行できます。 GUI要素からネットワーク、データベース、およびXMLを操作するためのクラスに至るまで、アプリケーションソフトウェアの開発に必要となる可能性のあるすべての基本クラスが含まれています。 Qtは完全にオブジェクト指向であり、簡単に拡張でき、コンポーネントプログラミング技術をサポートしています。 [ソース:ウィキペディア]

参照:Qtバージョン5.2.1で作業します。 分析には、 PVS-Studioバージョン5.15を使用します。

KlocworkおよびCoverityアナライザーを使用してQtプロジェクトがチェックされたという事実にもかかわらず、PVS-Studioがエラーを見つけることができたという事実に注意を喚起したいと思います。 これらのアナライザーの使用頻度はわかりません。 ただし、KlocworkとCoverityはバグトラッカーとChangeLog-xxxファイルで言及されています。 また、インターネット上で、PC-lintを使用してQtが定期的にチェックされるという言及を見つけました。

Qtプロジェクト検証の機能


変更のために、PVS-Studio Standaloneで導入された新しいメカニズムでQtをテストしました。 メカニズムについてはこれまで誰も知らず、時々その存在について記事で思い出させます。 この新しい神秘的で美しいメカニズムは何ですか?

nmakeなどを使用してビルドされている場合、PVS-Studioを使用してプロジェクトを検証するのは難しい場合があります。 PVS-Studioをアセンブリに統合する必要がありますが、これはそれほど単純ではありません。 少なくとも、これにより、ツールをすばやく試して評価することが明らかに困難になります。

PVS-Studioに新しい操作モードが登場しました。これにより、そのようなプロジェクトでの作業が大幅に容易になります。 アナライザーは、コンパイラーがどのパラメーターで起動されるかをモニターし、検証に必要なすべての情報を収集できます。 いつ監視を開始し、いつ停止するかを分析装置に伝えるだけで十分です。

コンパイラの追跡は、アプリケーションGUIとコマンドラインの両方から実行できます。 これらすべての仕組みと新しいモードの使用方法の詳細については、記事で説明しています。

エフゲニー・リジコフ。 PVS-Studioは、Windowsのビルドシステムとコンパイラをサポートするようになりました。 簡単ですぐに使用できます

この記事では、コマンドラインモニタリングの開始モードでQtプロジェクトをテストした方法について説明します。

誤解が少なくなるように、この記事を必ずお読みください。 たとえば、プロジェクトのコンパイルが監視されている間、プログラミングを並行して行うことはできません。 別のプロジェクトからファイルをコンパイルすると、それらに関する情報が収集され、それらもチェックされます。 その結果、別のプロジェクトに関連するメッセージがレポートに含まれます。 それは混乱になります。

検証結果


一般的に、次のコードの印象を得ました。

Qtコードは高品質であり、実際にはC ++言語の危険な機能に関連するエラーは含まれていません。 しかし、多くの普通のタイプミス。

この記事は、プロフェッショナリズムに関係なく、すべての開発者がタイプミスをすることをよく示しています。 静的コード分析の利点は、以前も現在もそうです。 アナライザーが1回の実行で10個のタイプミスを見つけたとします。 そのため、定期的に使用すれば、今では数百または数千の間違いを防ぐことができます。 これは非常に時間の節約になります。 コードのデバッグ時やユーザーからの苦情のおかげでエラーを見つけるよりも、コードにエラーが現れた直後にエラーを検出する方がはるかに有益です。

タイプミスの素晴らしい世界に飛び込む


タイプミスの不思議な世界へようこそ

タイプミスN1
bool QWindowsUser32DLL::initTouch() { QSystemLibrary library(QStringLiteral("user32")); registerTouchWindow = ....; unregisterTouchWindow = ....; getTouchInputInfo = ....; closeTouchInputHandle = ....; return registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && getTouchInputInfo; } 

PVS-Studio警告:V501「&&」演算子の左側と右側に同じサブ表現「getTouchInputInfo」があります。 qwindowscontext.cpp 216

4つの変数に値が割り当てられています。 これらの4つの変数を確認する必要があります。 ただし、タイプミスのため、3つだけがチェックされます。最後の行では、「getTouchInputInfo」の代わりに「closeTouchInputHandle」と記述する必要があります。

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

PVS-Studio警告:V501 '||'の左右に同じサブ式があります 演算子:iw <= 0 || iw <= 0 qwindowsfontengine.cpp 1095

変数 'ih'に格納されている高さチェックはありません。

タイプミスN3、N4

このエラーはテストに適用されます。 静的分析が単体テストを補完する方法の良い例です。 このトピックの詳細:「 静的分析がTDDを補完する方法
 inline bool qCompare(QImage const &t1, QImage const &t2, ....) { .... if (t1.width() != t2.width() || t2.height() != t2.height()) { .... } 

警告PVS-Studio:V501 '!='演算子の左右に同じ副次式があります:t2.height()!= T2.height()qtest_gui.h 101

2つの画像を比較する関数は、それらの高さを正しく比較しません。 もっと真に、まったく比較しません。

Copy-Pasteを使用して伝播されたエラー。 まったく同じ比較が、すぐ下の同じファイルで見ることができます(135行目)。

Typo N5

コードをformattedい形式にしたことを申し訳ありません。 行が長すぎました。
 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警告:V501 '||'の左右に同じサブ式があります 演算子。 qxml.cpp 3249

変数 'name'は、同じ文字列と2回比較されます。 上記のコードには、同様の比較があります。 そこで、変数は文字列を使用してこれら2つと比較されます。類推により、上記のコードでは変数「name」が次のものと比較されるべきであると仮定できます。タイプミスN6、N7、N8、N9
 QString DayTimeDuration::stringValue() const { .... if(!m_hours && !m_minutes && !m_seconds && !m_seconds) .... } 

PVS-Studio警告:V501 '&&'演算子の左右に同じ副次式 '!M_seconds'があります。 qdaytimeduration.cpp 148

ミリ秒を忘れました。 ミリ秒は変数「m_mseconds」に保存されます。 チェックは次のようになります。
 if(!m_hours && !m_minutes && !m_seconds && !m_mseconds) 

ミリ秒でさらに3つの同一のエラーがあります。タイプミス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警告:V501「||」の左右に同じ副表現「!QIsFinite(w)」があります 演算子。 qquickcontext2d.cpp 3305

変数 'h'の検証はありません。 代わりに、変数「w」が2回チェックされます。

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

V656変数「num1」、「num2」は、同じ関数の呼び出しによって初期化されます。 おそらくエラーまたは最適化されていないコードです。 「o1.as <Numeric>()」式の検査を検討してください。 行を確認してください:220、221。qatomiccomparators.cpp 221

変数「num1」と「num2」は同じ値で初期化されます。 これらの変数は両方とも以下でチェックされます。 これは疑わしいです。 結局のところ、1つの変数の値のみをチェックするだけで十分です。

ほとんどの場合、変数「num2」は、引数「o2」が使用される式で初期化する必要があります。
 const Numeric *const num1 = o1.as<Numeric>(); const Numeric *const num2 = o2.as<Numeric>(); 

タイプミス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式は常に真です。 ここでは、おそらく「&&」演算子を使用する必要があります。 qsgatlastexture.cpp 271

このコードの条件は意味がありません。 彼女はいつも真実です。 ここで何が間違っているのかを理解しやすくするために、簡単な例を示します。
 int a = ...; if (a != 1 || a != 2) 

変数は常に何かと等しくありません。

正しいコードがどのように見えるかわかりません。 たぶん次のようになります:
 if (image.format() == QImage::Format_ARGB32_Premultiplied || image.format() == QImage::Format_RGB32) { 

または:
 if (image.format() != QImage::Format_ARGB32_Premultiplied && image.format() != QImage::Format_RGB32) { 

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

PVS-Studio警告:V501 '||'の左右に同じサブ式があります 演算子:ignoreTrans || ignoreTrans qdeclarativestategroup.cpp 442

ここで何かが間違っています。 彼らが小切手をどのように書きたかったかは、私には明らかではありません。

タイプミス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の警告:V519 'pattern-> patternRepeatY'変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:1775、1776。qquickcontext2d.cpp 1776

変数 'patternRepeatY'に2つの連続した割り当てが行われます。
 pattern->patternRepeatY = false; pattern->patternRepeatY = false; 

私はそれがここに書かれるべきだと思う:
 } else if (repetition == QStringLiteral("no-repeat")) { pattern->patternRepeatX = false; pattern->patternRepeatY = false; } else { 

C ++の誤用


C ++言語の誤用

私が言ったように、ほとんどの間違いはよくあるタイプミスです。 C ++言語の不適切な使用に関連するエラーはほとんどありません。 しかし、このようなエラーがいくつか見つかりました。

操作の優先順位に関連する美しいエラー
 bool QConfFileSettingsPrivate::readIniLine(....) { .... char ch; while (i < dataLen && ((ch = data.at(i) != '\n') && ch != '\r')) ++i; .... } 

V593「A = B!= C」の表現を検討することを検討してください。 式は次のように計算されます: 'A =(B!= C)'。 qsettings.cpp 1702

ループは、行の終わりを見つけるように設計されています。 行末文字は、文字「\ n」または「\ r」です。

条件内で、文字を取得し、「\ n」および「\ r」と比較する必要があります。 エラーは、演算子「!=」の優先度が演算子「=」の優先度よりも高いために発生します。 このため、文字コードは変数「ch」に書き込まれるのではなく、「true」または「false」に書き込まれます。 その結果、比較 '\ r'はもはや役割を果たしません。

エラーが目立つようにブラケットを配置します。
 while (i < dataLen && ((ch = (data.at(i) != '\n')) && ch != '\r')) 

エラーのため、「\ n」文字のみが行の終わりと見なされます。 行が文字「\ r」で終わる場合、関数は正しく機能しません。

正しいコードは次のとおりです。
 while (i < dataLen && (ch = data.at(i)) != '\n' && ch != '\r') 

精度の低下
 bool QWindowsTabletSupport::translateTabletPacketEvent() { .... const double radAzim = (packet.pkOrientation.orAzimuth / 10) * (M_PI / 180); .... } 

V636「packet.pkOrientation.orAzimuth / 10」式は、暗黙的に「int」型から「double」型にキャストされました。 分数部分の損失を避けるために、明示的な型キャストの使用を検討してください。 例:double A =(double)(X)/ Y;。 qwindowstabletsupport.cpp 467

変数「packet.pkOrientation.orAzimuth」のタイプは「int」です。 この整数変数は数値10で除算されます。除算の結果が「double」型の値と組み合わせて使用​​されることは疑わしいです。 最終結果は、「double」型の変数にも格納されます。

このような整数除算は必ずしも間違いではありません。 おそらく、コードは意図したとおりに正確に記述されています。 しかし、実践が示すように、これは多くの場合、欠陥であり、計算の精度が失われます。

たとえば、変数 'packet.pkOrientation.orAzimuth'を55とすると、計算結果は次のようになります。

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

精度を大幅に高めることができます。 定数10をdouble型として宣言するだけで十分です: "(packet.pkOrientation.orAzimuth / 10.0 )*(M_PI / 180)"。 計算の結果は次のとおりです。

(55 / 10.0)*(3.14159 ... / 180)= 5.5 * 0.01745 ... = 0.095993 ...

プログラマは異なるタイプの変数が混在する式に注意を払わないため、このような不正確さがしばしば発生します。 このような不注意は、多くの場合64ビットエラーにもつながります( 混合演算を参照)。

アナライザーは、さらに51の疑わしい整数除算を検出します。 おそらく、一部の式は開発者が望んでいたものよりも正確ではないでしょう。 それらをリストします: qt-v636.txt

無意味なポインターチェック

「new」演算子を使用してメモリが割り当てられる場合、長い間、ゼロに等しいポインタをチェックすることは意味がありません。 メモリを割り当てることができない場合、例外がスローされます。 もちろん、演算子 'new'が0を返すようにすることもできますが、ここではこれらのケースについては説明しません。

ただし、プログラマーは時々忘れてしまい、無意味なチェックがコードに再び現れます。
 HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone( IEnumVARIANT **ppEnum) { QWindowsEnumerate *penum = 0; *ppEnum = 0; penum = new QWindowsEnumerate(array); if (!penum) return E_OUTOFMEMORY; .... } 

PVS-Studio警告:V668メモリが「新しい」演算子を使用して割り当てられたため、「ペナム」ポインターをnullに対してテストする意味がありません。 メモリ割り当てエラーの場合、例外が生成されます。 qwindowsmsaaaccessible.cpp 141

このようなチェックがいくつかあります:main.cpp 127、qaudiodevicefactory.cpp 236、qaudiodevicefactory.cpp 263、qaudiobuffer.cpp 488、mfvideorenderercontrol.cpp 143、mfvideorenderercontrol.cpp 158、mfvideorenderercontrol.cppprefpppprev 11 、positionpollfactory.cpp 60。

ダークサイド


ダークサイド

これは間違いだとは言えないコードが2つあります。 プロジェクトのアーキテクチャと実装の機能がわかりません。 ただし、これらがエラーではない場合でも、これはC ++プログラミングの欠点です。
 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<void *>(o), 0, instr.typeSize + sizeof(QQmlData)); .... } 

PVS-Studio警告:V598「memset」関数は、「QObject」クラスのフィールドを無効にするために使用されます。 これにより、仮想メソッドテーブルが破損します。 qqmlvme.cpp 658

QObjectクラスには仮想関数があります。 これは、オブジェクトが仮想メソッドのテーブルへのポインターを格納することを意味します。 memset()関数を使用してそのようなオブジェクトを初期化することは、私には良い考えではないようです。

別の警告:V598「memset」関数は、「QObject」クラスのフィールドを無効にするために使用されます。 これにより、仮想メソッドテーブルが破損します。 qdeclarativevme.cpp 286

NULLポインターの逆参照


おそらく、これらのエラーはタイプミスに起因する可能性があります。 しかし、私はそれらを別のグループに分けるのが好きです。 したがって、彼らはより暗く、より深刻に見えます。

ご注意 エラーをグループに分割することは常にかなりarbitrary意的です。 多くの場合、同じエラーは、タイプミス、脆弱性、配列の範囲外などに分類されます。

NULLポインターに戻りましょう。

タイプミスによる誤字脱参照
 QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed( QV4::Managed *m, uint index, bool *hasProperty) { .... if (!m) return m->engine()->currentContext()->throwTypeError(); .... } 

PVS-Studio警告:V522ヌルポインター「m」の逆参照が行われる場合があります。 qquickcontext2d.cpp 3169

どうやら、演算子 '!' ここは不要です。 深刻な間違いにつながる単純なタイプミス。

エラーハンドラーでのNULLポインター逆参照
 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警告:V522 nullポインター 'dn'の逆参照が行われる場合があります。 qdocindexfiles.cpp 539

エラーが発生した場合、診断メッセージが出力されます。 彼らはその中に存在しないオブジェクトから名前を取得しようとします:dn-> name()。

82の潜在的なNULLポインター逆参照

Qtを含むほとんどすべてのプロジェクトでは、nullポインターの操作に欠陥があります。 多くの場合、ポインターが使用された後に検証が実行されます。 これは必ずしも間違いではありません。 原則として、ポインタをゼロに等しくすることはできません。

いずれにせよ、そのような場所は研究し、リファクタリングするに値します。 エラーがなくても、ポインターを余分にチェックすると、コードを読み取るときにプログラマが混乱します。

危険なコードの断片の1つを考えてみましょう。
 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警告:V595 nullptrに対して検証される前に、「アウトライン」ポインターが使用されました。 行を確認してください:1746、1749。qgrayraster.c 1746

gray_raster_render()関数を最適化しようとした瞬間にエラーが発生したと思います。 ほとんどの場合、すでに完成した機能コードに次の行が挿入されています。
 /* return immediately if the outline is empty */ if ( outline->n_points == 0 || outline->n_contours <= 0 ) return 0; 

問題は、「アウトライン」ポインターがヌルになる可能性があることです。 ポインターがゼロであることを確認するのは少し低くなります。

アナライザーは、さらに81の潜在的なエラーを発見しました。 診断メッセージをリストとして提供します: qt-v595.txt

未回答の質問


答えのない質問

奇妙なコードの断片があり、それらがどのように現れ、実際に書かれようとしていたのかを言うのは困難です。 おそらく、これらはタイプミス、おそらく不完全なコード、おそらく失敗したリファクタリングです。

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

PVS-Studio警告:V571繰り返しチェック。 'if(QWindowsContext :: verboseFonts)'条件は、369行目で既に検証されています。qwindowsfontengine.cpp 370

なぜ同じことを再確認するのですか? おそらく、1つのチェックは不要です。 おそらく他の何かをチェックするのを忘れていたのでしょう。

ダブル割り当て
 void Moc::parse() { .... index = def.begin + 1; namespaceList += def; index = rewind; .... } 

PVS-Studio警告:V519「インデックス」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認してください:568、570。moc.cpp 570

変数 'index'に異なる値が割り当てられるのはなぜですか?

他にも似たような奇妙なコードスニペットがいくつかあります。不明なブレークオペレーターの疑い
 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警告:V519「消費」変数には、連続して2回値が割り当てられます。 おそらくこれは間違いです。 行を確認:110、115。googlesuggest.cpp 115

ここでbreakステートメントを忘れましたか?

アナライザーにとっては、変数「consumed」に値「true」を連続して2回割り当てることができるのは奇妙に思えました。 ここでbreakステートメントを忘れている可能性があります。 しかし、私はよくわかりません。 おそらく、最初の割り当て「consumed = true;」を削除する必要があるだけです。

追加のbreakステートメントの疑い
 bool QHelpGenerator::registerVirtualFolder(....) { .... while (d->query->next()) { d->namespaceId = d->query->value(0).toInt(); break; } .... } 

PVS-Studio警告:V612ループ内の無条件の「ブレーク」。 qhelpgenerator.cpp 429

「break」ステートメントが原因でループがすぐに停止するのは正しいですか?

別のそのようなコードがここにあります:qhelpgenerator.cpp 642

雑多


我慢してください。 記事は間もなく終了します。 まだいくつかの雑多なエラーがあります。

toLower()関数の誤った使用
 int main(int argc, char **argv) { .... QByteArray arg(argv[a]); .... arg = arg.mid(1); arg.toLower(); if (arg == "o") .... } 

PVS-Studio警告:V530関数 'toLower'の戻り値を使用する必要があります。 main.cpp 72

「toLower()」関数はオブジェクトを変更しません。 小文字を格納するオブジェクトのコピーを返します。

別の間違い:V530関数 'toLower'の戻り値を使用する必要があります。 main.cpp 1522

配列の境界を越える

状況は複雑です。 集中してください。

そのような番号付きタイプがあります:
 typedef enum { JNone, JCausing, JDual, JRight, JTransparent } Joining; 

JTransparent == 4であることを忘れないでください。

次に、getNkoJoining()関数を検討します。
 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; } 

私たちにとって重要なのは、この関数が「JTransparent」を返すことができるということです。 つまり、関数は4を返すことができます。

プログラムには、2次元配列「joining_table」があります。
 static const JoiningPair joining_table[5][4] = { .... }; 

そして今、エラーが発生する実際の場所:
 static void getNkoProperties(....) { .... Joining j = getNkoJoining(chars[0]); ArabicShape shape = joining_table[XIsolated][j].form2; .... } 

PVS-Studio警告:V557アレイがオーバーランする可能性があります。 「j」インデックスの値は4に達する可能性があります。harfbuzz-arabic.c 516

思い出すと、getNkoJoining()関数は値4を返すことができます。したがって、joining_table [...] [4]配列のセルを参照します。 これは許されません。 配列は配列の境界を超えます。

同じ条件
 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警告:V517「if(A){...} else if(A){...}」パターンの使用が検出されました。 論理エラーが存在する可能性があります。 行を確認してください:386、392。node.cpp 386

チェックは2回実行されます(t == "howto")。 それらの1つは余分だと思います。

同様の警告がいくつかあります。同じアクションを実行する
 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警告:V523「then」ステートメントは「else」ステートメントと同等です。 qbluetoothservicediscoveryagent.cpp 402

条件に関係なく、同じアクションが実行されます。

同様に:pcre_exec.c 5577、ditaxmlgenerator.cpp 1722、htmlgenerator.cpp 388。

継承されたエラー


Qtはいくつかのサードパーティライブラリを使用します。 これらのライブラリにもエラーがあります。 これらのエラーはQtにもあることがわかります。 記事ではそれらについては説明しませんでしたが、言及することを決めました。

私はサードパーティのライブラリを注意深く見ませんでしたが、何かを書きました: qt-3rdparty.txt

ご注意 ただし、Qtを非常に注意深く見たとは思わないでください。 そのような記事を書くには、大規模で表面的な検査のプロジェクトで十分です。

結論


PVS-Studioは、Qtフレームワークなどの高品質で洗練されたプロジェクトでもエラーを検出できる優れた強力なアナライザーです。

初期段階で多くのエラーを検出することで、開発チームの時間を大幅に節約できます。 インクリメンタル分析を使用すると、ファイルをコンパイルした直後にエラーが検出されます。

サイトリンク


  1. オープンソースプロジェクトを定期的にチェックしています。 たとえば、Tor、Chromium、Clang、Firebird、OpenCV。 興味のある方は、「 PVS-Studioを使用してテストしたオープンソースプロジェクト最新リスト 」をご覧ください。
  2. ここでは、PVS-Studioの試用版をダウンロードできます 。 最初は、アラートをナビゲートするために20回クリックします。 自分に関する情報を報告した後、さらに200クリックします。


この記事は英語です。


この記事を英語圏の聴衆と共有したい場合は、翻訳リンクを使用してください:Andrey Karpov。 Qt 5フレームワークの確認

スローポーク質問

記事を読んで質問がありますか?
多くの場合、記事には同じ質問が寄せられます。 ここでそれらに対する回答を収集しました: PVS-StudioおよびCppCatバージョン2014に関する記事の読者からの質問への回答 。 リストをご覧ください。

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


All Articles