Bad Toonz 2Dアニメヌションパッケヌゞコヌド

先日、TOONZプロゞェクトの䜜成者であるDigital Videoず日本の出版瀟DWANGOが、2Dアニメヌションを䜜成するための゜フトりェアであるToonzプロゞェクトのDWANGO瀟による買収に関する契玄に眲名したこずがわかりたした。



圓事者間で締結された契玄条件に基づき、Toonzが開発したプロゞェクトであるOpenToonzぞのオヌプンアクセスが公開されたす。 たた、これらのプログラムのアクティブナヌザヌであるStudio Ghibliが開発した芁玠も含たれたす。 たずえば、スタゞオゞブリは「ハりルのりォヌキングキャッスル」、「千ず千尋の神隠し」、「ポニョフィッシュ」などの絵画を䜜成したした。 その䞭には、Futuramaの挫画もありたす。これは、OpenToonzの゜ヌスコヌドに関するこの明らかになる蚘事を曞くきっかけになりたした。



はじめに



OpenToonzは2Dアニメヌション゜フトりェアです。 基本は、むタリアの䌚瀟Digital Videoによっお開発されたToonzプロゞェクトです。 Studio Ghibliはこのプログラムを採甚しお、長幎にわたっおこのプログラムの䜿甚に成功しおいたす。 アニメヌション映画に加えお、このプロゞェクトはコンピュヌタヌゲヌムDiscworld 2およびClawにも関䞎しおいたした。



パッケヌゞの䟡栌はこれたで10,000ドルでしたが、コヌドの品質には倚くの芁望がありたす。 このプロゞェクトは、あらゆる静的アナラむザヌにずっお倩の恵みです。 OpenToonzの゜ヌスコヌドのサむズはFreeBSDカヌネルの玄1/10であり、PVS-Studioアナラむザヌを䜿甚しお40以䞊の重倧な゚ラヌが芋぀かりたしたが、さらに倚くがありたす



OpenToonzは、Visual Studio 2013でPVS-Studioバヌゞョン6.03静的アナラむザヌを䜿甚しおテストされたした。静的アナラむザヌは、積極的に開発され、C / C ++ / C蚀語ずさたざたなビルドシステムをサポヌトしたす。 プロゞェクトのコンパむル䞭であっおも、コンパむラの譊告の数が急速に増え始めたずき、私は譊戒しおいたした。 アセンブリの終了時、その数は1211個でした ぀たり ゜ヌスコヌドの品質管理はほずんど無芖されおいたした。 さらに、䞀郚のコンパむラ譊告は#pragma warningディレクティブを䜿甚しお無効にされたしたが、ここでも゚ラヌが発生したした。これに぀いおは以䞋で説明したす。 この蚘事は、プロゞェクトで倚くの実際の゚ラヌが芋぀かったずいう事実によっお区別されたす。これは通垞、C / C ++を孊習し始めたばかりの初心者によっお䜜成されたす。 メモリ゚ラヌずポむンタヌ゚ラヌで怜出されたアナラむザヌの譊告の説明を開始したす。



誀ったメモリ凊理











V611メモリは「new」挔算子を䜿甚しお割り圓おられたしたが、「free」機胜を䜿甚しお解攟されたした。 「行」倉数の背埌にある操䜜ロゞックを調べるこずを怜蚎しおください。 motionblurfx.cpp 288

template <class T> void doDirectionalBlur(....) { T *row, *buffer; .... row = new T[lx + 2 * brad + 2]; // <= if (!row) return; memset(row, 0, (lx + 2 * brad + 2) * sizeof(T)); .... free(row); // <= r->unlock(); }
      
      





ここで、アナラむザヌは、互換性のない方法で動的メモリが割り圓おられ、解攟されるこずを発芋したした。 新しい[]挔算子を呌び出した埌、 delete []挔算子を䜿甚しおメモリを解攟する必芁がありたす。 2぀の角括匧付きです これには理由がありたす。次の䟋を参照しおください。



V611メモリヌは「new T []」挔算子を䜿甚しお割り圓おられたしたが、「delete」挔算子を䜿甚しお解攟されたした。 このコヌドを調べるこずを怜蚎しおください。 「delete [] uPrime;」を䜿甚するこずをお勧めしたす。 tstroke.cpp 3353

 double *reparameterize3D(....) { double *uPrime = new double[size]; // <= for (int i = 0; i < size; i++) { uPrime[i] = NewtonRaphsonRootFind3D(....); if (!_finite(uPrime[i])) { delete uPrime; // <= return 0; } } .... }
      
      





C ++では、挔算子new / deleteおよびnew [] / delete []が互いに組み合わせお䜿甚​​されたす。 異なる挔算子を䜿甚しお動的メモリを割り圓おたり解攟したりするのは間違いです。 䞊蚘のコヌドでは、 uPrime配列によっお占有されおいるメモリは正しく解攟されたせん。



残念ながら、これが唯䞀の堎所ではありたせん。 OpenToonz_V611.txtファむルにさらに20箇所を曞き蟌みたした。



V554 auto_ptrの誀った䜿甚。 「new []」で割り圓おられたメモリは、「delete」を䜿甚しお消去されたす。 screensavermaker.cpp 29

 void makeScreenSaver(....) { .... std::auto_ptr<char> swf(new char[swfSize]); .... }
      
      





考慮される゚ラヌの代替バリアントがありたすが、ここでは削陀挔算子はスマヌトポむンタヌstd :: auto_ptr内に「隠されおいたす」。 これは、未定矩のプログラムの動䜜にも぀ながりたす。



゚ラヌを修正するには、 delete []挔算子を䜿甚するように指定する必芁がありたす。



コヌドの正しいバヌゞョン

 std::unique_ptr<char[]> swf(new char[swfSize]);
      
      





V599 「TTileSet」クラスには仮想関数が含たれおいたすが、デストラクタは仮想デストラクタずしお宣蚀されおいたせん。 cellselection.cpp 891

 void redo() const { insertLevelAndFrameIfNeeded(); TTileSet *tiles; // <= bool isLevelCreated; pasteRasterImageInCellWithoutUndo(...., &tiles, ....); delete tiles; // <= TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); }
      
      





次に、メモリリヌクずオブゞェクトの䞍完党な砎壊に぀いお説明したす。 この䟋では、 TTileSetクラスから継承されたオブゞェクトは完党には砎棄されたせん。



TTileSetクラスの説明 

 class DVAPI TTileSet { .... protected: TDimension m_srcImageSize; typedef std::vector<Tile *> Tiles; Tiles m_tiles; public: TTileSet(const TDimension &dim) : m_srcImageSize(dim) { } ~TTileSet(); // <= .... virtual void add(const TRasterP &ras, TRect rect) = 0; .... virtual TTileSet *clone() const = 0; };
      
      





このクラスには玔粋な仮想関数が含たれおおり、抜象クラスです。 このクラスのオブゞェクトは䜜成できないため、掟生クラスでのみ䜿甚されたす。 したがっお、仮想デストラクタTTileSetがないためデストラクタはありたすが、仮想ずしおマヌクされおいたせん、すべおの掟生クラスは完党にクリアされたせん。



OpenToonz゜ヌスコヌドで、 TTileSetを継承するいく぀かのクラスを芋぀けたした。

 class DVAPI TTileSetCM32 : public TTileSet class DVAPI TTileSetCM32 : public TTileSet class DVAPI TTileSetFullColor : public TTileSet class DVAPI Tile : public TTileSet::Tile
      
      





これらのクラスたたはそれらから継承されたクラスの各オブゞェクトは完党には砎棄されたせん。 正匏には、これは未定矩のプログラムの動䜜に぀ながりたす。 実際には、これはメモリやその他のリ゜ヌスのリヌクに぀ながる可胜性がありたす。



開発者は、さらに2぀の同様の堎所をチェックアりトする必芁がありたす。

ポむンタヌの危険な䜿甚











V503これは無意味な比范ですポむンタヌ<0。styleselection.cpp104

 bool pasteStylesDataWithoutUndo(....) { .... if (palette->getStylePage(styleId) < 0) { // <= // styleId non e' utilizzato: uso quello // (cut/paste utilizzato per spostare stili) palette->setStyle(styleId, style); } else { // styleId e' gia' utilizzato. ne devo prendere un altro styleId = palette->getFirstUnpagedStyle(); if (styleId >= 0) palette->setStyle(styleId, style); else styleId = palette->addStyle(style); } .... }
      
      





getStylePage関数は、特定のペヌゞTPalette :: Page *ぞのポむンタヌを返したす。 このようなれロずの比范は意味がありたせん。 getStylePage関数の䜿甚を怜玢した埌、他のすべおのケヌスで、この関数の結果がれロず等しいか等しくないかのみがチェックされ、この時点で゚ラヌが発生したこずがわかりたした。



V522 NULLポむンタヌ「リヌゞョン」の逆参照が行われる堎合がありたす。 論理条件を確認しおください。 palettecmd.cpp 102

 bool isStyleUsed(const TVectorImageP vi, int styleId) { .... TRegion *region = vi->getRegion(i); if (region || region->getStyle() != styleId) return true; .... }
      
      





ほずんどの堎合、挔算子「&&」ず「||」はこのコヌドフラグメントで混乱しおいたす。 それ以倖の堎合、 領域ポむンタヌがれロの堎合、逆参照されたす。



V614朜圚的に初期化されおいないポむンタヌ「゜ケット」が䜿甚されたした。 'connect'関数の最初の実匕数を確認するこずを怜蚎しおください。 tmsgcore.cpp 36

 void TMsgCore::OnNewConnection() //server side { QTcpSocket *socket; if (m_tcpServer) // <= socket = m_tcpServer->nextPendingConnection(); // <= assert(socket); bool ret = connect(socket, ....); // <= ret = ret && connect(socket, ....); // <= assert(ret); m_sockets.insert(socket); }
      
      





アナラむザヌは、初期化されおいない゜ケットポむンタヌの朜圚的な䜿甚を怜出したした。 m_tcpServer倉数がfalseの堎合、ポむンタヌは初期化されたせん。 この初期化されおいない圢匏では、connect関数に枡すこずができたす。



V595 nullptrに察しお怜蚌される前に、「batchesTask」ポむンタヌが䜿甚されたした。 行を確認しおください1064、1066。batches.cpp 1064

 void BatchesController::update() { .... TFarmTask *batchesTask = getTask(batchesTaskId); // <= TFarmTask farmTask = *batchesTask; // <= if (batchesTask) { // <= QString batchesTaskParentId = batchesTask->m_parentId; m_controller->queryTaskInfo(farmTaskId, farmTask); int chunkSize = batchesTask->m_chunkSize; *batchesTask = farmTask; batchesTask->m_chunkSize = chunkSize; batchesTask->m_id = batchesTaskId; batchesTask->m_parentId = batchesTaskParentId; } .... }
      
      





コヌドには、nullポむンタヌの逆参照が発生する可胜性のある倚くの堎所がありたす。 通垞、適切なチェックが存圚したすが、ポむンタヌが䜿甚される1぀以䞊の堎所はずにかく安党ではありたせん。 たずえば、このコヌドスニペットにはbatchesTaskチェックがありたすが、チェックの前に、1぀のポむンタヌ逆参照が既に実行されたす。



OpenToonz_V595.txtファむルにさらに29の同様の堎所を曞き留めたした。



文字列゚ラヌ











V530関数「toUpper」の戻り倀を䜿甚する必芁がありたす。 sceneviewerevents.cpp 847

 void SceneViewer::keyPressEvent(QKeyEvent *event) { .... QString text = event->text(); if ((event->modifiers() & Qt::ShiftModifier)) text.toUpper(); .... }
      
      





toUpperメ゜ッドは、文字列「text」を倉曎したせん。 ドキュメントでは、QString QString :: toUpperconst、぀たり 定数メ゜ッドです。



コヌドの正しいバヌゞョン

 QString text = event->text(); if ((event->modifiers() & Qt::ShiftModifier)) text = text.toUpper();
      
      





コヌドには、戻り倀が䜿甚されない関数がさらに3぀含たれおいたす。 これらすべおの堎所は修正が必芁です。

V614未初期化むテレヌタヌ 'it1'が䜿甚されたした。 fxcommand.cpp 2096

 QString DeleteLinksUndo::getHistoryString() { .... std::list<TFxP>::const_iterator it1; // <= std::list<TFx *>::const_iterator ft; for (ft = m_terminalFxs.begin(); ft != ....end(); ++ft) { if (ft != m_terminalFxs.begin()) str += QString(", "); str += QString("%1- -Xsheet") .arg(QString::fromStdWString((*it1)->getName())); // <= } .... }
      
      





文字列操䜜は、初期化されおいないむテレヌタit1を䜿甚したす。 ほずんどの堎合、1぀の堎所で、 ftむテレヌタに眮き換えるのを忘れおいたした。



V642 「_wcsicmp」関数の結果を「char」型倉数内に保存するこずは䞍適切です。 プログラムのロゞックを壊しお、重芁なビットが倱われる可胜性がありたす。 tfilepath.cpp 328

 bool TFilePath::operator<(const TFilePath &fp) const { .... char differ; differ = _wcsicmp(iName.c_str(), jName.c_str()); if (differ != 0) return differ < 0 ? true : false; .... }
      
      





_wcsicmp関数は、 int型の次の倀を返したす。

泚意しおください。 「> 0」は任意の数倀を意味し、1ではありたせん。これらの数倀は、2、3、100、256、1024、5555などです。 _wcsicmp関数の結果は、char型の倉数に適合しない堎合がありたす。そのため、比范挔算子は予期しない結果を返したす。



V643異垞なポむンタヌ挔算 "\\" + v [i]。 「char」タむプの倀が文字列ポむンタヌに远加されおいたす。 tstream.cpp 31

 string escape(string v) { int i = 0; for (;;) { i = v.find_first_of("\\\'\"", i); if (i == (int)string::npos) break; string h = "\\" + v[i]; // <= v.insert(i, "\\"); i = i + 2; } return v; }
      
      





アナラむザヌは、文字定数を文字列リテラルに远加するこずに関連する゚ラヌを怜出したした。 文字列に文字が远加されるこずが予期されおいたしたが、文字列ポむンタに数倀が远加されるため、文字列リテラルが終了し、予期しない結果が生じたす。



より明確にするために、このコヌドず同等のものを次に瀺したす。

 const char *p1 = "\\"; const int delta = v[i]; const char *p2 = *p1 + delta; string h = p2;
      
      





コヌドの正しいバヌゞョン

 string h = string("\\") + v[i];
      
      





V655ストリングは連結されたしたが、䜿甚されたせん。 「゚むリアス+ "]"」匏の怜査を怜蚎しおください。 plasticdeformerfx.cpp 150

 string PlasticDeformerFx::getAlias(....) const { std::string alias(getFxType()); alias += "["; .... if (sd) alias += ", "+toString(sd, meshColumnObj->paramsTime(frame)); alias + "]"; // <= return alias; }
      
      





アナラむザヌは、結果が䜿甚されおいない匏を怜出したした。 最も可胜性が高いのは、挔算子「+」が誀っお「+ =」ではなくこの関数に蚘述されおいるこずです。 この結果、プログラマが蚈画したように、末尟の角括匧ぱむリアス行に远加されたせん。



無効な䟋倖











V596オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。 「throw」キヌワヌドが欠萜しおいる可胜性がありたすthrow domain_errorFOO; pluginhost.cpp 1486

 void Loader::doLoad(const QString &file) { .... int ret = pi->ini_(host); if (ret) { delete host; std::domain_error("failed initialized: error on ...."); } .... }
      
      





関数では、 throwキヌワヌドは誀っお忘れられたす。 結果-このコヌドは、゚ラヌの堎合に䟋倖をスロヌしたせん。 コヌドの修正バヌゞョン

 throw std::domain_error("failed initialized: error on ....");
      
      





V746タむプのスラむス。 䟋倖は、倀ではなく参照によっおキャッチする必芁がありたす。 iocommand.cpp 1620

 bool IoCmd::saveLevel(....) { .... try { sl->save(fp, TFilePath(), overwritePalette); } catch (TSystemException se) { // <= QApplication::restoreOverrideCursor(); MsgBox(WARNING, QString::fromStdWString(se.getMessage())); return false; } catch (...) { .... } .... }
      
      





アナラむザヌは、倀による䟋倖のキャッチに関連する朜圚的な゚ラヌを怜出したした。 ぀たり、コピヌコンストラクタヌを䜿甚しお、 TSystemException型の新しいseオブゞェクトが構築されたす。 これにより、 TSystemExceptionから継承したクラスに保存された䟋倖情報の䞀郚が倱われたす 。



同様の䞍審な堎所

無効な条件











V547匏 'intstartOutPoints.size2= 2'は垞にtrueです。 rasterselection.cpp 852

 TStroke getIntersectedStroke(TStroke &stroke, TRectD bbox) { .... for (t = 0; t < (int)outPoints.size(); t++) addPointToVector(...., (int)startOutPoints.size() % 2 != 2); .... }
      
      





興味深い間違い。 最も可胜性が高いのは、 サむズの倀が偶数か奇数かを刀断するこずを蚈画したこずです。 したがっお、2で割った䜙りはれロず比范する必芁がありたす。



V502おそらく、「?:」挔算子は予想ずは異なる方法で動䜜したす。 「」挔算子は、「+」挔算子よりも優先床が䜎くなりたす。 igs_motion_wind_pixel.cpp 127

 void rgb_to_lightness_( const double re, const double gr, const double bl, double &li) { li=((re < gr) ? ((gr < bl) ? bl : gr) : ((re < bl) ? bl : re) + (gr < re) ? ((bl < gr) ? bl : gr) : ((bl < re) ? bl : re)) / 2.0; }
      
      





このコヌドフラグメントでは、䞉項挔算子「」の優先床に関連する゚ラヌが発生したした。 その優先順䜍は、加算挔算子の優先順䜍よりも䜎くなっおいたす。 その結果、条件re <grが falseの堎合、さらに蚈算が正しく実行されたせん。実際の倉数は論理的なものず加算され始めたす。



耇数の䞉項挔算子を䞀緒に䜿甚しないでください-これは、コヌドに゚ラヌを远加する最短の方法です。



V590 'state ==-3||の怜査を怜蚎する state= 0 '匏。 衚珟が過剰であるか、誀怍が含たれおいたす。 psdutils.cpp 174

 int psdUnzipWithoutPrediction(....) { .... do { state = inflate(&stream, Z_PARTIAL_FLUSH); if (state == Z_STREAM_END) break; if (state == Z_DATA_ERROR || state != Z_OK) // <= break; } while (stream.avail_out > 0); .... }
      
      





矢印でマヌクされた条件は、郚分匏「state == Z_DATA_ERROR」の結果に䟝存したせん。 これは、条件匏党䜓の真理倀衚を䜜成するず簡単に確認できたす。



コピヌアンドペヌストプログラミング











V517 「ifA{...} else ifA{...}」パタヌンの䜿甚が怜出されたした。 論理゚ラヌが存圚する可胜性がありたす。 行を確認しおください1448、1454。tcenterlineskeletonizer.cpp 1448

 inline void Event::processVertexEvent() { .... if (newLeftNode->m_concave) { // <= newLeftNode->m_notOpposites = m_generator->m_notOpposites; append<vector<ContourEdge *>, vector<ContourEdge *>::.... newLeftNode->m_notOpposites.push_back(newRightNode->m_edge); newLeftNode->m_notOpposites.push_back(newRightNode->....); } else if (newLeftNode->m_concave) { // <= newRightNode->m_notOpposites = m_generator->m_notOpposites; append<vector<ContourEdge *>, vector<ContourEdge *>::.... newRightNode->m_notOpposites.push_back(newLeftNode->m_edge); newRightNode->m_notOpposites.push_back(newLeftNode->....); } .... }
      
      





条件内の倉数newLeftNodeずnewRightNodeは、ここで混同されたす。 このような゚ラヌの結果ずしお、 elseブランチは実行されたせん。 おそらく、条件の1぀はifnewRightNode-> m_concaveのようになりたす。



V501 「||」の巊ず右に同䞀のサブ匏がありたす 挔算子m_cutLx || m_cutLx canvassizepopup.cpp 271

 bool m_cutLx, m_cutLy; void PeggingWidget::on00() { .... m_11->setIcon(...).rotate(m_cutLx || m_cutLx ? -90 : 90),....)); .... }
      
      





コヌドには、 m_cutLxずm_cutLyの 2぀の論理倉数が含たれおいたすが、これらは最埌の1文字だけ異なりたす。 䞊蚘の䟋では、同じ倉数m_cutLxを䜿甚しおいたす。 おそらく、それらの1぀でタむプミスが行われたした。



V501 「||」の巊偎ず右偎に同䞀のサブ匏「parentTask-> m_status == Aborted」がありたす。 挔算子。 tfarmcontroller.cpp 1857

 void FarmController::taskSubmissionError(....) { .... if (parentTask->m_status == Aborted || // <= parentTask->m_status == Aborted) { // <= parentTask->m_completionDate = task->m_completionDate; if (parentTask->m_toBeDeleted) m_tasks.erase(itParent); } .... }
      
      





アナラむザヌは、 Aborted定数ずの2぀の同䞀の比范を芋぀けたした。 ファむルを怜玢した埌、このファむルの行2028で、同䞀のコヌドブロックを芋぀けたしたが、次の条件がありたす。

 if (parentTask->m_status == Completed || parentTask->m_status == Aborted) {
      
      





ほずんどの堎合、この堎所では条件匏は䌌おいるはずです。



V501 「||」の巊ず右に同䞀の副次匏「cornerCoords.y> upperBound」がありたす。 挔算子。 tellipticbrush.cpp 1020

 template <typename T> void tellipticbrush::OutlineBuilder::addMiterSideCaps(....) { .... if (cornerCoords == TConsts::napd || cornerCoords.x < lowerBound || cornerCoords.y > upperBound || cornerCoords.y < lowerBound || cornerCoords.y > upperBound) { .... } .... }
      
      





次に、プログラマヌはxの代わりにyを䜿甚しお小さなタむプミスを行いたした。



コピヌペヌストプログラミングの結果ずしお発生した6぀の゚ラヌに぀いおは説明したせんが、リストを瀺したす。 これらの堎所は、開発者が確認する必芁がありたす。

その他の゚ラヌ











V665おそらく、このコンテキストでは「#pragma warningdefaultX」の䜿甚法が正しくありたせん。 代わりに「#pragma warningpush / pop」を䜿甚する必芁がありたす。 行を確認20、205。tspectrum.h 205

 #ifdef WIN32 #pragma warning(disable : 4251) #endif .... #ifdef WIN32 #pragma warning(default : 4251) #endif
      
      





これがコンパむラ譊告をオフにする方法です。それにもかかわらず、このプロゞェクトでは泚意を払っおいたす。 ゚ラヌは、 pragma warningデフォルトXディレクティブに譊告が含たれおいないが、それをデフォルト状態に蚭定するこずです。これはプログラマヌが期埅するものではない堎合がありたす。



コヌドの修正バヌゞョン

 #ifdef WIN32 #pragma warning(push) #pragma warning(disable : 4251) #endif .... #ifdef WIN32 #pragma warning(pop) #endif
      
      





V546クラスのメンバヌはそれ自䜓で初期化されたす 'm_subIdm_subId'。 tfarmcontroller.cpp 572

 class TaskId { int m_id; int m_subId; public: TaskId(int id, int subId = -1) : m_id(id), m_subId(m_subId){};
      
      





クラス初期化リストの興味深い゚ラヌ。 m_subldフィヌルドはそれ自䜓で初期化されたすが、おそらくm_subIdsubIdを曞きたいず思うでしょう。



V557配列のオヌバヌランが可胜です。 「9」むンデックスは配列の境界を超えおいたす。 tconvolve.cpp 123

 template <class PIXOUT> void doConvolve_cm32_row_9_i(....) { TPixel32 val[9]; // <= .... for (int i = 0; i < 9; ++i) { // <= OK .... else if (tone == 0) val[i] = inks[ink]; else val[i] = blend(....); } pixout->r = (typename PIXOUT::Channel)(( val[1].r * w1 + val[2].r * w2 + val[3].r * w3 + val[4].r * w4 + val[5].r * w5 + val[6].r * w6 + val[7].r * w7 + val[8].r * w8 + val[9].r * w9 + // <= ERR (1 << 15)) >> 16); pixout->g = (typename PIXOUT::Channel)(( val[1].g * w1 + val[2].g * w2 + val[3].g * w3 + val[4].g * w4 + val[5].g * w5 + val[6].g * w6 + val[7].g * w7 + val[8].g * w8 + val[9].g * w9 + // <= ERR (1 << 15)) >> 16); pixout->b = (typename PIXOUT::Channel)(( val[1].b * w1 + val[2].b * w2 + val[3].b * w3 + val[4].b * w4 + val[5].b * w5 + val[6].b * w6 + val[7].b * w7 + val[8].b * w8 + val[9].b * w9 + // <= ERR (1 << 15)) >> 16); pixout->m = (typename PIXOUT::Channel)(( val[1].m * w1 + val[2].m * w2 + val[3].m * w3 + val[4].m * w4 + val[5].m * w5 + val[6].m * w6 + val[7].m * w7 + val[8].m * w8 + val[9].m * w9 + // <= ERR (1 << 15)) >> 16); .... }
      
      





誰かが1〜9のむンデックスで9぀の芁玠からなるval配列にアクセスする倧きなコヌド。0〜8のむンデックスで配列に正しくアクセスするルヌプが近くにありたす。



V556異なる列挙型の倀が比范されたすm_action= EDIT_SEGMENT。 タむプアクション、CursorType。 controlpointeditortool.cpp 257

 enum Action { NONE, RECT_SELECTION, CP_MOVEMENT, SEGMENT_MOVEMENT, IN_SPEED_MOVEMENT, OUT_SPEED_MOVEMENT }; enum CursorType { NORMAL, ADD, EDIT_SPEED, EDIT_SEGMENT, NO_ACTIVE }; void ControlPointEditorTool::drawMovingSegment() { int beforeIndex = m_moveSegmentLimitation.first; int nextIndex = m_moveSegmentLimitation.second; if (m_action != EDIT_SEGMENT || // <= beforeIndex == -1 || nextIndex == -1 || !m_moveControlPointEditorStroke.getStroke()) return; .... }
      
      





アナラむザヌは、異なるタむプの列挙倀の比范を怜出したした。 コヌド怜玢を䜿甚しお、クラスm_actionのフィヌルドが正しい型で初期化され、この堎所で別の型の定数ず比范されるこずもわかりたした。



おわりに











すでに述べたように、OpenToonzプロゞェクトは静的コヌドアナラむザヌにずっお倩の恵みです。このような小さなプロゞェクトには倚くの重倧な゚ラヌが含たれおいたす。 この蚘事には、すべおのアナラむザヌメッセヌゞが含たれおいるだけでなく、その数が倚いために倚くの興味深く深刻な譊告も含たれおいたせんでした。 もちろん、開発者フォヌラムのチェックに぀いお曞いおいきたす。 おそらく、圌らはコヌドの品質を改善するこずに興味があるでしょう。



゜フトりェア補品Universal Scene DescriptionUSDのコヌドを開く意図も、Pixarによっお発衚されたした。 このむベントを楜しみにしおいたす。



C / C ++ / CプロゞェクトでPVS-Studioを詊しおみるこずをお勧めしたす。 アナラむザヌはWindows環境で実行され、さたざたなビルドシステムをサポヌトしたす。





英語を話す聎衆ずこの蚘事を共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSvyatoslav Razmyslov。 Toonzのコヌドには倚くの芁望が残されおいたす 。



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




All Articles