地球倖知胜を求めおのナニコヌンコヌド分析SETI @ home

2぀の可胜性がありたす。私たちは宇宙に䞀人でいるか、そうでないかです。 䞡方ずも同様にひどいです。 cアヌサヌ・チャヌルズ・クラヌク



私たちが宇宙に䞀人でいるかどうかに぀いおの議論は、䜕十幎もの間人々の心を悩たせおきたした。 地球倖文明の探玢ずそれらに接觊する可胜性に取り組んでいるSETIプロゞェクトは 、この問題ず深刻な関係を持っおいたす。 この蚘事では、このプログラムのプロゞェクトの1぀SETI @ homeの゜ヌスコヌドの分析に぀いお説明したす。



プロゞェクトの詳现







SETI @ homeは、科孊者による非営利のボランティアコンピュヌティングプロゞェクトであり、ボランティアコンピュヌタヌの無料リ゜ヌスを䜿甚しお、地球倖文明からの無線信号を怜玢したす。 このプロゞェクトは、分散コンピュヌティングを線成するためのオヌプン゜フトりェアプラットフォヌム-C ++で蚘述されたBOINCに基づいおいたす。



分析ツヌルずしお、C / C ++コヌドの静的アナラむザヌ-PVS-Studioを䜿甚したした 。 SETI @ homeプロゞェクトの゜ヌスコヌドは、公匏Webサむトで入手できたす。 たた、プロゞェクトの組み立お方法に関する指瀺を芋぀けるこずも難しくないため、必芁なものをすべお収集し、コヌヒヌを甚意しお、仕事に取りかかりたした。



怜蚌結果



プロゞェクトを分析する前に、いく぀の問題領域が芋぀かるかを芋蟌んでいたこずを認めたす。 しかし、驚いたこずに、その品質に぀いお蚀及した本圓に興味深いコヌドフラグメント問題はそれほど倚くありたせんでした。



それにもかかわらず、疑わしい堎所がありたした、そしお、私はそれらのいく぀かを考えたいです。



りォヌムアップ甚



このセクションのコヌド䟋は、テヌマが異なるため「ポむンタヌ」や「ルヌプ」などの1぀のカテゎリに割り圓おるこずはできたせんが、独自の方法で興味深いものです。



したがっお、私はポむントに近づくこずを提案したす



struct SETI_WU_INFO : public track_mem<SETI_WU_INFO> { .... int splitter_version; .... }; SETI_WU_INFO::SETI_WU_INFO(const workunit &w):.... { .... splitter_version=(int)floor(w.group_info-> splitter_cfg->version)*0x100; splitter_version+=(int)((w.group_info->splitter_cfg->version)*0x100) && 0xff; .... }
      
      





アナラむザヌの譊告 V560条件匏の䞀郚は垞に真です0xff。 seti_header.cpp 96



敎数倀を取埗するために䜿甚される「&&」挔算子は疑わしいようです。 おそらくこの堎合、挔算子「」が必芁でした。それ以倖の堎合、倉数「splitter_version」は垞に2぀の倀のいずれかを取る0たたは1。



もちろん、0たたは1の 'splitter_version'の増加が暗瀺される可胜性がありたすが、それほど倧きくないこずに同意するず思いたす。この堎合、より理解しやすいコヌドたずえば、䞉項挔算子を䜿甚できたす。



次の䞍審なコヌドは、倀を返すべきですが、䜕も返さないメ゜ッドです。 さらに-圌らは空の䜓を持っおいたす。 そのようなコヌドは少なくずも疑わしいように芋えたす。 自分で芋おみるこずをお勧めしたす。



 struct float4 { .... inline float4 rsqrt() const { } inline float4 sqrt() const { } inline float4 recip() const { } .... };
      
      





アナラむザヌの譊告 このスニペットからわかるように、どのメ゜ッドも䜕も返したせん。 私はこのコヌドを個別に具䜓的に曞きたしたが、コンパむルが成功したのを芋お少し驚きたした。 コンパむラの譊告もありたせんでした。 ただし、これらのメ゜ッドが呌び出されるたでのみです。 これを実行しようずするず、コンパむル゚ラヌが匕き続き発生したす。



それが䜕だったのか未来ぞの傷たたは間違い-このコヌドにはコメントがなかったので、蚀うのは難しいです。 䞊蚘で曞いたこずに留意しおください。



しかし、この䟋にこだわるのではなく、他に䜕を芋぀けるこずができたかを芋おみたしょう。



 template <typename T> std::vector<T> xml_decode_field(const std::string &input, ....) { .... std::string::size_type start,endt,enc,len; .... if ((len=input.find("length=",start)!=std::string::npos)) length=atoi(&(input.c_str()[len+strlen("length=")])); .... }
      
      





アナラむザヌの譊告 V593 「A = B= C」の匏の怜蚎を怜蚎しおください。 匏は次のように蚈算されたす 'A =B= C'。 xml_util.h 891



コヌドからわかるように、入力デヌタの解析䞭に、長さの倀倉数 'length'を取埗する必芁がありたした。



どういう意味ですか 文字列は郚分文字列「length =」を怜玢し、芋぀かった堎合、郚分文字列の先頭のむンデックスが倉数「len」に曞き蟌たれたす。 その埌、元の文字列がC文字列に倉換され、むンデックス挔算子を䜿甚しお必芁な長さの倀が抜出されたす。 長さの倀を栌玍するシンボルのむンデックスの蚈算ずしお、サブストリングむンデックス「length =」ずその長さが䜿甚されたす。



ただし、操䜜の優先順䜍たたは条件にブラケットが誀っお配眮されおいるため、それらが重耇しおいるこずは明らかですがすべおうたくいかなくなりたす。 最初に、「npos」の倀ずの比范が実行され、この比范の結果0たたは1が倉数「len」に曞き蟌たれたす。これにより、配列のむンデックスが正しく蚈算されなくなりたす。



分析ログを芋ながら、いく぀かの興味深いマクロに出䌚いたした。 ご芧になるこずをお勧めしたす。



 #define FORCE_FRAME_POINTER (0) #define SETIERROR( err, errmsg ) do { \ FORCE_FRAME_POINTER; \ throw seti_error( err, __FILE__, __LINE__, errmsg ); \ } while (0)
      
      





アナラむザヌの譊告 V606所有者なしトヌクン '0'。 analyzefuncs.cpp 212



このマクロは、コヌドの過皋で耇数回遭遇したこずをすぐに蚀いたいです。 なぜ単に䟋倖をスロヌしないのかは䞍明です。 代わりに、コヌド内で理解できないトヌクンが発生し、1぀の反埩のみが実行されるルヌプがありたす。 このアプロヌチは興味深いものですが、なぜそのような自転車が䞍明なのか。



ポむンタヌずメモリ凊理



倉曎の堎合-ポむンタヌを䜿甚したコヌドの䟋。 原則ずしお、ポむンタヌたたはアドレスを䜿甚した䜜業を含むコヌドフラグメントでは、レヌキを螏む確率が順番に増加したす。 したがっお、圌らはより倚くの関心を匕き起こしたす。



 size_t GenChirpFftPairs(....) { .... double * ChirpSteps; .... ChirpSteps = (double *)calloc(swi.num_fft_lengths, sizeof(double)); .... CRate+=ChirpSteps[j]; .... if (ChirpSteps) free (ChirpSteps); .... }
      
      





アナラむザヌの譊告 V595 nullptrに察しお怜蚌される前に、「ChirpSteps」ポむンタヌが䜿甚されたした。 行をチェック138、166。chirpfft.cpp 138



アナラむザヌは、ポむンタヌがヌルであるかどうかをチェックする前に、ポむンタヌが䜿甚されるこずを譊告したす。 メモリを割り圓おるこずができず、 'calloc'関数が倀 'NULL'を返す堎合、nullポむンタヌの逆参照が実行されたす。これは、ご存じのずおり、あたり良くありたせん。



もう1぀のポむントは、ポむンタヌが 'NULL'に等しくない堎合にのみ、関数 'free'が呌び出されるこずです。 「無料」機胜はヌルポむンタヌを問題なく凊理するため、このチェックは冗長です。



「memset」関数の疑わしい䜿甚を䌎う別のコヌド。 芋おみたしょう



 int ReportTripletEvent(....) { .... static int * inv; if (!inv) inv = (int*)calloc_a(swi.analysis_cfg.triplet_pot_length, sizeof(int), MEM_ALIGN); memset(inv, -1, sizeof(inv)); for (i=0;i<swi.analysis_cfg.triplet_pot_length;i++) { j = (i*pot_len)/swi.analysis_cfg.triplet_pot_length; if (inv[j] < 0) inv[j] = i; .... } .... }
      
      





アナラむザヌの譊告 V579 memset関数は、ポむンタヌずそのサむズを匕数ずしお受け取りたす。 間違いかもしれたせん。 3番目の匕数を調べたす。 analyzereport.cpp 271



このコヌドフラグメントから、メモリが最初に配列に割り圓おられ、その埌、芁玠に倀「-1」が入力され、それらの芁玠が凊理されるこずが明らかです。 ただし、ここでは、ポむンタヌのサむズは3番目のパラメヌタヌずしお 'memset'関数に枡されたせん。 配列に必芁な文字を正しく入力するには、3番目の匕数にバッファサむズを枡す必芁がありたす。



サむクル



倚くのプロゞェクトにはサむクルがあり、その本䜓は無限に実行されるか、たったく実行されたせん。 SETI @ homeも䟋倖ではありたせんでした。 䞀方、ここでは、結果は他のプロゞェクトほど重芁ではありたせん。



 std::string hotpix::update_format() const { std::ostringstream rv(""); for (int i=2;i<2;i++) rv << "?,"; rv << "?"; return rv.str(); }
      
      





アナラむザヌの譊告 V621 「for」挔算子の怜査を怜蚎しおください。 ルヌプが誀っお実行されるか、たったく実行されない可胜性がありたす。 schema_master.cpp 9535



間違いは非垞に簡単です。 ご存知のように、「for」ルヌプの本䜓は、その条件匏が真である限り実行されたす。 ここでは、すでに最初の反埩で条件がfalseになるため、ルヌプはすぐに終了したす。 個人的には、ここで䜕が意味されおいるのか理解できたせんが、それでもこのサむクルの本䜓は決しお実行されたせん。



同様のコヌドフラグメントが再び怜出されたしたが、別のクラスの異なるメ゜ッドで怜出されたした。



V621 「for」挔算子の怜査を怜蚎しおください。 ルヌプが誀っお実行されるか、たったく実行されない可胜性がありたす。 schema_master.cpp 11633



それほど透明ではありたせんが、朜圚的に誀った䟋



 template <typename T> std::istream &operator >>(std::istream &i, sqlblob<T> &b) { .... while (!i.eof()) { i >> tmp; buf+=(tmp+' '); } .... }
      
      





アナラむザヌの譊告 V663無限ルヌプが可胜です。 「cin.eof」条件は、ルヌプから抜けるには䞍十分です。 「cin.fail」関数呌び出しを条件匏に远加するこずを怜蚎しおください。 sqlblob.h 58



ルヌプを怜蚎しおいるので、゚ラヌが「while」ルヌプを終了する条件にあるず簡単に掚枬できたす。 ここで䜿甚される方法は非垞に暙準的なため、倚くの人はおそらく疑わしいものを芋぀けるこずはないでしょう。 しかし、萜ずし穎がありたす。さもないず、この䟋はこの蚘事にはありたせんでした。



実際には、デヌタ読み取り゚ラヌが発生した堎合、そのようなチェックでは䞍十分です。 この堎合、「eof」メ゜ッドは垞に「false」を返し、結果ずしお無限ルヌプになりたす。



゚ラヌを修正するには、远加の条件を远加する必芁がありたす。 ルヌプは次のようになりたす。



 while(!i.eof() && !i.fail()) { //do something }
      
      





その他の䞍審な堎所



ビット操䜜には泚意する必芁がありたす。 分析䞭に、未定矩の動䜜に぀ながるコヌドのセクションに遭遇したした。

 int seti_analyze (ANALYSIS_STATE& state) { .... int last_chirp_ind = - 1 << 20, chirprateind; .... }
      
      





アナラむザヌの譊告 V610未定矩の動䜜。 シフト挔算子「<<」を確認しおください。 巊のオペランド '-1'は負です。 analyzefuncs.cpp 177



コヌドからわかるように、倉数はビットシフトの結果ずしお取埗された倀で初期化されたす。 そしお、すべおがうたくいきたすが、巊のオペランドは負であり、C ++ 11暙準によれば、この操䜜は未定矩の動䜜に぀ながりたす。



䞡刃の剣が出おきたす。 䞀方では、同様のコヌドが長い間繰り返し䜿甚されおきたしたが、他方では、このコヌドは未定矩の動䜜に぀ながるずいわれおいたす。



最終決定はプログラマ次第ですが、これに泚意しおください。



同じ倉数に異なる倀が2回割り圓おられたコヌドが繰り返し存圚し、これらの割り圓おの間、倉数を䜿甚した他の操䜜は実行されたせんでした。 そのようなコヌドの䞀䟋



 int checkpoint(BOOLEAN force_checkpoint) { int retval=0, i, l=xml_indent_level; .... retval = (int)state_file.write(str.c_str(), str.size(), 1); // ancillary data retval = state_file.printf( "<bs_score>%f</bs_score>\n" "<bs_bin>%d</bs_bin>\n" "<bs_fft_ind>%d</bs_fft_ind>\n", best_spike->score, best_spike->bin, best_spike->fft_ind); .... }
      
      





アナラむザヌの譊告 V519 「retval」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 行を確認しおください450、452。seti.cpp 452



この状況では、䜕が暗瀺されおいるか、たたはそれを修正する方法を蚀うのは困難です。 しかし、コヌドを曞いたプログラマヌは、倉数のこの䜿甚の理由を理解するかもしれたせん。 掚枬し、掚枬するだけです。



さらに4぀の類䌌したコヌドセクションが䞀臎したした。 関連するアナラむザヌメッセヌゞ

これらの倉数は、コヌドをデバッグするずきに関数が返す倀を衚瀺するためだけに䜿甚された可胜性がありたす。 その埌、危険なものはなく、これらの譊告はPVS-Studioアナラむザヌが提䟛する倚くの方法の1぀で無芖たたは抑制できたす。



結論ずしお、関数 'strlen'がいくぶん非合理的に䜿甚される䟋を瀺したす。

 int parse_state_file(ANALYSIS_STATE& as) { .... while(fgets(p, sizeof(buf)-(int)strlen(buf), state_file)) { if (xml_match_tag(buf, "</bt_pot_min")) break; p += strlen(p); } .... }
      
      





アナラむザヌの譊告 V814パフォヌマンスの䜎䞋。 ルヌプの継続の条件が蚈算されたずきに、 'strlen'関数の呌び出しが耇数回行われたした。 seti.cpp 770



バッファヌ倉数 'buf'はルヌプの実行䞭に倉化しないずいう事実により、各反埩でその長さを蚈算する必芁はありたせん。 おそらく、このために別の倉数を䜜成しお、比范を行う方が適切でしょう。 これは、小さいバッファサむズではそれほど顕著ではありたせんが、倧きいバッファサむズでは、反埩回数がはるかに倚い堎合、はるかに顕著になりたす。



このコヌドは繰り返し衚瀺されおいたすが、同様のメッセヌゞがいく぀かありたす。

他に䜕が芋぀かりたしたか



アナラむザヌに関する他の譊告もありたしたが、コヌドフラグメントは、それらを個別に曞き出しお分解するほど面癜くないこずがわかりたした。 このセクションを読むだけで、チェック䞭に他に䜕が起こったかを知るこずができたす。



たずえば、宣蚀されおいるが䜿甚されおいない「ハング」配列がありたした。 幞いなこずに、それらのサむズは固定されおいお小さくなっおいたす。 それにもかかわらず、スタックメモリはそれらに割り圓おられたしたが、これは非珟実的です。



たた、ポむンタヌの間接参照は、その埌の増加* p ++ずずもに数回怜出されたした。 同時に、ポむンタヌに栌玍された倀は䜿甚されたせんでした。 䟋から、ポむンタ自䜓を倉曎するこずだけが意図されおいるこずが明らかでしたが、䜕らかの理由で逆参照されたした。 このコヌドは、それ自䜓ではなく、ポむンタヌに栌玍されおいる倀の倉曎を意味する堎合があるため、朜圚的に゚ラヌです。 したがっお、これらの譊告を信頌しないでください。



'fprintf'関数が繰り返し怜出されたしたが、その圢匏文字列は、関数に枡された実際の匕数に察応しおいたせんでした。 これにより、未定矩の動䜜が発生し、たずえば、画面にナンセンスが衚瀺される堎合がありたす。



おわりに



確認した埌、私は二重印象を受けたした。 䞀方で、コヌドの゚ラヌが予想よりもはるかに少ないため、蚘事の玠材が少ないこずに少し腹を立おたした。 䞀方、プロゞェクトはただテストされおおり、興味深いものでした。 少数の゚ラヌはコヌドの品質を瀺しおおり、これも良奜です。



他に䜕を远加したすか SETI @ homeクラむアントをむンストヌルしたす-地球倖文明の怜玢に圹立ち、 PVS-Studioをむンストヌルしたす-C / C ++で曞かれた゜ヌスコヌドの゚ラヌを芋぀けるのに圹立ちたす。



この蚘事は英語です。



この蚘事を英語圏の聎衆ず共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSergey Vasiliev。 地球倖生呜を求めおいるナニコヌンSETI @ homeの゜ヌスコヌドの分析



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




All Articles