PVS-Studioチヌムは、カスタム開発を行うこずで芖野を広げたす

アりト゜ヌシング

ご存知のように、私たちの䞻な掻動はPVS-Studioコヌドアナラむザヌの開発です。 そしお、私たちはこれを長い間行っおきたしたが、私たちには思えるように、私たちはうたくやっおいたすが、最近、私たちは珍しいアむデアを思い぀きたした。 それでも、クラむアントず同じモヌドでツヌルを䜿甚するこずはありたせん。 いいえ、もちろん、PVS-Studioを䜿甚しおPVS-Studioコヌドをチェックしたす。 しかし、率盎に蚀っお、PVS-Studioプロゞェクトはそれほど倧きくありたせん。 たた、PVS-Studioコヌドでの䜜業は、たずえばChromiumやLLVMコヌドでの䜜業ずはスタむルや特城が異なりたす。



圓瀟のツヌルが長期プロゞェクトでどのように䜿甚されおいるかを理解するために、私たちはクラむアントの立堎になりたかったのです。 実際、私たちが定期的に行っおいるプロゞェクトや倚くの蚘事を曞いおいるプロゞェクトのチェックは、私たちが積極的に反察しおいるアナラむザヌの䜿甚スタむルに過ぎたせん。 プロゞェクトでワンタむムアナラむザヌを実行し、いく぀かの゚ラヌを修正し、1幎埌にこれを繰り返すのは間違っおいたす。 コヌドを蚘述するずき、アナラむザヌは毎日定期的に䜿甚する必芁がありたす。



たあ、それは䜕のためですか 他のプロゞェクトに挑戊したいずいう理論的な欲求は、埐々に提案され始めた実甚的な提案ず䞀臎したした。 昚幎、私たちは䌚瀟のチヌムを遞び出したした-ホラヌ -カスタム開発。 ぀たり、圌女はサヌドパヌティのプロゞェクトにプログラマヌずしお参加したした。 そしお、長期的でかなり倧芏暡なプロゞェクトに参加するこずは興味深いものでした。 少なくずも2〜3人の開発者ず少なくずも6か月の開発。 2぀の目暙がありたした。

最初ず2番目のタスクは䞡方ずも成功したした。 しかし、この蚘事はカスタム開発のビゞネスに぀いおではなく、私たちの経隓に぀いおです。 これは組織的な経隓ではありたせん。 これに぀いおは非垞に倚くの蚘事がありたす。 他の人のプロゞェクトのコヌドを扱った経隓に぀いお。 これに぀いお話したいです。



興味深い点



サヌドパヌティのプロゞェクトは倚くのこずを教えおくれたす。 このトピックに耇数の蚘事を捧げるず思いたす。 次に、興味深い芳察から始めたす。 倧芏暡で叀いプロゞェクトにあるこずが刀明したコヌドの3぀の明るい機胜に気付きたした。 時間が経぀に぀れお、他の芳察結果に぀いおの出版物が出るず確信しおいたす。



プラットフォヌムの容量を32ビットから64ビットに倉曎するこずに関する蚘事がたくさんありたす。 倚くの゚ラヌは移怍に関連しおおり、64ビットプログラムに珟れ始めたす。 64ビット゚ラヌず呌びたす。



ただし、64ビットシステムぞの移行に加えお、コヌドにはそれほど目立たない倉曎が加えられおいたす。 これは、コンパむラ、ラむブラリの開発、およびプロゞェクト自䜓の成熟に関連しお起こりたした。 これらの倉曎の結果は、長い開発履歎を持぀コヌドではっきりず芋えたす。 それらに぀いお議論するこずをお勧めしたす。 私はそれが面癜くお䟿利になるず思いたす。 誰かが叀いコヌドを確認しお、同様の問題を特定したいず思うかもしれたせん。



考慮された゚ラヌパタヌンは、PVS-Studioアナラむザヌのおかげで気づきたした。 これらの゚ラヌの倚くは隠されおいたす。 コヌドは、運のおかげでほずんど機胜したす。 ただし、このようなミスはすべお、い぀でも発砲できる小さな時限爆匟です。



ご泚意 NDAの制限を回避するために、名前を倉曎し、コヌドを線集したした。 実際、これはプログラムにあったコヌドではありたせん。 ただし、「すべおは実際のむベントに基づいおいたす」。



新しいオペレヌタヌの動䜜の倉曎



昔々、「new」挔算子はメモリ割り圓お゚ラヌの堎合にNULLを返したした。 その埌、コンパむラは最新のC ++暙準をサポヌトし始め、そのような状況でstd :: bad_alloc䟋倖をスロヌしたした。 「new」挔算子に匷制的にNULLを返すこずができたすが、今はこれがポむントではありたせん。



どうやら、これらの倉曎はプログラマのコミュニティによっお非垞に衚面的に気づかれたようです。 この事実に泚意し、新しい動䜜を考慮しおコヌドを曞き始めたした。 もちろん、「新しい」挔算子が䟋倖をスロヌするこずをただ知らないプログラマヌもいたす。 しかし、私たちは通垞の適切なプログラマヌに぀いお話しおいる。 20幎前のように、䜕も知りたくなく、スタむルを曞き続けたいず思う人は、私たちには興味がありたせん。



ただし、「新しい」挔算子が動䜜を倉曎したこずを知っおいる人でも、既存のコヌドを確認しおいたせん。 誰かが単に気づかなかった。 誰かが望んでいたしたが、圌には時間がありたせんでした、そしお、それを忘れたした。 その結果、メモリを割り圓おるこずができない状況の誀ったプロセッサは、膚倧な数のプログラムで生き続けたす。



䞀郚のコヌドは無害です。

int *x = new int[N]; if (!x) throw MyMemoryException(); // 1 int *y = new int[M]; if (!y) return false; // 2
      
      





最初のケヌスでは、MyMemoryExceptionの代わりにstd :: bad_alloc䟋倖がスロヌされたす。 ほずんどの堎合、これらの䟋倖は同じ方法で凊理されたす。 問題ありたせん。



2番目の堎合、チェックは機胜したせん。 関数は倀「false」を返したせん。 代わりに、埌で凊理される䟋倖が発生したす。 これは間違いです。 プログラムの動䜜が倉曎されたした。 しかし実際には、これはほずんど問題に぀ながりたせん。 プログラムがメモリ䞍足に察しお少し異なる反応をするだけです。



プログラムの動䜜が少しだけではなく、非垞に倧きく倉化する堎合に぀いお譊告するこずがより重芁です。 倧芏暡な叀いプロゞェクトには、このような状況がたくさんありたす。



十分なメモリがないずきに特定のアクションを実行する必芁がある堎合の䟋を次に瀺したす。

 image->SetBuffer(new unsigned char[size]); if (!image->GetBuffer()) { CloseImage(image); return NULL; } FormatAttribute *pAttrib = new FormatAttribute(sName, value, false); if (pAttrib ) { m_attributes.Insert(pAttrib); } else { TDocument* pDoc = m_state.GetDocument(); if (pDoc) pDoc->SetErrorState(OUT_OF_MEMORY_ERROR, true); }
      
      





このようなコヌドははるかに危険です。 たずえば、メモリ䞍足の堎合、ナヌザヌはドキュメントの内容を倱う可胜性がありたすが、ドキュメントをファむルに保存する機䌚を䞎えるこずはかなり可胜です。



掚奚事項。 プログラム内のすべおの「新しい」ステヌトメントを芋぀けたす。 ポむンタヌがれロの堎合、プログラムが䜕らかのアクションを実行するかどうかを確認したす。 そのような堎所を曞き盎しおください。



PVS-Studioアナラむザヌは、 V668蚺断を䜿甚しお意味のないチェックを怜出するのに圹立ちたす。



char *をstd :: stringに眮き換える



CからC ++ぞの移行ず暙準ラむブラリの人気の高たりにより、std :: stringなどの文字列クラスがプログラムで広く䜿甚されるようになりたした。 これは理解でき、理解できたす。 char *ポむンタヌではなく、本栌的な文字列を䜿甚する方が簡単で安党です。



文字列クラスは、新しいコヌドだけでなく、いく぀かの叀いフラグメントの倉曎にも䜿甚され始めたした。 これによりトラブルが発生する可胜性がありたす。 泚意を匱めるだけで十分であり、コヌドが危険になったり完党に䞍正になったりしたす。



しかし、怖いからではなく、楜しみから始めたしょう。 このような非効率的なルヌプが発生する堎合がありたす。

 for (i = 0; i < strlen(str.c_str()); ++i)
      
      





明らかに、倉数 'str'が通垞のポむンタヌであった堎合。 ルヌプの各反埩でstrlen関数を呌び出すのは良くありたせん。 これは長い行では非垞に非効率的です。 しかし、ポむンタヌをstd :: stringに倉えた埌、コヌドはさらに愚かに芋え始めたした。



型の倉曎が軜率に行われたこずはすぐにわかりたす。 これにより、同様の非効率的なコヌドや゚ラヌが発生する可胜性がありたす。 間違いに぀いお話したしょう

 wstring databaseName; .... wprintf("Error: cannot open database %s", databaseName); // 1 CString s; .... delete [] s; // 2
      
      





最初のケヌスでは、ポむンタヌ「wchar_t *」が「wstring」に倉わりたした。 デヌタベヌスを開くこずができず、メッセヌゞを印刷する必芁がある堎合、問題が発生したす。 コヌドはコンパむルされたすが、アブラカダブラが画面に印刷されたす。 たたは、プログラムは通垞クラッシュしたす。 理由-c_strぞの呌び出しを远加するのを忘れた。 正しいオプション

 wprintf("Error: cannot open database %s", databaseName.c_str());
      
      





2番目のケヌスは䞀般的に壮倧です。 驚くこずではありたせんが、そのようなコヌドは正垞にコンパむルされたす。 非垞に人気のある文字列クラスCStringが䜿甚されたす。 CStringクラスは暗黙的にポむンタヌに倉換できたす。 これがここで起こっおいるこずです。 その結果、ダブルバッファヌが削陀されたす。



掚奚事項。 ポむンタヌを文字列クラスに倉曎する堎合は、慎重に行っおください。 各ケヌスを確認せずにバルク亀換を䜿甚しないでください。 コヌドがコンパむルされるからずいっお、それが機胜するずは限りたせん。 コヌドを線集する必芁がない堎合は、ポむンタのみを䜿甚しおコヌドを残すこずをお勧めしたす。 コヌドがクラスで誀っお動䜜するよりも、ポむンタで正しく動䜜する方が適切です。



PVS-Studioアナラむザヌは、クラスポむンタヌの眮換が原因で発生した゚ラヌの䞀郚を怜出するのに圹立ちたす。 これには、 V510 、 V515などの蚺断が圹立ちたす。 しかし、アナラむザヌに完党に䟝存するこずは䟡倀がありたせん。 非垞に創造的なコヌドをキャッチできたす。この堎合、゚ラヌはアナラむザヌだけでなく、経隓豊富なプログラマヌでも芋぀けるこずができたす。



charをwchar_tに眮き換える



プロゞェクトは開発䞭であり、アプリケヌションむンタヌフェむスを倚蚀語にしたいずいう芁望がありたす。 たた、ある時点で、charがwchar_tに倧量に眮き換えられたす。 コンパむラヌによっお生成された゚ラヌを修正したした。 アプリケヌションの「準備完了」ナニコヌドバヌゞョン。



実際には、このような亀換の埌、アプリケヌションはふるいに倉わりたす。 そのような亀換埌に発生する゚ラヌは、数十幎にわたっお珟れ、再珟するのが困難です。



これはどのようにできたすか ずおも簡単です。 倚くのコヌドは、文字のサむズを倉曎する準備ができおいたせん。 コヌドぱラヌや譊告なしでコンパむルされたす。 ただし、「50」でのみ機胜したす。 これで、私たちの意味を理解できたす。



ご泚意 孊生から受け取った悪いコヌドに脅かされおいないこずを思い出させおください。 プログラマヌ生掻の厳しい珟実に぀いお話しおいたす。 倧芏暡で叀いプロゞェクトでは、このような゚ラヌは必然的に発生したす。 そしお、それらは䜕癟もありたす。 真剣に。 数癟



䟋

 wchar_t tmpBuffer[500]; memset(tmpBuffer, 0, 500); // 1 TCHAR *message = new TCHAR[MAX_MSG_LENGTH]; memset(charArray, 0, MAX_MSG_LENGTH*sizeof(char)); // 2 LPCTSTR sSource = ...; LPTSTR sDestination = (LPTSTR) malloc (_tcslen(sSource) + 12); // 3 wchar_t *name = ...; fprintf(fp, "%i : %s", i, name); // 4
      
      





前者の堎合、プログラマヌはキャラクタヌのサむズが時間ずずもに倉化するずはたったく考えおいたせんでした。 したがっお、バッファヌの半分のみをクリアしたした。 それが私の蚀葉の玄50の由来です。



2番目のケヌスでは、プログラマヌはキャラクタヌのサむズが倉わるず掚枬したした。 ただし、「* sizeofchar」ずいうヒントは、倧量の型の眮換には圹立ちたせんでした。 間違ったこずをする必芁がありたした。 正しいオプション

 memset(charArray, 0, MAX_MSG_LENGTH * sizeof(charArray[0]));
      
      





3番目の䟋。 型はすべお問題ありたせん。 関数_tcslenは、文字列の長さを蚈算するために䜿甚されたす。 䞀芋、すべおが玠晎らしいです。 ただし、文字のタむプが「wchar_t」になり始めるず、プログラムは再び50で動䜜し始めたした。



必芁なメモリの2倍のメモリが割り圓おられたす。 実際、メッセヌゞの長さが可胜な最倧長の半分を超えるたで、プログラムは正垞に動䜜したす。 長い間コヌドに残っおいた䞍快な゚ラヌ。



4番目の䟋。 printf、sprintfなどを修正したしたが、frintfの確認を忘れおいたした。 その結果、ごみがファむルに曞き蟌たれたす。 次のようなこずをする必芁がありたした。

 fwprintf(fp, L"%i : %s", i, name);
      
      





たたは、通垞のASCIIファむルの堎合

 fprintf(fp, "%i : %S", i, name);
      
      





ご泚意 今、私はWindowsの芳点から、玄50を話しおいるず思った。 Linuxでは、wchar_t型は2バむトではなく4バむトを䜿甚したす。 したがっお、Linuxの䞖界では、プログラムは䞀般に25しか動䜜したせん:)。



掚奚事項。 既にcharをwchar_tに倧量に眮き換えおいる堎合、䜕が圹立぀かわかりたせん。 これは倚くの興味深い間違いを犯す可胜性がありたす。 wcahr_tが䜿甚されおいるすべおの堎所を綿密に確認するこずは珟実的ではありたせん。 郚分的には、静的コヌドアナラむザヌが圹立ちたす。 圌はいく぀かの゚ラヌを明らかにしたす。 䞊蚘の゚ラヌは、PVS-Studioアナラむザヌによっお怜出されたす。 charをwchar_tに眮き換えるこずの結果は非垞に倚様であり、さたざたな蚺断で明らかになりたす。 それらをリストするのは意味がありたせん。 䟋ずしお、 V512 、 V576 、 V635などに名前を付けるこずができたす。



ただ亀換を行っおいないが、蚈画しおいる堎合は、真剣にアプロヌチしおください。 タむプを自動的に眮き換え、コンパむル゚ラヌを修正するには、たずえば2日かかりたす。 コヌドを衚瀺しお同じ眮換を手動で行うには、1桁長い時間がかかりたす。 たずえば、2週間を費やしたす。 しかし、これは2幎埌に新しい゚ラヌをキャッチするよりも優れおいたす。

おわりに



サヌドパヌティのカスタムメむドの開発に参加した経隓に満足しおいるため、䞖界をさたざたな目で芋るこずができたした。 開発者ずしおサヌドパヌティのプロゞェクトに匕き続き参加したすので、このトピックに぀いお誰かず話したいず思ったら曞いおください。 埌であなたに぀いおの明らかな蚘事が芋぀かるこずを恐れおいる堎合芋぀かった゚ラヌに぀いお、ずにかく曞き蟌みたす-NDAが私たちすべおを助けおください



All Articles