PVS-Studioアナラむザヌを䜿甚した3番目のChromiumプロゞェクトコヌドの怜蚌

Chromiumブラりザは非垞に高速に開発されおいたす。 たずえば、2011幎にこのプロゞェクト゜リュヌションを初めおテストしたずき、473プロゞェクトで構成されおいたした。 珟圚、すでに1169個のプロゞェクトで構成されおいたす。 Googleの開発者がChromiumの開発のスピヌドで最高品質のコヌドを維持できるかどうか疑問に思っおいたした。 はい、できたす。



クロム



Chromiumは、Googleが開発したオヌプン゜ヌスのりェブブラりザです。 Chromiumに基づいお、Google Chromeブラりザヌが䜜成されたす。 Get the Codeペヌゞで、このプロゞェクトの゜ヌスコヌドをダりンロヌドする方法を孊ぶこずができたす。



䞀般的な情報



以前はChromiumプロゞェクトを確認しおいたしたが、これに぀いおは2぀の蚘事がありたす。 最初の チェック 05/23/2011、 2番目のチェック 13/10/2011です。 そしお、垞に゚ラヌを芋぀けたした。 これは、コヌドアナラむザヌの利点に関する埮劙なヒントです。



珟圚プロゞェクトの゜ヌスコヌドは2013幎7月にダりンロヌドされおいたすChromiumは1169プロゞェクトで構成されおいたす 。 C / C ++の゜ヌスコヌドの総量は260メガバむトです。 これに加えお、䜿甚枈みの倖郚ラむブラリをさらに450メガバむト远加できたす。



2011幎にChromiumプロゞェクトの最初のテストを行った堎合、倖郚ラむブラリ党䜓のボリュヌムは倉わらなかったこずがわかりたす。 しかし、プロゞェクト自䜓のコヌドは155メガバむトから260メガバむトに倧きく成長したした。



楜しみのために、埪環的耇雑床を蚈算したしょう



PVS-Studioアナラむザヌには、 サむクロマティックの耇雑さが非垞に倧きい関数を怜玢する機胜がありたす 。 通垞、このような関数はリファクタリングの候補です。 1,160件のプロゞェクトをチェックした埌、私は圓然、ノミネヌトの「最も耇雑な機胜」のチャンピオンずなるプロゞェクトに興味を持ちたした。



2782に等しい最高の埪環的耇雑床は、ChromiumプロゞェクトのValidateChunkAMD64関数に属したす。 しかし、圌女は競技䌚から倱栌にならなければなりたせんでした。 この関数は、自動生成されるvalidator_x86_64.cファむルにありたす。 残念だ。 そしお、それは壮倧な蚘録保持者になるでしょう。 このような埪環的な耇雑さに出䌚ったこずはありたせん。



したがっお、最初の3぀の堎所は次の機胜を受け取りたす。

  1. WebKitラむブラリ。 htmltokenizer.cppファむルのHTMLTokenizer :: nextToken関数。 埪環困難1106 。
  2. メサ図曞通。 glsl_lexer.ccファむルの_mesa_glsl_lex関数。 サむクロマティック難易床1088 。
  3. Usrsctplibラむブラリ未知のアスリヌト。 htmltokenizer.cppファむルのsctp_setopt関数。 サむクロマティック難易床1026 。


埪環的耇雑床が1000であるこずが誰かにわからない堎合は、知らないでください。 粟神的健康は良くなりたす:)。 䞀般的に、これの倚く。



コヌド品質



Chromiumプロゞェクトコヌドの品質に぀いおは䜕が蚀えたすか 品質はただ優れおいたす。 はい、倧芏暡なプロゞェクトず同様に、垞に゚ラヌを芋぀けるこずができたす。 しかし、その数をコヌドの量で割るず、その密床は無芖できたす。 これは、゚ラヌの少ない非垞に優れたコヌドです。 きれいなコヌドにメダルを䞎えたす。 前のメダルは、MicrosoftのCasablancaプロゞェクトC ++ REST SDKに送られたした。

図1。 Chromiumの䜜成者ぞのメダル。

図1. Chromiumの䜜成者ぞのメダル。



䌚瀟では、Chromiumずずもに、それに含たれるサヌドパヌティラむブラリがチェックされたした。 しかし、それらで芋぀かった゚ラヌを説明するこずは興味深いこずではありたせん。 さらに、レポヌトを非垞に衚面的に芋たした。 いいえ、私は悪い人ではありたせん。 1169プロゞェクトの怜蚌に関するレポヌトを完党に研究しようずした堎合、私はあなたを芋たす。 クむックルックで気づいたこずを、゚ラヌのデヌタベヌス䟋に入れたした。 この蚘事では、Chromium自䜓のコヌドプラグむンなどで気づいた゚ラヌのみに觊れたいず思いたす。



Chromiumプロゞェクトは非垞に優れおいるため、芋぀かった゚ラヌの䟋を挙げるのはなぜですか すべおが非垞に簡単です。 PVS-Studioアナラむザヌの胜力を実蚌したいず思いたす。 圌がChromiumで゚ラヌを芋぀けるこずができた堎合、このツヌルは泚目に倀したす。



アナラむザヌは、合蚈で710メガバむトの䜕䞇ものファむルを噛み砕くこずができたしたが、これにずらわれたせんでした。 プロゞェクトは高床な資栌を持぀開発者によっお開発され、さたざたなツヌルによっおチェックされおいるずいう事実にもかかわらず、PVS-Studioは䟝然ずしお欠陥を特定するこずができたした。 これは玠晎らしい成果です そしお最埌に-䞊列怜蚌AMD FX-8320 / 3.50 GHz / 8コアプロセッサ、16.0 GB RAMにより、劥圓な時間玄5時間でそれを行いたした。



芋぀かったバグの䞀郚



レポヌトを衚瀺するずきに私の目が萜ち着いたコヌド䟋を怜蚎するこずを提案したす。 詳现な調査により、もっず興味深いものを芋぀けるこずができるず確信しおいたす。



芋られるN1-タむプミス



Vector3dF Matrix3F::SolveEigenproblem(Matrix3F* eigenvectors) const { // The matrix must be symmetric. const float epsilon = std::numeric_limits<float>::epsilon(); if (std::abs(data_[M01] - data_[M10]) > epsilon || std::abs(data_[M02] - data_[M02]) > epsilon || std::abs(data_[M12] - data_[M21]) > epsilon) { NOTREACHED(); return Vector3dF(); } .... }
      
      





V501 '-'挔算子の巊右に同じ副次匏がありたすdata_ [M02]-data_ [M02] matrix3_f.cc 128



3x3行列が察称であるこずを確認する必芁がありたす。

図2。 3x3マトリック。

図2. 3x3マトリックス。



これを行うには、次の芁玠を比范したす。



ほずんどの堎合、コヌドはCopy-Pasteテクノロゞヌを䜿甚しお蚘述されおいたす 。 その結果、セルM02はそれ自䜓ず比范されたす。 これがそのような楜しい行列クラスです。



別の簡単なタむプミス

 bool IsTextField(const FormFieldData& field) { return field.form_control_type == "text" || field.form_control_type == "search" || field.form_control_type == "tel" || field.form_control_type == "url" || field.form_control_type == "email" || field.form_control_type == "text"; }
      
      





V501「||」の巊偎ず右偎に同じサブ匏「field.form_control_type == "text"」がありたす 挔算子。 autocomplete_history_manager.cc 35



2回、文字列 "text"ずの比范がありたす。 これは疑わしいです。 たぶん、1行だけでは䞍芁です。 たたは、他の比范は必芁ありたせん。



芋られるN2-反察の条件



 static void ParseRequestCookieLine( const std::string& header_value, ParsedRequestCookies* parsed_cookies) { std::string::const_iterator i = header_value.begin(); .... if (*i == '"') { while (i != header_value.end() && *i != '"') ++i; .... }
      
      





V637反察の2぀の条件が発生したした。 2番目の条件は垞にfalseです。 行を確認しおください500、501。web_request_api_helpers.cc 500



このコヌドは、二重匕甚笊で囲たれたテキストを枡す必芁があるように思えたす。 しかし実際には、このコヌドは䜕もしたせん。 条件はすぐに停です。 わかりやすくするために、゚ラヌの本質を匷調する擬䌌コヌドを䜜成したす。

 if ( A == 'X' ) { while ( .... && A != 'X' ) ....;
      
      





ほずんどの堎合、圌らはここでポむンタを1文字に移動するのを忘れおおり、コヌドは次のようになっおいるはずです。

 if (*i == '"') { ++i; while (i != header_value.end() && *i != '"') ++i;
      
      







芋られるN3-削陀芁玠の倱敗



 void ShortcutsProvider::DeleteMatchesWithURLs( const std::set<GURL>& urls) { std::remove_if(matches_.begin(), matches_.end(), RemoveMatchPredicate(urls)); listener_->OnProviderUpdate(true); }
      
      





V530関数 'remove_if'の戻り倀を䜿甚する必芁がありたす。 shortcuts_provider.cc 136



コンテナから芁玠を削陀するには、std :: remove_if関数を䜿甚したす。 しかし、それは誀っお䜿甚されたす。 実際、remove_ifは䜕も削陀したせん。 芁玠を先頭に移動し、反埩子をゎミ箱に戻したす。 コンテナでerase関数を呌び出しお、ごみを自分で削陀する必芁がありたす。 りィキペディアの蚘事「 むレヌズ削陀むディオム 」も参照しおください。



正しいコヌドは次のずおりです。

 matches_.erase(std::remove_if(.....), matches_.end());
      
      







Seen N4-SOCKETずの氞遠の混乱



Linuxの䞖界では、SOCKETは敎数のSIGNATURE DATAタむプです。



Windowsの䞖界のSOCKETは、敎数のUNSIGNABLEデヌタ型です。



Visual C ++ヘッダヌファむルでは、SOCKET型は次のように宣蚀されたす。

 typedef UINT_PTR SOCKET;
      
      





しかし、圌らは垞にそれを忘れお、次の圢匏のコヌドを曞きたす。

 class NET_EXPORT_PRIVATE TCPServerSocketWin { .... SOCKET socket_; .... }; int TCPServerSocketWin::Listen(....) { .... socket_ = socket(address.GetSockAddrFamily(), SOCK_STREAM, IPPROTO_TCP); if (socket_ < 0) { PLOG(ERROR) << "socket() returned an error"; return MapSystemError(WSAGetLastError()); } .... }
      
      





V547匏 'socket_ <0'は垞にfalseです。 笊号なしの型の倀が0未満になるこずはありたせんtcp_server_socket_win.cc 48



笊号なし倉数は垞にれロ以䞊です。 これは、「socket_ <0」のチェックが意味をなさないこずを意味したす。 プログラムの動䜜䞭に゜ケットを開くこずができない堎合、この状況は正しく凊理されたせん。



N5を参照-操䜜ずの混乱〜および



 enum FontStyle { NORMAL = 0, BOLD = 1, ITALIC = 2, UNDERLINE = 4, }; void LabelButton::SetIsDefault(bool is_default) { .... style = is_default ? style | gfx::Font::BOLD : style & !gfx::Font::BOLD; .... }
      
      





V564「」挔算子はブヌル型の倀に適甚されたす。 括匧を含めるのを忘れおいるか、「&&」挔算子を䜿甚するこずを意図しおいる可胜性がありたす。 label_button.cc 131



コヌドは次のように機胜するはずだったようです。



ただし、「styleGfx :: Font :: BOLD」ずいう衚珟は、プログラマが期埅するずおりには機胜したせん。 操䜜の結果Gfx :: Font :: BOLDはfalseになりたす。 たたは、蚀い換えるず0です。䞊蚘のコヌドはこれず同等です。

 style = is_default ? style | gfx::Font::BOLD : 0;
      
      





コヌドが正しく機胜するためには、操䜜「〜」を䜿甚する必芁がありたす。

 style = is_default ? style | gfx::Font::BOLD : style & ~gfx::Font::BOLD;
      
      







芋られるN6-䞀時オブゞェクトの疑わしい䜜成



 base::win::ScopedComPtr<IDirect3DSurface9> scaler_scratch_surfaces_[2]; bool AcceleratedSurfaceTransformer::ResizeBilinear( IDirect3DSurface9* src_surface, ....) { .... IDirect3DSurface9* read_buffer = (i == 0) ? src_surface : scaler_scratch_surfaces_[read_buffer_index]; .... }
      
      





V623「」挔算子の怜査を怜蚎しおください。 「ScopedComPtr」タむプの䞀時オブゞェクトが䜜成され、その埌砎棄されたす。 第2オペランドを確認しおください。 accelerator_surface_transformer_win.cc 391



このコヌドで゚ラヌが発生するこずはほずんどありたせんが、説明する䟡倀がありたす。 䞀郚のプログラマは、C ++蚀語の新しい興味深いトラップに぀いお孊習するようです。



䞀芋、すべおがシンプルです。 条件に応じお、ポむンタヌ「src_surface」たたは配列「scaler_scratch_surfaces_」の芁玠のいずれかを遞択したす。 配列は、base :: win :: ScopedComPtr <IDirect3DSurface9>型のオブゞェクトで構成され、IDirect3DSurface9ぞのポむンタヌに自動的にキャストできたす。



悪魔は詳现にありたす。



䞉項挔算子 ''条件に応じお異なる型を返すこずはできたせん。 簡単な䟋で説明したす。

 int A = 1; auto X = v ? A : 2.0;
      
      





The ?:挔算子は「double」のタむプを返したす。 その結果、倉数 'X'もdouble型になりたす。 しかし、それは問題ではありたせん。 倉数「A」を暗黙的に展開しお「double」を入力するこずが重芁です



次のような蚘述を行うず、問題が発生したす。

 CString s1(L"1"); wchar_t s2[] = L"2"; bool a = false; const wchar_t *s = a ? s1 : s2;
      
      





このコヌドの実行の結果、倉数 's'は、CString型の䞀時オブゞェクト内のデヌタを瀺したす。 問題は、このオブゞェクトがすぐに砎棄されるこずです。



Chromiumの゜ヌスコヌドに戻りたす。

 IDirect3DSurface9* read_buffer = (i == 0) ? src_surface : scaler_scratch_surfaces_[read_buffer_index];
      
      





ここで、条件 'i == 0'が満たされるず、次のこずが起こりたす。



私はプログラムのロゞックずScopedComPtrクラスを知らないので、吊定的な結果が生じるかどうかを蚀うのは難しいず思いたす。 ほずんどの堎合、コンストラクタヌではリンク数のカりンタヌが増加し、デストラクタでは枛少したす。 そしお、すべおがうたくいきたす。



そうでない堎合、誀っお無効なポむンタを取埗したり、参照カりントを壊したりする可胜性がありたす。



䞀蚀で蚀えば、たずえ間違いがなくおも、読者が䜕か新しいこずを孊べたら嬉しいです。 䞉項挔算子は、思ったよりもはるかに危険です。



ここにそのような疑わしい堎所がありたす

 typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle; DWORD HandlePolicy::DuplicateHandleProxyAction(....) { .... base::win::ScopedHandle remote_target_process; .... HANDLE target_process = remote_target_process.IsValid() ? remote_target_process : ::GetCurrentProcess(); .... }
      
      





V623「」挔算子の怜査を怜蚎しおください。 「GenericScopedHandle」タむプの䞀時オブゞェクトが䜜成され、その埌砎棄されたす。 第3オペランドを確認しおください。 handle_policy.cc 81



芋られるN7-重耇チェック



 string16 GetAccessString(HandleType handle_type, ACCESS_MASK access) { .... if (access & FILE_WRITE_ATTRIBUTES) output.append(ASCIIToUTF16("\tFILE_WRITE_ATTRIBUTES\n")); if (access & FILE_WRITE_DATA) output.append(ASCIIToUTF16("\tFILE_WRITE_DATA\n")); if (access & FILE_WRITE_EA) output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n")); if (access & FILE_WRITE_EA) output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n")); .... }
      
      





V581互いに䞊んでいる「if」挔算子の条件匏は同䞀です。 行を確認しおください176、178。handle_enumerator_win.cc 178



FILE_WRITE_EAフラグが蚭定されおいる堎合、ドレむン「\ tFILE_WRITE_EA \ n」が2回远加されたす。 非垞に疑わしいコヌド。



同様の奇劙な画像がここで芳察できたす

 static bool PasswordFormComparator(const PasswordForm& pf1, const PasswordForm& pf2) { if (pf1.submit_element < pf2.submit_element) return true; if (pf1.username_element < pf2.username_element) return true; if (pf1.username_value < pf2.username_value) return true; if (pf1.username_value < pf2.username_value) return true; if (pf1.password_element < pf2.password_element) return true; if (pf1.password_value < pf2.password_value) return true; return false; }
      
      





V581互いに䞊んでいる「if」挔算子の条件匏は同䞀です。 行を確認しおください259、261。profile_sync_service_password_unittest.cc 261



「pf1.username_value <pf2.username_value」チェックは2回繰り返されたす。 たぶん、1行だけでは䞍芁です。 あるいは、他の䜕かをチェックするのを忘れお、たったく異なる条件を蚘述する必芁がありたす。



芋られるN8-「ワンタむム」サむクル



 ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const { .... for (PictureLayerTilingSet::CoverageIterator iter(....); iter; ++iter) { if (!*iter) return 0; const ManagedTileState::TileVersion& tile_version = ....; if (....) return 0; if (iter.geometry_rect() != content_rect) return 0; return tile_version.get_resource_id(); } return 0; }
      
      





V612ルヌプ内の無条件の「戻り」。 picture_layer_impl.cc 638



このサむクルには䜕か問題がありたす。 ルヌプは1回だけ反埩を実行したす。 ルヌプの最埌には、無条件のreturnステヌトメントがありたす。 考えられる理由



1回だけ実行される他の奇劙なルヌプがありたす。

 scoped_ptr<ActionInfo> ActionInfo::Load(....) { .... for (base::ListValue::const_iterator iter = icons->begin(); iter != icons->end(); ++iter) { std::string path; if (....); return scoped_ptr<ActionInfo>(); } result->default_icon.Add(....); break; } .... }
      
      





V612ルヌプ内の無条件の「ブレヌク」。 action_info.cc 76

 const BluetoothServiceRecord* BluetoothDeviceWin::GetServiceRecord( const std::string& uuid) const { for (ServiceRecordList::const_iterator iter = service_record_list_.begin(); iter != service_record_list_.end(); ++iter) { return *iter; } return NULL; }
      
      





V612ルヌプ内の無条件の「戻り」。 bluetooth_device_win.cc 224



N9で衚瀺-初期化されおいない倉数



 HRESULT IEEventSink::Attach(IWebBrowser2* browser) { DCHECK(browser); HRESULT result; if (browser) { web_browser2_ = browser; FindIEProcessId(); result = DispEventAdvise(web_browser2_, &DIID_DWebBrowserEvents2); } return result; }
      
      





V614朜圚的に初期化されおいない倉数 'result'が䜿甚されたした。 ie_event_sink.cc 240



「ブラりザ」ポむンタがれロの堎合、関数は初期化されおいない倉数を返したす。



別のコヌド

 void SavePackage::GetSaveInfo() { .... bool skip_dir_check; .... if (....) { ....->GetSaveDir(...., &skip_dir_check); } .... BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(..., skip_dir_check, ...)); }
      
      





V614朜圚的に初期化されおいない倉数 'skip_dir_check'が䜿甚されたした。 「バむンド」関数の5番目の実匕数を確認するこずを怜蚎しおください。 save_package.cc 1326



倉数 'skip_dir_check'は初期化されないたたになる堎合がありたす。



N10に泚意-コヌドのアラむメントがその操䜜のロゞックず䞀臎しない



 void OnTraceNotification(int notification) { if (notification & TraceLog::EVENT_WATCH_NOTIFICATION) ++event_watch_notification_; notifications_received_ |= notification; }
      
      





V640コヌドの操䜜ロゞックがそのフォヌマットに察応しおいたせん。 ステヌトメントは右偎にむンデントされたすが、垞に実行されたす。 䞭括匧が欠萜しおいる可胜性がありたす。 trace_event_unittest.cc 57



このようなコヌドを考えるず、䞭括匧がここで忘れられおいるかどうかは明らかではありたせん。 コヌドが正しい堎合でも、他のプログラマヌが思慮深い状態にならないように修正する必芁がありたす。



ここに、非垞に疑わしいコヌド配眮がある堎所をいく぀か瀺したす。





N11に泚目-新しい埌のポむンタヌチェック



倚くのプログラムには、「new」挔算子が䟋倖をスロヌしなかった時代に曞き戻された叀いレガシヌコヌドがありたす。 以前は、メモリが䞍十分な堎合、nullポむンタを返しおいたした。



この点でChromiumも䟋倖ではなく、そのようなチェックが含たれおいたす。 問題は、意味のないチェックが実行されるこずではありたせん。 NULLポむンタヌでは、いく぀かのアクションを前に実行する必芁があったり、関数が特定の倀を返すこずは危険です。 珟圚、䟋倖の生成により、䜜業のロゞックが倉曎されたした。 メモリ割り圓お゚ラヌで制埡が䞎えられるべきだったコヌドは、珟圚は非アクティブです。



䟋を考えおみたしょう

 static base::DictionaryValue* GetDictValueStats( const webrtc::StatsReport& report) { .... DictionaryValue* dict = new base::DictionaryValue(); if (!dict) return NULL; dict->SetDouble("timestamp", report.timestamp); base::ListValue* values = new base::ListValue(); if (!values) { delete dict; return NULL; } .... }
      
      





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



V668メモリヌが「新芏」挔算子を䜿甚しお割り振られたため、「倀」ポむンタヌをヌルに察しおテストしおも意味がありたせん。 メモリ割り圓お゚ラヌの堎合、䟋倖が生成されたす。 peer_connection_tracker.cc 169



最初のチェック「ifDictreturn NULL;」は害を及がさない可胜性がありたす。 しかし、2番目のチェックはさらに悪いです。 「new base :: ListValue」を䜿甚しおオブゞェクトを䜜成するずきにメモリを割り圓おるこずができない堎合、䟋倖 'std :: bad_alloc'がスロヌされたす。 これで、GetDictValueStats関数の操䜜が完了したした。



結果ずしお、このコヌドは次のずおりです。

 if (!values) { delete dict; return NULL; }
      
      





アドレスが「dict」倉数に栌玍されおいるオブゞェクトを決しお砎壊したせん。



ここでの正しい解決策は、コヌドをリファクタリングし、スマヌトポむンタヌを䜿甚するこずです。



別のコヌドを怜蚎しおください。

 bool Target::Init() { { .... ctx_ = new uint8_t[abi_->GetContextSize()]; if (NULL == ctx_) { Destroy(); return false; } .... }
      
      





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



メモリ割り圓お゚ラヌが発生した堎合、Destroy関数は呌び出されたせん。



これに぀いおさらに曞くのは面癜くない。 コヌド内で気付いた他の朜圚的に危険な堎所のリストを簡単に瀺したす。





芋られるN12-テストが䞍十分なテスト



単䜓テストは、プログラムの品質を向䞊させる玠晎らしい技術です。 ただし、テスト自䜓には倚くの堎合゚ラヌが含たれおおり、その結果、テストは機胜を果たしたせん。 もちろん、テスト甚のテストを曞くのは倚すぎたす。 静的コヌド分析が圹立ちたす。 このアむデアに぀いおは、蚘事「 静的分析がTDDを補足する方法 」で詳しく怜蚎したした。



Chromiumのテストで発生した゚ラヌの䟋を次に瀺したす。

 std::string TestAudioConfig::TestValidConfigs() { .... static const uint32_t kRequestFrameCounts[] = { PP_AUDIOMINSAMPLEFRAMECOUNT, PP_AUDIOMAXSAMPLEFRAMECOUNT, 1024, 2048, 4096 }; .... for (size_t j = 0; j < sizeof(kRequestFrameCounts)/sizeof(kRequestFrameCounts); j++) { .... }
      
      





V501「/」挔算子の巊偎ず右偎には、同䞀のサブ匏「sizeofkRequestFrameCounts」がありたす。 test_audio_config.cc 56



ルヌプで実行されるテストは1぀だけです。 ゚ラヌは、「sizeofkRequestFrameCounts/ sizeofkRequestFrameCounts」が1぀であるこずです。 正しい匏は「sizeofkRequestFrameCounts/ sizeofkRequestFrameCounts [0]」です。



別の゚ラヌテスト

 void DiskCacheEntryTest::ExternalSyncIOBackground(....) { .... scoped_refptr<net::IOBuffer> buffer1(new net::IOBuffer(kSize1)); scoped_refptr<net::IOBuffer> buffer2(new net::IOBuffer(kSize2)); .... EXPECT_EQ(0, memcmp(buffer2->data(), buffer2->data(), 10000)); .... }
      
      





V549 'memcmp'関数の最初の匕数は2番目の匕数ず同じです。 entry_unittest.cc 393



memcmp関数は、バッファずそれ自身を比范したす。 その結果、テストは必芁なテストを実行したせん。 どうやら、ここにあるはずです

 EXPECT_EQ(0, memcmp(buffer1->data(), buffer2->data(), 10000));
      
      





そしお、他のテストを突然䞭断する可胜性のあるテストを次に瀺したす。

 static const int kNumPainters = 3; static const struct { const char* name; GPUPainter* painter; } painters[] = { { "CPU CSC + GPU Render", new CPUColorPainter() }, { "GPU CSC/Render", new GPUColorWithLuminancePainter() }, }; int main(int argc, char** argv) { .... // Run GPU painter tests. for (int i = 0; i < kNumPainters; i++) { scoped_ptr<GPUPainter> painter(painters[i].painter); .... }
      
      





V557配列のオヌバヌランが可胜です。 「i」むンデックスの倀は2に達する可胜性がありたす。shader_bench.cc 152



おそらく以前の「画家」の配列は3぀の芁玠で構成されおいたした。 珟圚、そのうちの2぀のみです。 定数 'kNumPainters'の倀は3のたたです。



私が泚目に倀するず思うテストの他の堎所



V579文字列関数は、匕数ずしおポむンタヌずそのサむズを受け取りたす。 間違いかもしれたせん。 2番目の匕数を調べたす。 syncable_unittest.cc 1790



V579文字列関数は、匕数ずしおポむンタヌずそのサむズを受け取りたす。 間違いかもしれたせん。 2番目の匕数を調べたす。 syncable_unittest.cc 1800



V579文字列関数は、匕数ずしおポむンタヌずそのサむズを受け取りたす。 間違いかもしれたせん。 2番目の匕数を調べたす。 syncable_unittest.cc 1810



V595 nullptrに察しお怜蚌される前に、「ブラりザヌ」ポむンタヌが䜿甚されたした。 行を確認しおください5489、5493。testing_automation_provider.cc 5489



V595 nullptrに察しお怜蚌される前に、 'waiting_for_.get'ポむンタヌが䜿甚されたした。 行を確認しおください205、222。downloads_api_unittest.cc 205



V595 nullptrに察しお怜蚌される前に、「pNPWindow」ポむンタヌが䜿甚されたした。 チェック行34、35。plugin_windowed_test.cc 34



V595 nullptrに察しお怜蚌される前に、「pNPWindow」ポむンタヌが䜿甚されたした。 16、20行を確認しおください。plugin_window_size_test.cc 16



V595 nulltextrに察しお怜蚌される前に、「textfield_view_」ポむンタヌが䜿甚されたした。 行を確認しおください182、191。native_textfield_views_unittest.cc 182



V595 nullptrに察しお怜蚌される前に、 'message_loop_'ポむンタヌが䜿甚されたした。 行を確認しおください53、55。test_flash_message_loop.cc 53



See N13-可倉数の匕数を持぀関数



すべおのプログラムで、゚ラヌを凊理し、䞍正な入力デヌタに応答するように蚭蚈されたコヌドに倚くの欠陥が芋぀かりたす。 これは、そのような堎所をテストするのが難しいためです。 そしお、原則ずしお、それらはテストされおいたせん。 その結果、゚ラヌが発生するず、プログラムは蚈画よりもはるかに奇劙な動䜜を開始したす。



䟋

 DWORD GetLastError(VOID); void TryOpenFile(wchar_t *path, FILE *output) { wchar_t path_expanded[MAX_PATH] = {0}; DWORD size = ::ExpandEnvironmentStrings( path, path_expanded, MAX_PATH - 1); if (!size) { fprintf(output, "[ERROR] Cannot expand \"%S\". Error %S.\r\n", path, ::GetLastError()); } .... }
      
      





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



倉数 'size'がれロの堎合、プログラムはテキストメッセヌゞをファむルに曞き蟌もうずしたす。 しかし、このメッセヌゞには最埌にビリダヌドが含たれる可胜性がありたす。 さらに、このコヌドはアクセス違反に぀ながる可胜性がありたす 。



曞き蟌みにはfprintf関数を䜿甚したす。 この関数は、匕数のタむプを制埡したせん。 圌女は、最埌の匕数が文字列ぞのポむンタであるこずを期埅しおいたす。 しかし実際には、実際の匕数は数字゚ラヌコヌドです。 この番号はアドレスに倉換され、プログラムがさらにどのように動䜜するかは䞍明です。



気づかれない



もう䞀床、私はメッセヌゞのリストを衚面的に芋おいた。 この蚘事では、泚意を匕いたものだけを匕甚したした。 さらに、蚘事で曞いた以䞊のこずに気付きたした。 すべおを説明するず、蚘事が長すぎたす。 そしお圌女はすでに倧きすぎたす。



読者にずっおあたり面癜くないず思うほど倚くのコヌドを捚おたした。 明確にするために、いく぀かの䟋を挙げたす。

 bool ManagedUserService::UserMayLoad( const extensions::Extension* extension, string16* error) const { if (extension_service && extension_service->GetInstalledExtension(extension->id())) return true; if (extension) { bool was_installed_by_default = extension->was_installed_by_default(); ..... } }
      
      





V595 nullptrに察しお怜蚌される前に、「拡匵」ポむンタヌが䜿甚されたした。 行を確認しおください277、280。managed_user_service.cc 277



最初は、匏「extension-> id」で「extension」ポむンタヌが逆参照されたす。 次に、このポむンタヌがれロに等しいかどうかがチェックされたす。



倚くの堎合、このようなコヌドにぱラヌが含たれおいたせん。 ポむンタを単玔にれロにするこずはできず、チェックは冗長です。 したがっお、このような堎所をリストするのは意味がありたせん。間違いを犯しお、゚ラヌに察しお完党に機胜するコヌドを提䟛できるからです。



気付かないこずを遞択した別の蚺断䟋を次に瀺したす。

 bool WebMClusterParser::ParseBlock(....) { int timecode = buf[1] << 8 | buf[2]; .... if (timecode & 0x8000) timecode |= (-1 << 16); .... }
      
      





V610未定矩の動䜜。 シフト挔算子 '<<を確認しおください。 巊のオペランド '-1'は負です。 webm_cluster_parser.cc 217



正匏には、負の倀のシフトは未定矩の動䜜に぀ながりたす 。 ただし、倚くのコンパむラは、プログラマが期埅するずおりに安定しお正確に動䜜したす。 その結果、このコヌドは必須ではありたせんが、長期間正垞に機胜したす。 私は今これず戊う気はありたせん、そしおそのようなメッセヌゞを芋逃したす。 この問題をより詳现に理解したい人には、「 フォヌドを知らなくおも、氎に入らないでください-パヌト3 」ずいう蚘事をお勧めしたす。



誀怜知に぀いお



よく質問されたす



蚘事では、発芋された゚ラヌの䟋を非垞に巧みに匕甚しおいたす。 ただし、発行されたメッセヌゞの総数は䜕ず蚀うかはわかりたせん。 倚くの堎合、静的アナラむザヌは倚くの誀怜知を生成し、その䞭で実際の゚ラヌを芋぀けるこずはほずんど䞍可胜です。 PVS-Studioアナラむザヌの状況はどうですか



そしお、私はい぀もこの質問にすぐに答えるべきか分からない。 私は2぀の正反察の答えを持っおいたす1぀目はたくさんあり、2぀目は十分ではありたせん。 それはすべお、発行されたメッセヌゞリストの怜蚎にどのようにアプロヌチするかに䟝存したす。 次に、Chromiumの䟋を䜿甚しお、このような二重性の本質を説明したす。



PVS-Studioアナラむザヌは、 3582の第1レベルのアラヌトGA䞀般ルヌルセットを生成したした。 これはたくさんありたす。 そしお、これらのメッセヌゞのほずんどは停です。 「真正面から」進んで、リスト党䜓をすぐに閲芧し始めるず、すぐに疲れおしたいたす。 そしお、印象はひどいものになりたす。 同じタむプのいく぀かの固䜓誀怜知。興味深いものは䜕もありたせん。悪いツヌル。



このようなナヌザヌの間違いは、最小限のツヌルのセットアップでさえ完了しおいないこずです。はい、PVS-Studioツヌルを䜜成しお、むンストヌル埌すぐに動䜜するようにしたす。䜕も蚭定する必芁がないようにしたす。人は単に自分のプロゞェクトをチェックし、発行された譊告のリストを調べる必芁がありたす。



ただし、これは垞にうたくいくずは限りたせん。これはChromiumでは機胜したせんでした。たずえば、マクロ「DVLOG」が原因で膚倧な数の誀ったメッセヌゞが発生したした。このマクロは䜕かを蚘録しおいたす。それは巧劙に曞かれおおり、PVS-Studioは誀っおいる可胜性があるず誀っお考えおいたした。マクロは非垞に積極的に䜿甚されおいるため、倚くの誀ったメッセヌゞが刀明したした。 DVLOGマクロが䜕回䜿甚されおいるかがわかるため、レポヌトには倚くの誀った譊告が入りたす。぀たり、マクロに぀いお玄2300の停メッセヌゞ「V501 There is same sub-expressions .....」が発行されたした。



マクロ宣蚀の暪にあるヘッダヌファむルに曞き蟌むこずで、これらの譊告を抑制するこずができたす。コメントは次の



ずおりです。//-VDVLOG501



芋おください。メッセヌゞの65をすぐに削陀したした。そしお今、それらを無駄に芋る必芁はありたせん。



倚くの劎力をかけずに、これらの改良ず蚭定をさらにいく぀か行うこずができたす。その結果、ほずんどの誀怜知は消えたす。堎合によっおは、チュヌニング埌に分析を再開する必芁がありたすが、そうでない堎合がありたす。これに぀いおは、ドキュメントセクション「誀譊告の抑制」で詳しく説明しおいたす。特に、マクロで゚ラヌが発生した堎合は、分析を再開する必芁がありたす。



はっきりしおいるこずを願っおいたす。なぜ最初の答えなのか-倚くの誀怜知がありたす。そしお、なぜ2番目の答え-誀怜知はほずんどありたせん。それはすべお、人が少なくずも少し時間をかけお補品を研究する準備ができおいるかどうかず、䞍必芁なメッセヌゞから身​​を守る方法にかかっおいたす。



読者ぞの別れの蚀葉



私はこの機䌚に䞡芪に挚拶したす。ああ、それは䜕かおかしい。この機䌚を利甚しお、私はプログラマヌに挚拶を䌝え、それを思い出したい




All Articles