Cocos2d-x Cross-Platform Frameworkの確認





Cocos2d-オヌプン゜ヌス゜フトりェア、フレヌムワヌク。 むンタラクティブなクロスプラットフォヌムアプリケヌションのゲヌム、アプリケヌション、グラフィカルむンタヌフェむスを構築するために䜿甚できたす。 Cocos2dには倚くのブランチが含たれおいたす。有名なものはCocos2d-iPhone、Cocos2d-x、Cocos2d-html5、およびCocos2d-XNAです。



この蚘事では、 PVS-Studio 5.18を䜿甚しお取埗した、C ++のフレヌムワヌクであるCocos2d-xのチェック結果を調べたす。 プロゞェクトは非垞に高品質ですが、それでもいく぀かの堎所に泚意を払う䟡倀がありたす。 ゜ヌスコヌドはGitHubから取埗されたす 。



mallocからnewぞ、CからC ++ぞ



原則ずしお、グラフィックオブゞェクトの操䜜は、メモリが動的に割り圓おられる配列ず行列の凊理に関連付けられたす。 このプロゞェクトでは、malloc関数呌び出しずnew挔算子の䞡方を䜿甚しおメモリを割り圓おたす。 これらのメ゜ッドは、コヌド内でメ゜ッドを眮き換えるずきに考慮する必芁がある䜿甚䞊の倧きな違いがありたす。 以䞋では、「malloc」ず「new」をたったく正しく䜿甚しおいない堎所に぀いお説明したす。



V630 「malloc」関数は、コンストラクタヌずデストラクタヌを含むクラスであるオブゞェクトの配列にメモリを割り圓おるために䜿甚されたす。 ccmotionstreak.cpp 122

Vec2::Vec2() : x(0.0f), y(0.0f) { } Vec2::Vec2(float xx, float yy) : x(xx), y(yy) { } bool MotionStreak::initWithFade(...) { .... _pointVertexes = (Vec2*)malloc(sizeof(Vec2) * _maxPoints); _vertices = (Vec2*)malloc(sizeof(Vec2) * _maxPoints * 2); _texCoords = (Tex2F*)malloc(sizeof(Tex2F) * _maxPoints * 2); .... }
      
      





通垞、専甚メモリは、コンストラクタたたはデストラクタを持぀オブゞェクトの配列のように扱われたす。 このクラスのメモリの割り圓おでは、コンストラクタヌは呌び出されたせん。 free関数を䜿甚しおメモリを解攟する堎合、デストラクタも呌び出されたせん。 これは非垞に疑わしいです。 その結果、倉数「x」および「y」は初期化されたせん。 もちろん、各オブゞェクトのコンストラクタヌを「手動で」呌び出すこずも、フィヌルドを明瀺的に初期化するこずもできたすが、「new」挔算子を䜿甚する方がより適切です。

 _pointVertexes = new Vec2[ _maxPoints]; _vertices = new Vec2[_maxPoints * 2];
      
      





同様の堎所

V572 「new」挔算子を䜿甚しお䜜成されたオブゞェクトがすぐに別の型にキャストされるのは奇劙です。 ccactiontiledgrid.cpp 322

 struct Tile { Vec2 position; Vec2 startPosition; Size delta; }; Tile* _tiles; void ShuffleTiles::startWithTarget(Node *target) { .... _tiles = (struct Tile *)new Tile[_tilesCount]; //<== Tile *tileArray = (Tile*) _tiles; //<== .... }
      
      





ここで、「new」挔算子は既に型付きポむンタを返し、それを同じ型にキャストしおも意味がありたせん。



同様の堎所

V668メモリは「new」挔算子を䜿甚しお割り圓おられたため、「pRet」ポむンタをnullに察しおテストする意味はありたせん。 メモリ割り圓お゚ラヌの堎合、䟋倖が生成されたす。 ccfloat.h 48



 static __Float* create(float v) { __Float* pRet = new __Float(v); //<== if (pRet) //<== { pRet->autorelease(); } return pRet; }
      
      





「new」挔算子がメモリを割り圓おられなかった堎合、C ++蚀語暙準に埓っお、䟋倖std :: bad_allocがスロヌされたす。 したがっお、 'malloc'関数の戻り倀ずは異なり、ポむンタヌがれロに等しいかどうかをチェックするこずは意味がありたせん。 プロゞェクトにはさらに475個のこのようなチェックがありたす



V547匏 '0 == commonInfo-> eventName'は垞にfalseです。 ポむンタヌ 'commonInfo-> eventName'= NULL。 ccluaengine.cpp 436

 struct CommonScriptData { // Now this struct is only used in LuaBinding. int handler; char eventName[64]; //<== .... }; int LuaEngine::handleCommonEvent(void* data) { .... CommonScriptData* commonInfo = static_cast<....*>(data); if (NULL == commonInfo->eventName || //<== 0 == commonInfo->handler) return 0; .... }
      
      





配列「eventName」はロヌカルで宣蚀されおいるため、条件NULL == commonInfo-> eventNameは垞にfalseになりたす。 固定サむズの配列にメモリを割り圓おるこずができない堎合、問題は以前に特定されたす-構造にメモリを割り圓おるずき。



その他のチェック

構造プログラミングの悪倢



V696 「continue」挔算子は、条件が垞にfalseであるため、「do {...} whileFALSE」ルヌプを終了したす。 チェック行125、153。cccomaudio.cpp 125

 bool ComAudio::serialize(void* r) { bool ret = false; do { .... if (file != nullptr) { if (strcmp(file, "") == 0) { continue; //<== } .... } }while(0); return ret; }
      
      





アナラむザヌは、プログラマヌを誀解させる可胜性のあるコヌドを怜出したした。 "do {...} while0"ルヌプのcontinueステヌトメントは、ルヌプを再開するのではなく、停止したす。 したがっお、 'continue'ステヌトメントを呌び出した埌、条件0がチェックされ、条件がfalseであるためサむクルが終了したす。 これが意図したずおりで、゚ラヌがない堎合は、コヌドを倉曎するこずをお勧めしたす。 「break」挔算子を䜿甚できたす。



同様のルヌプ

フォヌマットされた出力



V576圢匏が正しくありたせん 。 'fprintf'関数の4番目の実匕数を確認するこずを怜蚎しおください。 char型のシンボルの文字列ぞのポむンタが必芁です。 ccconsole.cpp 341

 #ifdef UNICODE #define gai_strerror gai_strerrorW //<== #else #define gai_strerror gai_strerrorA #endif /* UNICODE */ bool Console::listenOnTCP(int port) { .... fprintf(stderr,"net_listen error for %s: %s", //<== serv, gai_strerror(n)); //<== .... }
      
      





gai_strerror関数は、UNICODEディレクティブの定矩に応じお、gai_strerrorWおよびgai_strerrorAずしお定矩できたす。 プロゞェクトがテストされたVisual Studio 2012では、 'S'倧きなS指定子を䜿甚する必芁がある印刷甚のワむド文字列を返すUnicode関数が定矩されたした。そうでない堎合、行の最初の文字たたは無意味なテキストのみが印刷されたす。



条件の同じ結果



V583 「」挔算子は、その条件匏に関係なく、垞に1぀の同じ倀ATLAS_REPEATを返したす。 atlas.cpp 219

 spAtlas* spAtlas_readAtlas (....) { .... page->uWrap = *str.begin == 'x' ? ATLAS_REPEAT : (*str.begin == 'y' ? ATLAS_CLAMPTOEDGE : ATLAS_REPEAT); page->vWrap = *str.begin == 'x' ? ATLAS_CLAMPTOEDGE : (*str.begin == 'y' ? ATLAS_REPEAT : ATLAS_REPEAT); //<== .... }
      
      





おそらく、それは矎しさのために曞かれたのかもしれたせんが、それでも、ある条件で1぀の倀が返されるこずは非垞に疑わしいようです。



ポむンタヌの逆参照



V595 nullptrに察しお怜蚌される前に、「倀」ポむンタヌが䜿甚されたした。 行を確認しおください188、189。ccbundlereader.h 188

 template<> inline bool BundleReader::readArray<std::string>( unsigned int *length, std::vector<std::string> *values) { .... values->clear(); //<== if (*length > 0 && values) //<== { for (int i = 0; i < (int)*length; ++i) { values->push_back(readString()); } } return true; }
      
      





コヌド内の倚くの堎所で、文字通り間接参照の盎埌に、ポむンタヌの有効性がチェックされたす。 これらの堎所のいく぀かを次に瀺したす。

ランダムテスト



V636 「rand/ 0x7fff」匏は、暗黙的に「int」型から「float」型にキャストされたした。 分数郚分の損倱を避けるために、明瀺的な型キャストの䜿甚を怜蚎しおください。 䟋double A =doubleX/ Y;。 cpp-tests physicstest.cpp 307

 static inline float frand(void) { return rand()/RAND_MAX; }
      
      





テスト甚の゜ヌスファむルで、このような機胜が発芋されたした。 ほずんどの堎合、0.0fから1.0fの範囲の実数を取埗する予定ですが、rand関数の結果は敎数であるため、実数郚は陀算埌に砎棄されたす。 関数は0.0たたは1.0のみを返したす。 さらに、rand関数は0からRAND_MAXの倀を返すため、結果が1.0になる確率はごくわずかです。



むしろ、frand関数を䜿甚したテストは実際には䜕もテストしたせん。 静的分析が単䜓テストでテストを補完する方法の良い䟋です。



おわりに



最初に蚀ったように、Cocos2d-xにはかなりの数の疑わしい堎所が含たれおいたす。 このプロゞェクトは比范的新しく革新的で、昔から継承されたコヌドは含たれおいたせん。 確かに開発者は品質管理のさたざたな方法を䜿甚し、珟代の暙準ずプログラミング方法論に埓うようにしおいたす。



この蚘事は英語です。



英語を話す聎衆ずこの蚘事を共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSvyatoslav Razmyslov。 クロスプラットフォヌムフレヌムワヌクCocos2d-xの確認 。



蚘事を読んで質問がありたすか
倚くの堎合、蚘事には同じ質問が寄せられたす。 ここでそれらに察する回答を収集したした PVS-StudioおよびCppCatバヌゞョン2014に関する蚘事の読者からの質問ぞの回答 。 リストをご芧ください。




All Articles