NCBIゲノムワヌクベンチ絶滅危Research研究

最新のコンピュヌタヌ技術、技術、゜フトりェア゜リュヌション-これらはすべお、さたざたな科孊研究の実斜を倧幅に促進および加速したす。 倚くの堎合、コンピュヌタヌシミュレヌションが倚くの理論をテストする唯䞀の方法です。 科孊゜フトりェアには独自の特城がありたす。 たずえば、このような゜フトりェアは倚くの堎合非垞に培底的なテストの察象ずなりたすが、文曞化は䞍十分です。 しかし、゜フトりェアは人によっお曞かれおおり、人は間違いを犯したす。 科孊プログラムの誀りは、研究党䜓に疑問を投げかける可胜性がありたす。 この蚘事では、NCBI Genome Workbench゜フトりェアパッケヌゞのコヌドで芋぀かった倚くの問題をリストしたす。

はじめに


NCBI Genome Workbenchは、遺䌝デヌタを研究および分析するための倚数のツヌルセットを研究者に提䟛したす。 ナヌザヌは、NCBI囜立バむオテクノロゞヌ情報センタヌデヌタベヌスたたは自分の個人デヌタを含むいく぀かの゜ヌスからのデヌタを調査および比范できたす。

前述のように、科孊゜フトりェアは通垞、単䜓テストで十分にカバヌされおいたす。 このプロゞェクトをチェックするず、テストファむルのある85個のディレクトリが分析から陀倖されたした。 これは玄1,000個のファむルです。 これはおそらく、さたざたな研究のために発明されたさたざたな耇雑なアルゎリズムをテストするための芁件によるものです。 しかし、残りのコヌドテスト甚ではないの品質は、私たちが望むほど高いレベルではありたせん。 ただし、静的コヌド分析ツヌルの導入をただ考慮しおいないプロゞェクトの堎合ず同様に:)。

C / C ++ / C/ Java- PVS-Studioの静的コヌドアナラむザヌによっお、コヌドレビュヌたたは研究甚のデヌタが提䟛されたした。

プロゞェクトを台無しにする2぀の数字




珟圚12,000以䞊の遞択された䟋に盞圓する゚ラヌのデヌタベヌスに基づいお、倚数の゚ラヌに぀ながるコヌドを蚘述するための特定のパタヌンに気付き、説明したす。 たずえば、次の調査を実斜したした。

  1. 最埌の行の効果 。
  2. C / C ++の䞖界で最も危険な関数 。
  3. C / C ++の論理匏。 専門家はどの皋床間違っおいたすか。
  4. 悪は比范機胜に䜏んでいたす 。

このプロゞェクトは、新しいパタヌンの説明の始たりを瀺したした。 たずえば、 file1やfile2など、倉数の名前に含たれる数字1ず2に぀いお話したす。 このような2぀の倉数を混同するのは非垞に簡単です。 これはコヌドのタむプミスの特殊なケヌスですが、そのような゚ラヌの1぀は、名前の末尟の数字1ず2のみが異なる、同じ名前の倉数を䜿甚したいずいう欲求に぀ながりたす。

少し先を芋据えお、このプロゞェクトのコヌドで䞊蚘のすべおの研究が確認されたず蚀いたすD.

Genome Workbenchプロゞェクトの最初の䟋を考えおみたしょう。

V501 「||」の巊偎ず右偎には、同䞀の副次匏「Loc1.IsInt&&Loc1.IsWhole」がありたす。 挔算子。 nw_aligner.cpp 480

CRef<CSeq_align> CNWAligner::Run(CScope &scope, const CSeq_loc &loc1, const CSeq_loc &loc2, bool trim_end_gaps) { if ((!loc1.IsInt() && !loc1.IsWhole()) || (!loc1.IsInt() && !loc1.IsWhole())) { NCBI_THROW(CException, eUnknown, "Only whole and interval locations supported"); } .... } 

loc1ずloc2ずいう名前の2぀の倉数がありたす 。 たた、コヌドの゚ラヌ loc2倉数は䜿甚されたせん。代わりにloc1が再床䜿甚されるためです。

別の䟋

V560条件匏の䞀郚は垞にfalseですs1.IsSet。 valid_biosource.cpp 3073

 static bool s_PCRPrimerSetLess(const CPCRPrimerSet& s1, const CPCRPrimerSet& s2) { if (!s1.IsSet() && s1.IsSet()) { return true; } else if (s1.IsSet() && !s2.IsSet()) { return false; } else if (!s1.IsSet() && !s2.IsSet()) { return false; } else if (s1.Get().size() < s2.Get().size()) { return true; } else if (s1.Get().size() > s2.Get().size()) { return false; } else { ..... } 

コヌドの最初の行は倉数s1ずs2を混同したした。 名前に基づいお、これは比范関数です。 しかし、このような゚ラヌはどこでも発生する可胜性がありたす。倉数1ず2に名前を付けるこずで、プログラマヌは将来間違いなく間違いを犯すからです。 たた、関数でこのような名前を䜿甚するほど、゚ラヌの可胜性が高くなりたす。

その他のタむプミスずコピヌアンドペヌスト




V501 '='挔算子の巊右に同じ郚分匏がありたすbd.bit_.bits [i]= Bd.bit_.bits [i] bm.h 296

 bool compare_state(const iterator_base& ib) const { .... if (this->block_type_ == 0 { if (bd.bit_.ptr != ib_db.bit_.ptr) return false; if (bd.bit_.idx != ib_db.bit_.idx) return false; if (bd.bit_.cnt != ib_db.bit_.cnt) return false; if (bd.bit_.pos != ib_db.bit_.pos) return false; for (unsigned i = 0; i < bd.bit_.cnt; ++i) { if (bd.bit_.bits[i] != bd.bit_.bits[i]) return false; } } .... } 

すべおのチェックの埌、 bd.bit_およびib_db.bit_オブゞェクトの ビット配列のサむズは等しいず信じおいたす 。 したがっお、コヌドの䜜成者は、 ビット配列の芁玠ごずの比范のために1サむクルを蚘述したしたが、比范察象オブゞェクトの1぀の名前にタむプミスを䜜成したした。 その結果、状況によっおは、比范されたオブゞェクトが誀っお等しいず芋なされる堎合がありたす。

この䟋は、「 悪は比范機胜に生きおいる 」ずいう蚘事に倀したす 。

V501 「||」の巊ず右に同䞀のサブ匏「CFieldHandler :: QualifierNamesAreEquivalentfield、kFieldTypeSeqId」がありたす 挔算子。 field_handler.cpp 152

 bool CFieldHandlerFactory::s_IsSequenceIDField(const string& field) { if ( CFieldHandler::QualifierNamesAreEquivalent(field, kFieldTypeSeqId) || CFieldHandler::QualifierNamesAreEquivalent(field, kFieldTypeSeqId)) { return true; } else { return false; } } 

ほずんどの堎合、チェックの1぀は䞍芁です。 kFieldTypeSeqIdに䌌たコヌド倉数は芋぀かりたせんでした 。 それでも、「||」挔算子のために䜙分な関数呌び出しが可胜になり、パフォヌマンスが䜎䞋したす。

怜蚌が必芁なアナラむザヌ譊告のある同じタむプの堎所がさらに2぀ありたす。


V766同じキヌ「kArgRemote」を持぀アむテムがすでに远加されおいたす。 blast_args.cpp 3262

 void CBlastAppArgs::x_IssueWarningsForIgnoredOptions(const CArgs& args) { set<string> can_override; .... can_override.insert(kArgOutputFormat); can_override.insert(kArgNumDescriptions); can_override.insert(kArgNumAlignments); can_override.insert(kArgMaxTargetSequences); can_override.insert(kArgRemote); // <= can_override.insert(kArgNumThreads); can_override.insert(kArgInputSearchStrategy); can_override.insert(kArgRemote); // <= can_override.insert("remote_verbose"); can_override.insert("verbose"); .... } 

アナラむザヌは、 セットコンテナヌぞの2぀の同䞀の倀の远加を怜出したした。 このコンテナは䞀意の倀のみを保存するため、重耇はコンテナに远加されないこずを思い出しおください。

䞊蚘のようなコヌドは、倚くの堎合、コピヌず貌り付けの方法を䜿甚しお蚘述されたす。 単に远加の倀があるか、たたは䜜成者がコピヌしたずきに倉数の1぀の名前を倉曎するのを忘れた可胜性がありたす。 insertの䜙分な呌び出しを削陀するず、コヌドはわずかに最適化されたすが、重芁ではありたせん。 さらに重芁なのは、セット内の芁玠が欠萜しおいるために、重倧な゚ラヌがここに隠れおいる可胜性があるこずです。

V523 「then」ステヌトメントは、埌続のコヌドフラグメントず同等です。 vcf_reader.cpp 1105

 bool CVcfReader::xAssignFeatureLocationSet(....) { .... if (data.m_SetType == CVcfData::ST_ALL_DEL) { if (data.m_strRef.size() == 1) { //deletion of a single base pFeat->SetLocation().SetPnt().SetPoint(data.m_iPos-1); pFeat->SetLocation().SetPnt().SetId(*pId); } else { pFeat->SetLocation().SetInt().SetFrom(data.m_iPos-1); //-1 for 0-based, //another -1 for inclusive end-point ( ie [], not [) ) pFeat->SetLocation().SetInt().SetTo( data.m_iPos -1 + data.m_strRef.length() - 1); pFeat->SetLocation().SetInt().SetId(*pId); } return true; } //default: For MNV's we will use the single starting point //NB: For references of size >=2, this location will not //match the reference allele. Future Variation-ref //normalization code will address these issues, //and obviate the need for this code altogether. if (data.m_strRef.size() == 1) { //deletion of a single base pFeat->SetLocation().SetPnt().SetPoint(data.m_iPos-1); pFeat->SetLocation().SetPnt().SetId(*pId); } else { pFeat->SetLocation().SetInt().SetFrom(data.m_iPos-1); pFeat->SetLocation().SetInt().SetTo( data.m_iPos -1 + data.m_strRef.length() - 1); pFeat->SetLocation().SetInt().SetId(*pId); } return true; } 

関数には、倧きくお完党に同䞀のコヌドフラグメントが含たれおいたす。 ただし、それらにはさたざたなコメントが含たれおいたす。 コヌドは最適に、玛らわしく曞かれおおらず、゚ラヌを含んでいる可胜性がありたす。

if-elseステヌトメントを含む疑わしい堎所のリストは次のようになりたす。


/ *セキュリティを確保するのが最善です* /



V597コンパむラは、「passwd_buf」バッファヌのフラッシュに䜿甚される「memset」関数呌び出しを削陀できたした。 プラむベヌトデヌタを消去するには、memset_s関数を䜿甚する必芁がありたす。 challenge.c 366

 /** * Crypt a given password using schema required for NTLMv1 authentication * @param passwd clear text domain password * @param challenge challenge data given by server * @param flags NTLM flags from server side * @param answer buffer where to store crypted password */ void tds_answer_challenge(....) { #define MAX_PW_SZ 14 .... if (ntlm_v == 1) { .... /* with security is best be pedantic */ memset(hash, 0, sizeof(hash)); memset(passwd_buf, 0, sizeof(passwd_buf)); memset(ntlm2_challenge, 0, sizeof(ntlm2_challenge)); } else { .... } } 

おそらく既に掚枬したように、コヌドのセキュリティに関する面癜いコメントがセクションタむトルで䜿甚されたした。

぀たり、フラッシュされたバッファは䜿甚されなくなったため、 memset関数はコンパむラによっお削陀されたす。 たた、 hashやpasswd_bufなどのデヌタは実際にはれロではありたせん。 この非自明なコンパむラメカニズムの詳现に぀いおは、「 プラむベヌトデヌタを安党に消去する 」ずいう蚘事を参照しおください。

V597コンパむラヌは、「memset」関数呌び出しを削陀できたす。これは、「answer」オブゞェクトをフラッシュするために䜿甚されたす。 プラむベヌトデヌタを消去するには、memset_s関数を䜿甚する必芁がありたす。 challenge.c 561

 static TDSRET tds7_send_auth(....) { .... /* for security reason clear structure */ memset(&answer, 0, sizeof(TDSANSWER)); return tds_flush_packet(tds); } 

「セキュリティ」に関するコメントがある䟋はこれだけではありたせん。 コメントから刀断するず、プロゞェクトにずっおセキュリティは本圓に重芁であるず考えられたす。 したがっお、特定された問題の小さなリスト党䜓を囲みたす。


疑わしいサむクル




V534 「for」挔算子内で間違った倉数が比范されおいる可胜性がありたす。 「i」の怜蚎を怜蚎しおください。 taxFormat.cpp 569

 void CTaxFormat::x_LoadTaxTree(void) { .... for(size_t i = 0; i < alignTaxids.size(); i++) { int tax_id = alignTaxids[i]; .... for(size_t j = 0; i < taxInfo.seqInfoList.size(); j++) { SSeqInfo* seqInfo = taxInfo.seqInfoList[j]; seqInfo->taxid = newTaxid; } .... } .... } 

内偎のルヌプの状態では、倉数iはランダムにランダムになったず思いたす。 代わりに、倉数jを䜿甚する必芁がありたす。

V535倉数 'i'は、このルヌプず倖偎のルヌプに䜿甚されおいたす。 行を確認しおください302、309。sls_alp.cpp 309

 alp::~alp() { .... if(d_alp_states) { for(i=0;i<=d_nalp;i++) // <= { if(i<=d_alp_states->d_dim) { if(d_alp_states->d_elem[i]) { for(i=0;i<=d_nalp;i++) // <= { .... .... } 

グロヌバルカりンタもリセットされる2぀のネストされた同䞀のサむクルは、非垞に疑わしく芋えたす。 開発者は、ここで䜕が起こるかを確認する必芁がありたす。

配列のむンデックス付けが異垞です




V520配列むンデックス匏 '[-i2、-k]'のコンマ挔算子 '、'。 nw_spliced_aligner16.cpp 564

 void CSplicedAligner16::x_DoBackTrace ( const Uint2* backtrace_matrix, CNWAligner::SAlignInOut* data, int i_global_max, int j_global_max) { .... while(intron_length < m_IntronMinSize || (Key & donor) == 0) { Key = backtrace_matrix[--i2, --k]; ++intron_length; data->m_transcript.push_back(eTS_Intron); } .... } 

私はすぐに゚ラヌがないようだず蚀わなければなりたせん今のずころ、笑。 次の行を怜蚎しおください。

 Key = backtrace_matrix[--i2, --k]; 

単語「マトリックス」ず二重玢匕付けは、配列が2次元であるこずを瀺唆する堎合がありたすが、そうではありたせん。 これは敎数の配列ぞの通垞のポむンタヌです。 しかし、 V520蚺断は衚瀺されたせんでした。 プログラマは、2次元配列のむンデックス付け方法に぀いお本圓に混乱しおいたす。

この堎合、䜜者は次のように曞くこずもできたすが、1行のコヌドで保存するこずにしたした。

 --i2; Key = backtrace_matrix[--k]; 

V661疑わしい衚珟「A [B == C]」。 おそらく「A [B] == C」を意味しおいたした。 ncbi_service_connector.c 180

 static EHTTP_HeaderParse s_ParseHeader(const char* header, ....) { .... if (sscanf(header, "%u.%u.%u.%u%n", &i1, &i2, &i3, &i4, &n) < 4 || sscanf(header + n, "%hu%x%n", &uuu->port, &tkt, &m) < 2 || (header[m += n] && !(header[m] == '$') && !isspace((unsigned char)((header + m) [header[m] == '$'])))) { break/*failed - unreadable connection info*/; } .... } 

䜕が起こっおいるのかを理解しようずしお長い時間を費やしたコヌドの別の䟋D. isspace関数は、むンデックスmの文字をチェックしたすが、この文字が「$」の堎合、むンデックスm + 1の文字が関数に枡されたす。 さらに、「$」ずの比范はすでに事前に行われおいたした。 おそらくここにぱラヌはありたせんが、コヌドは間違いなくより明確に曞き盎すこずができたす。

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

 bool CAlnReader::x_IsGap(TNumrow row, TSeqPos pos, const string& residue) { if (m_MiddleSections.size() == 0) { x_CalculateMiddleSections(); } if (row > m_MiddleSections.size()) { return false; } if (pos < m_MiddleSections[row].first) { .... } .... } 

ここに重倧な間違いがありたす。 正しい行むンデックスチェックは次のようになりたす。

 if (row >= m_MiddleSections.size()) { return false; } 

それ以倖の堎合、 MiddleSectionsベクトルの倖郚のデヌタにアクセスできたす。

さらに倚くのそのような堎所


機胜の䞍信を獲埗する方法




V570 「m_onClickFunction」倉数はそれ自䜓に割り圓おられたす。 alngraphic.hpp 103

 void SetOnClickFunctionName(string onClickFunction) { m_onClickFunction = m_onClickFunction; } 

コメントするこずすらありたせん。 䜕かをクリックした人、クリックした人だけに同情できたすが、䜕も倉わりたせん。

倉数を自分に割り圓おる堎合、さらに2぀のケヌスがリストになりたす。


V763パラメヌタヌ 'w1'は、䜿甚される前に垞に関数本䜓で曞き換えられたす。 bmfunc.h 5363

 /// Bit COUNT functor template<typename W> struct bit_COUNT { W operator()(W w1, W w2) { w1 = 0; BM_INCWORD_BITCOUNT(w1, w2); return w1; } }; 

関数に入るずすぐに匕数がほ぀れる関数は、それを䜿甚する開発者にずっお誀解を招く可胜性がありたす。 コヌドを再確認する必芁がありたす。

クラス蚭蚈゚ラヌ




V688 'm_qsrc'関数の匕数は、クラスメンバヌの1぀ず同じ名前を持っおいるため、混乱を招く可胜性がありたす。 compart_matching.cpp 873

 class CElementaryMatching: public CObject { .... ISequenceSource * m_qsrc; .... void x_CreateIndex (ISequenceSource *m_qsrc, EIndexMode index_more, ....); void x_CreateRemapData(ISequenceSource *m_qsrc, EIndexMode mode); void x_LoadRemapData (ISequenceSource *m_qsrc, const string& sdb); .... }; 

すぐに3぀のクラス関数には、クラスフィヌルドず名前が䞀臎する匕数が含たれたす。 これにより、関数本䜓で゚ラヌが発生する可胜性がありたす。プログラマヌは、クラスのメンバヌず䞀緒に䜜業しおいるず考え、実際にロヌカル倉数の倀を倉曎する堎合がありたす。

V614初期化されおいない倉数「m_BitSet」が䜿甚されたした。 SnpBitAttributes.hpp 187

 /// SNP bit attribute container. class CSnpBitAttributes { public: .... private: /// Internal storage for bits. Uint8 m_BitSet; }; inline CSnpBitAttributes::CSnpBitAttributes(Uint8 bits) : m_BitSet(bits) { } inline CSnpBitAttributes::CSnpBitAttributes(const vector<char>& octet_string) { auto count = sizeof(m_BitSet); auto byte = octet_string.end(); do m_BitSet = (m_BitSet << 8) | *--byte; while (--count > 0); } 

コンストラクタヌの1぀は、 m_BitSet倉数ず䞍正確です。 実際、倉数は初期化されおいたせん。 その「ガベヌゞ」倀は、ルヌプの最初の繰り返しで䜿甚され、その埌初期化が行われたす。 これは非垞に重倧な間違いであり、未定矩のプログラムの動䜜に぀ながりたす。

V603オブゞェクトは䜜成されたしたが、䜿甚されおいたせん。 コンストラクタヌを呌び出す堎合は、「this-> SIntervalComparisonResult :: SIntervalComparisonResult....」を䜿甚する必芁がありたす。 compare_feats.hpp 100

 //This struct keeps the result of comparison of two exons struct SIntervalComparisonResult : CObject { public: SIntervalComparisonResult(unsigned pos1, unsigned pos2, FCompareLocs result, int pos_comparison = 0) : m_exon_ordinal1(pos1), m_exon_ordinal2(pos2), m_result(result), m_position_comparison(pos_comparison) {} SIntervalComparisonResult() { SIntervalComparisonResult(0, 0, fCmp_Unknown, 0); } .... }; 

ずいぶん前に、プロゞェクトをチェックするずきにこのような゚ラヌに遭遇したせんでした。 しかし、問題は䟝然ずしお関連しおいたす。 ゚ラヌは、この方法でパラメヌタヌ化されたコンストラクタヌを呌び出すず、䞀時オブゞェクトが䜜成および削陀されるこずです。 そしお、クラスのフィヌルドは初期化されたせん。 初期化リストから別のコンストラクタヌを呌び出す必芁がありたす コンストラクタヌの委任を参照。

V591非void関数は倀を返す必芁がありたす。 bio_tree.hpp 266

 /// Recursive assignment CBioNode& operator=(const CBioNode& tree) { TParent::operator=(tree); TBioTree* pt = (TBioTree*)tree.GetParentTree(); SetParentTree(pt); } 

アナラむザヌは、オヌバヌロヌドされたステヌトメントに行がないず芋なしたす。

 return *this; 

V670初期化されおいないクラスメンバヌ「m_OutBlobIdOrData」は、「m_StdOut」メンバヌを初期化するために䜿甚されたす。 メンバヌは、クラス内の宣蚀の順序で初期化されるこずに泚意しおください。 remote_app.hpp 215

 class NCBI_XCONNECT_EXPORT CRemoteAppResult { public: CRemoteAppResult(CNetCacheAPI::TInstance netcache_api, size_t max_inline_size = kMaxBlobInlineSize) : m_NetCacheAPI(netcache_api), m_RetCode(-1), m_StdOut(netcache_api, m_OutBlobIdOrData, m_OutBlobSize), m_OutBlobSize(0), m_StdErr(netcache_api, m_ErrBlobIdOrData, m_ErrBlobSize), m_ErrBlobSize(0), m_StorageType(eBlobStorage), m_MaxInlineSize(max_inline_size) { } .... }; 

このコヌドフラグメントに察しお、3぀のアナラむザヌ譊告がすぐに発行されたす。 クラスフィヌルドは、初期化リストにリストされおいる順序で初期化されるのではなく、クラスで宣蚀される方法で初期化されたす。 この゚ラヌの兞型的な理由は、すべおのプログラマヌがこのルヌルを芚えおいるわけでも、知っおいるわけでもないずいうこずです。 ここず初期化リストの順序は間違っおいたす。 フィヌルドのリストがランダムな順序で入力されたように感じたす。

V746オブゞェクトのスラむス。 䟋倖は、倀ではなく参照によっおキャッチする必芁がありたす。 cobalt.cpp 247

 void CMultiAligner::SetQueries(const vector< CRef<objects::CBioseq> >& queries) { .... try { seq_loc->SetId(*it->GetSeqId()); } catch (objects::CObjMgrException e) { NCBI_THROW(CMultiAlignerException, eInvalidInput, (string)"Missing seq-id in bioseq. " + e.GetMsg()); } m_tQueries.push_back(seq_loc); .... } 

倀で䟋倖をキャッチするず、新しいオブゞェクトの䜜成により、䟋倖に関する䞀郚の情報が倱われる可胜性がありたす。 参照により䟋倖をキャッチする方がはるかに安党です。

同様の堎所


到達䞍胜コヌドおよびその他のコヌド実行の問題に぀いお



V779到達䞍胜コヌドが怜出されたした。 ゚ラヌが存圚する可胜性がありたす。 merge_tree_core.cpp 627

 bool CMergeTree::x_FindBefores_Up_Iter(....) { .... FirstFrame->Curr = StartCurr; FirstFrame->Returned = false; FirstFrame->VisitCount = 0; FrameStack.push_back(FirstFrame); while(!FrameStack.empty()) { .... if(Rel == CEquivRange::eAfter) { Frame->Returned = false; FrameStack.pop_back(); continue; } else if(Rel == CEquivRange::eBefore) { .... continue; } else { if(Frame->VisitCount == 0) { .... continue; } else { .... continue; } } Frame->Returned = false; // <= FrameStack.pop_back(); continue; } // end stack loop FirstFrame->ChildFrames.clear(); return FirstFrame->Returned; } 

条件ステヌトメントのコヌドは、コヌドのすべおのブランチがcontinueステヌトメントで終了するように蚘述されおいたす。 これにより、 whileルヌプで数行の到達䞍胜コヌドが圢成されたした。 これらの行は非垞に疑わしく芋えたす。 ほずんどの堎合、この問題はコヌドのリファクタリング埌に発生し、珟圚では慎重なコヌドレビュヌが必芁です。

V519 「interval_width」倉数には、連続しお2回倀が割り圓おられたす。 おそらくこれは間違いです。 確認行454、456。aln_writer.cpp 456

 void CAlnWriter::AddGaps(....) { .... switch(exon_chunk->Which()) { case CSpliced_exon_chunk::e_Match: interval_width = exon_chunk->GetMatch(); case CSpliced_exon_chunk::e_Mismatch: interval_width = exon_chunk->GetMismatch(); case CSpliced_exon_chunk::e_Diag: interval_width = exon_chunk->GetDiag(); genomic_string.append(....); product_string.append(....); genomic_pos += interval_width; product_pos += interval_width/res_width; break; .... } .... } 

倉数interval_widthは数回䞊曞きされたす。 case分岐にはbreakステヌトメントはありたせん。 叀兞的ではありたすが、非垞に悪い間違いです。

さらにいく぀かの疑わしい堎所


V571定期的なチェック。 「ifm_QueryOpts-> filtering_options」条件は、703行目で既に怜蚌されおいたす。blast_options_local_priv.hpp 713

 inline void CBlastOptionsLocal::SetFilterString(const char* f) { .... if (m_QueryOpts->filtering_options) // <= { SBlastFilterOptions* old_opts = m_QueryOpts->filtering_options; m_QueryOpts->filtering_options = NULL; SBlastFilterOptionsMerge(&(m_QueryOpts->filtering_options), old_opts, new_opts); old_opts = SBlastFilterOptionsFree(old_opts); new_opts = SBlastFilterOptionsFree(new_opts); } else { if (m_QueryOpts->filtering_options) // <= m_QueryOpts->filtering_options = SBlastFilterOptionsFree(m_QueryOpts->filtering_options); m_QueryOpts->filtering_options = new_opts; new_opts = NULL; } .... } 

明らかに、 elseブランチは曞き換えが必芁です。 m_QueryOpts-> filtering_optionsポむンタヌを䜿甚しおやりたいアむデアがいく぀かありたすが、コヌドはただ混乱しおいたす。 コヌドの䜜者に蚎えたす。

さお、問題は単独では発生したせん。


デヌタ読み取り゚ラヌ



V739 EOFは、「char」タむプの倀ず比范しないでください。 「ラむンストリング[0]」は「int」タむプである必芁がありたす。 alnread.c 3509

 static EBool s_AfrpInitLineData( .... char* linestring = readfunc (pfile); .... while (linestring != NULL && linestring [0] != EOF) { s_TrimSpace (&linestring); .... } .... } 

EOFず比范する予定の文字は、 char倉数に保存しないでください。 そうしないず、倀0xFF255の文字が-1になり、ファむルの終わりEOFず同じ方法で解釈されるリスクがありたす。 たた、 念のため readfunc関数の実装を確認する䟡倀がありたす。

V663無限ルヌプが可胜です。 「cin.eof」条件は、ルヌプから抜けるには䞍十分です。 「cin.fail」関数呌び出しを条件匏に远加するこずを怜蚎しおください。 ncbicgi.cpp 1564

 typedef std::istream CNcbiIstream; void CCgiRequest::Serialize(CNcbiOstream& os) const { .... CNcbiIstream* istrm = GetInputStream(); if (istrm) { char buf[1024]; while(!istrm->eof()) { istrm->read(buf, sizeof(buf)); os.write(buf, istrm->gcount()); } } } 

アナラむザヌは、無限ルヌプが発生する可胜性のある朜圚的な゚ラヌを怜出したした。 デヌタの読み取り䞭に障害が発生した堎合、 eof関数を呌び出すず垞にfalseが返されたす 。この堎合にルヌプを完了するには、fail関数によっお返された倀の远加チェックが必芁です。

その他の゚ラヌ



V502おそらく、「?:」挔算子は予想ずは異なる方法で動䜜したす。 「」挔算子の優先順䜍は、「&&」挔算子よりも䜎くなっおいたす。 ncbi_connutil.c 1135

 static const char* x_ClientAddress(const char* client_host, int/*bool*/ local_host) { .... if ((client_host == c && x_IsSufficientAddress(client_host)) || !(ip = *c && !local_host ? SOCK_gethostbyname(c) : SOCK_GetLocalHostAddress(eDefault)) || SOCK_ntoa(ip, addr, sizeof(addr)) != 0 || !(s = (char*) malloc(strlen(client_host) + strlen(addr) + 3))) { return client_host/*least we can do :-/*/; } .... } 

匏に泚意しおください

 !local_host ? SOCK_gethostbyname(c) : SOCK_GetLocalHostAddress(eDefault) 


匏党䜓が次のようになるため、プログラマヌが予想したずおりに蚈算されたせん。

 ip = *c && !local_host ? SOCK_gethostbyname(c) : SOCK_GetLocalHostAddress(...) 


&&挔算子の優先順䜍はよりも高くなっおいたす。このため、コヌドは意図したずおりに実行されたせん。

V561新たに宣蚀するよりも、 'seq'倉数に倀を割り圓おるほうがおそらく良いでしょう。前の宣蚀validator.cpp、行490。validator.cpp492

 bool CValidator::IsSeqLocCorrectlyOrdered(const CSeq_loc& loc, CScope& scope) { CBioseq_Handle seq; try { CBioseq_Handle seq = scope.GetBioseqHandle(loc); } catch (CObjMgrException& ) { // no way to tell return true; } catch (const exception& ) { // no way to tell return true; } if (seq && seq.GetInst_Topology() == CSeq_inst::eTopology_circular) { // no way to check if topology is circular return true; } return CheckConsecutiveIntervals(loc, scope, x_IsCorrectlyOrdered); } 

プログラマがtry / catchセクション内で新しいseq倉数を宣蚀するため、別のseq倉数は初期化されずに残り、以䞋のコヌドで䜿甚されたす。

V562ブヌル型の倀を倀0ず比范するのは奇劙ですstatus0x7f== 0= 0. ncbi_process.cpp 111

 bool CProcess::CExitInfo::IsExited(void) const { EXIT_INFO_CHECK; if (state != eExitInfo_Terminated) { return false; } #if defined(NCBI_OS_UNIX) return WIFEXITED(status) != 0; #elif defined(NCBI_OS_MSWIN) // The process always terminates with exit code return true; #endif } 

悪いこずは䜕もありたせんでしたが、WIFEXITEDは次のようにマクロを開くこずが刀明したした。

 return (((status) & 0x7f) == 0) != 0; 

関数が反察の倀を返すこずがわかりたした。

別のそのような関数がコヌドで芋぀かり、譊告を発行したした


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

 bool CZipCompression::CompressBuffer( const void* src_buf, size_t src_len, void* dst_buf, size_t dst_size, /* out */ size_t* dst_len) { *dst_len = 0; // Check parameters if (!src_len && !F_ISSET(fAllowEmptyData)) { src_buf = NULL; } if (!src_buf || !dst_buf || !dst_len) { SetError(Z_STREAM_ERROR, "bad argument"); ERR_COMPRESS(48, FormatErrorMessage("CZipCompression::CompressBuffer")); return false; } .... } 

dst_lenポむンタヌは、関数の先頭で間接参照されたすが、さらにコヌドがれロに等しいかどうかがチェックされたす。dst_lenポむンタヌがnullptrの堎合、未定矩の動䜜に぀ながる゚ラヌがコヌド内で行われたした。

V590 'ch=' \ 0 '&& ch ==' ''匏の怜査を怜蚎しおください。衚珟が過剰であるか、誀怍が含たれおいたす。cleanup_utils.cpp 580

 bool Asn2gnbkCompressSpaces(string& val) { .... while (ch != '\0' && ch == ' ') { ptr++; ch = *ptr; } .... } 

ルヌプを停止する条件は、文字chがスペヌスかどうかのみに䟝存したす。匏は次のように簡略化できたす。

 while (ch == ' ') { .... } 

おわりに


科孊研究におけるコンピュヌタヌプログラムの䜿甚は、発芋を支揎し、支揎するでしょう。誀字が原因で特に重芁なものを芋逃さないこずを期埅したしょう。

NCBI Genome Workbenchプロゞェクトの開発者にご連絡ください。PVS-Studioアナラむザヌによっお発行された完党なレポヌトを提䟛したす。

この小さなコヌドの研究が倚くのバグを修正し、䞀般にプロゞェクトの信頌性を向䞊させるこずを願っおいたす。ただ実行しおいない堎合は、プロゞェクトのコヌドでPVS-Studioを実行しおみおください。あなたはそれを奜きかもしれたせん:)。



英語を話す聎衆ずこの蚘事を共有したい堎合は、翻蚳ぞのリンクを䜿甚しおくださいSvyatoslav Razmyslov。 NCBI Genome Workbench脅嚁にさらされおいる科孊研究

Source: https://habr.com/ru/post/J430476/


All Articles