これは、PVS-Studioがプログラムの信頼性を高める方法に関する次の記事です。 それがどこで、どのエラーを検出するかです。 今回は、IPP 7.0ライブラリ(Intel Performance Primitives Library)での作業を示すハンマーの例の下で、ハンマーの下に落ちました。 最初は、この投稿をインテルのブログに投稿したかったのですが、それが完全に終わることになりました...
Intel Parallel Studio 2011には、パフォーマンスプリミティブライブラリが含まれています。 このライブラリには、効果的なビデオおよびオーディオコーデック、信号処理プログラム、画像レンダリングメカニズム、アーカイバなどを作成できる多数のプリミティブが含まれています。 当然、そのようなライブラリを操作するのは簡単ではありません。 そのため、インテルはこのライブラリに基づいて構築された多数のデモプログラムを用意しています。 例の説明をよく理解し、次のリンクからダウンロードできます。
- Intel Integrated Performance Primitives(Intel IPP)ライブラリのコードサンプル
- Parallel Studio 2011のIntel Integrated Performance Primitives Library 7.0のサンプル
すべての例は、4つのグループに分けられます。
- Windows用のIPPサンプル
- Windows用IPP UICデモ
- Windows用のIPP DMIPサンプル
- Windows用のIPP暗号化サンプル
各セットには多数のプロジェクトが含まれているため、最初はWindows用のIPPサンプルの最初のセットのみをテストすることにしました。 PVS-Studioバージョン4.10を使用して確認しました。
この投稿では、プログラマのプロ意識と開発中のソリューションのレベルに関係なく、静的分析が有用であることを示したいと思います。 「専門家を連れてすぐに文章を書く」という考えはうまくいきません。 高度な資格を持つ開発者でさえ、コーディングプロセスのエラーやタイプミスの影響を受けません。 IPPの例のエラーは、これを非常によく示しています。
Windows用IPPサンプルは高品質のプロジェクトであることを強調します。 ただし、コードのサイズは160万行であるため、必然的にさまざまなエラーが含まれます。 それらのいくつかを考えてみましょう。
配列インデックスの置換に失敗しました
この例は、以前の記事「 C ++でプログラミングする際にコピーペーストテクノロジーを使用した場合の結果とその対処方法 」を著しく補完するものです。
struct AVS_MB_INFO { ... Ipp8u refIdx [AVS_DIRECTIONS] [4]; ... }; void AVSCompressor :: GetRefIndiciesBSlice(void){ ... if(m_pMbInfo-> predType [0]&predType) { m_refIdx [iRefNum] = m_pMbInfo-> refIdx [dir] [0]; iRefNum + = 1; } if(m_pMbInfo-> predType [1]&predType) { m_refIdx [iRefNum] = m_pMbInfo-> refIdx [dir] [1]; iRefNum + = 1; } if(m_pMbInfo-> predType [2]&predType) { m_refIdx [iRefNum] = m_pMbInfo-> refIdx [dir] [2]; iRefNum + = 1; } if(m_pMbInfo-> predType [3]&predType) { m_refIdx [iRefNum] = m_pMbInfo-> refIdx [dir] [30]; iRefNum + = 1; } ... }
PVS-Studio診断メッセージ:V557アレイのオーバーランが可能です。 「30」インデックスは、配列の境界を超えています。 avs_enc umc_avs_enc_compressor_enc_b.cpp 495
プログラマーはコードフラグメントを数回コピーし、配列インデックスの値を変更しました。 しかし、最後に彼の手は震えました。 彼は番号3を入力しましたが、番号0を削除しませんでした。その結果、インデックス30が取得され、コードが実行されると、アクセスは配列の境界をはるかに超えます。
同じコードブランチ
コードのコピーから始めたので、このトピックの別の例を次に示します。
AACStatus aacencGetFrame(...) { ... if(maxEn [0]> maxEn [1]){ ics [1] .num_window_groups = ics [0] .num_window_groups; for(g = 0; g <ics [0] .num_window_groups; g ++){ ics [1] .len_window_group [g] = ics [0] .len_window_group [g]; } } else { ics [1] .num_window_groups = ics [0] .num_window_groups; for(g = 0; g <ics [0] .num_window_groups; g ++){ ics [1] .len_window_group [g] = ics [0] .len_window_group [g]; } } ... }
PVS-Studio診断メッセージ:V523「then」ステートメントは「else」ステートメントと同等です。 aac_enc aac_enc_api_fp.c 1379
しかし、今回は逆に、コピーされたコードを編集するのを忘れていました。 「if」条件演算子の両方のブランチは、同じアクションを実行します。
操作の優先順位「-」のデクリメントとポインター「*」の逆参照との混乱
静的ボイド sbrencConflictResolution(...、Ipp32s * nLeftBord) { ... * nLeftBord = nBordNext-1; ... if(* lenBordNext> 1){ ... * nLeftBord--; } ... }
PVS-Studio診断メッセージ:V532「* pointer--」パターンのステートメントの検査を検討してください。 おそらく意味:「(*ポインター)-」。 aac_enc sbr_enc_frame_gen.c 428
nLeftBordポインターは、sbrencConflictResolution関数から値を返すために使用されます。 最初に、値「nBordNext-1」が指定されたアドレスに書き込まれます。 特定の条件下では、この値は1減少します。 値を減らすために、プログラマは次のコードを使用しました。
* nLeftBord--;
エラーは、値の代わりにポインター自体が減少することです。 正しいコードは次のようになります。
(* nLeftBord)-;
インクリメント演算子「++」と逆参照ポインター「*」によるさらに混乱した状況
次のコードは、私にはまったく理解できません。 理にかなうように修正する方法がわかりません。 ここに何か足りないかもしれません。
静的IppStatus mp2_HuffmanTableInitAlloc(Ipp32s * tbl、...) { ... for(i = 0; i <num_tbl; i ++){ * tbl ++; } ... }
PVS-Studio診断メッセージ:V532「*ポインター++」パターンのステートメントの検査を検討してください。 おそらく意味:「(*ポインター)++」。 mpeg2_dec umc_mpeg2_dec.cpp 59
これで、例に示されているループは次のコードと同等になります。
tbl + = num_tbl;
PVS-Studioアナライザーは、ここではブラケットを忘れている可能性があるため、「(* tbl)++;」と記述する必要があると示唆しています。 しかし、このコードは意味がありません。 その場合、ループは同等になります。
* tbl + = num_tbl;
一般的に、非常に奇妙な種類のサイクル。 エラーがありますが、明らかにコードの作者だけがそれを修正できます。
エラーが発生したという兆候の喪失
コードには関数「GetTrackByPidOrCreateNew」があり、エラーが発生した場合に値「-1」を返します。
typedef signed int Ipp32s; typedef unsigned int Ipp32u; Ipp32s StreamParser :: GetTrackByPidOrCreateNew(Ipp32s iPid、bool * pIsNew) { ... else if(!pIsNew || m_uiTracks> = MAX_TRACK) return -1; ... }
「GetTrackByPidOrCreateNew」関数を使用すると、すべてがうまくいきます。 ただし、使用するとエラーが発生します。
ステータスStreamParser :: GetNextData(MediaData * pData、Ipp32u * pTrack) { ... * pTrack = GetTrackByPidOrCreateNew(m_pPacket-> iPid、NULL); if(* pTrack> = 0 && TRACK_LPCM == m_pInfo [* pTrack]-> m_Type) ippsSwapBytes_16u_I((Ipp16u *)pData-> GetDataPointer()、 m_pPacket-> uiSize / 2); ... }
PVS-Studio診断メッセージ:V547式 '* pTrack> = 0'は常にtrueです。 符号なしの型の値は常に> = 0です。demuxerumc_stream_parser.cpp 179
GetTrackByPidOrCreateNew関数が返す値は、符号なし形式(unsigned int)で保存されます。 これは、「-1」が「4294967295」に変わり、条件「* pTrack> = 0」が常に真であることを意味します。
その結果、関数「GetTrackByPidOrCreateNew」が値「-1」を返す場合、コード「m_pInfo [* pTrack]-> m_Type」が実行されるとアクセス違反が発生します。
コピーペーストと忘れられた+1
void H264SegmentDecoder :: ResetDeblockingVariablesMBAFF() { ... if(GetMBFieldDecodingFlag(m_gmbinfo-> mbs [m_CurMBAddr -mb_width * 2])) m_deblockingParams.nNeighbor [HORIZONTAL_DEBLOCKING] = m_CurMBAddr-mb_width * 2; 他に m_deblockingParams.nNeighbor [HORIZONTAL_DEBLOCKING] = m_CurMBAddr-mb_width * 2; ... }
PVS-Studio診断メッセージ:V523「then」ステートメントは「else」ステートメントと同等です。 h264_dec umc_h264_segment_decoder_deblocking_mbaff.cpp 340
近くのコードを見ると、コピーした行にコードを追加するのを忘れていることが明らかになります。 正しいコードは次のようになります。
if(GetMBFieldDecodingFlag(m_gmbinfo-> mbs [m_CurMBAddr -mb_width * 2])) m_deblockingParams.nNeighbor [HORIZONTAL_DEBLOCKING] = m_CurMBAddr-mb_width * 2; 他に m_deblockingParams.nNeighbor [HORIZONTAL_DEBLOCKING] = m_CurMBAddr-mb_width * 2 + 1;
近くの関数「H264CoreEncoder_ResetDeblockingVariablesMBAFF」には、忘れられた「+ 1」とまったく同じエラーがまだあります。
PVS-Studio診断メッセージ:V523「then」ステートメントは「else」ステートメントと同等です。 h264_enc umc_h264_deblocking_mbaff_tmpl.cpp.h 366
削除。何も削除されません。
void H264ThreadGroup :: RemoveThread(H264Thread *スレッド) { 自動UMCMutexガード(m_mGuard)。 std :: remove(m_threads.begin()、m_threads.end()、thread); }
PVS-Studio診断メッセージ:V530関数 'remove'の戻り値を使用する必要があります。 h264_dec umc_h264_thread.cpp 226
興味深い組み合わせ。 一方では、すべてが堅実です。 マルチスレッドアプリケーションでアイテムを正しく削除するためにmutexによって使用されます。 一方、std :: remove関数は配列から要素を削除せず、順序を変更するだけであることを忘れていました。 実際には次のように書く必要があります。
m_threads .erase( std :: remove(m_threads.begin()、m_threads.end()、thread)、 m_threads.end());
構造体フィールドとそれ自体の比較
私はエラーを見て、H264ビデオ圧縮標準の実装に何らかのバグがあることに気付きました。 このプロジェクトには、かなり多数のエラーが見つかりました。 たとえば、プログラミング中に誰かが急いで、すぐに2つの誤った変数名を使用しました。
bool H264_AU_Stream :: IsPictureSame(H264SliceHeaderParse&p_newHeader) { if((p_newHeader.frame_num!= m_lastSlice.frame_num)|| (p_newHeader.pic_parameter_set_id!= p_newHeader.pic_parameter_set_id)|| (p_newHeader.field_pic_flag!= p_newHeader.field_pic_flag)|| (p_newHeader.bottom_field_flag!= m_lastSlice.bottom_field_flag) ){ falseを返します。 } ... }
PVS-Studio診断メッセージ:
V501「!=」演算子の左側と右側に同一のサブ式「p_newHeader.pic_parameter_set_id」があります。 h264_spl umc_h264_au_stream.cpp 478
V501「!=」演算子の左側と右側には、同一のサブ式「p_newHeader.field_pic_flag」があります。 h264_spl umc_h264_au_stream.cpp 479
構造体の一部のメンバーがそれ自体と比較されるため、比較関数は機能しません。 以下に2つの修正された行を示します。
(p_newHeader.pic_parameter_set_id!= m_lastSlice.pic_parameter_set_id) || (p_newHeader.field_pic_flag!= m_lastSlice.field_pic_flag)||
不正なデータのコピー
比較するときだけでなく、オブジェクトの状態をコピーするときにも、間違ったオブジェクトを使用するとエラーが発生します。
Ipp32s ippVideoEncoderMPEG4 :: Init(mp4_Param * par) { ... VOL.sprite_width = par-> sprite_width; VOL.sprite_height = par-> sprite_height; VOL.sprite_left_coordinate = par-> sprite_left_coordinate; VOL.sprite_top_coordinate = par-> sprite_left_coordinate; ... }
PVS-Studio診断メッセージ:V537「sprite_left_coordinate」アイテムの使用の正確さを確認することを検討してください。 mpeg4_enc mp4_enc_misc.cpp 387
無効な値はVOL.sprite_top_coordinateに配置されます。 正しい割り当ては次のようになります。
VOL.sprite_top_coordinate = par-> sprite_top_coordinate;
1つの変数に2つのループ
JERRCODE CJPEGDecoder :: DecodeScanBaselineNI(void) { ... for(c = 0; c <m_scan_ncomps; c ++) { block = m_block_buffer +(DCTSIZE2 * m_nblock *(j +(i * m_numxMCU))); //関連するコンポーネントをスキップします for(c = 0; c <m_ccomp [m_curr_comp_no] .m_comp_no; c ++) { ブロック+ =(DCTSIZE2 * m_ccomp [c] .m_nblocks); } ... }
PVS-Studio診断メッセージ:V535このループと外側のループに変数「c」が使用されています。 jpegcodec jpegdec.cpp 4652
互いにネストされた2つのループの場合、1つの変数「c」が使用されます。 このようなデコード関数の操作の結果は、非常に奇妙で予期しないものになる可能性があります。
信頼性を高めるための二重割り当て
H264EncoderFrameType * H264ENC_MAKE_NAME(H264EncoderFrameList_findOldestToEncode)(...) { ... MaxBrefPOC = H264ENC_MAKE_NAME(H264EncoderFrame_PicOrderCnt)(pCurr、0、3); MaxBrefPOC = H264ENC_MAKE_NAME(H264EncoderFrame_PicOrderCnt)(pCurr、0、3); ... }
PVS-Studio診断メッセージ:V519「MaxBrefPOC」オブジェクトには、連続して2回値が割り当てられます。 おそらくこれは間違いです。 h264_enc umc_h264_enc_cpb_tmpl.cpp.h 784
このコードを見たとき、古いプログラミングのジョークを思い出しました。
-そして、なぜあなたはあなたのコードに2つの同一のGOTOを連続して持っているのですか?
-最初のものが機能しない場合はどうでしょう!
このエラーはおそらく重大ではありませんが、それでも間違いです。
憂慮すべきコード
AACStatus sbrencResampler_v2_32f(Ipp32f * pSrc、Ipp32f * pDst) { ... k = nCoef-1; k = nCoef; ... }
PVS-Studio診断メッセージ:V519「k」オブジェクトには、連続して2回値が割り当てられます。 おそらくこれは間違いです。 aac_enc sbr_enc_resampler_fp.c 90
この二重の割り当ては、前の例よりもはるかに危険です。 プログラマは自分に自信がなかったようです。 または、最初に「nCoef-1」を試してから「nCoef」を試してみることにしました。 これは「実験プログラミング」とも呼ばれます。 いずれにせよ、これはコードのどこにあるのかを考えて、どれを長引かせて思考にふけるべきかを見極めます。
完全に最小ではない最小値
void MeBase :: MakeVlcTableDecision() { ... Ipp32s BestMV = IPP_MIN(IPP_MIN(m_cur.MvRate [0]、m_cur.MvRate [1])、 IPP_MIN(m_cur.MvRate [2]、m_cur.MvRate [3])); Ipp32s BestAC = IPP_MIN(IPP_MIN(m_cur.AcRate [0]、m_cur.AcRate [1])、 IPP_MIN(m_cur.AcRate [2]、m_cur.AcRate [2])); ... }
PVS-Studio診断メッセージ:V501 '<'演算子の左右に同じ副次式があります:(m_cur.AcRate [2])<(m_cur.AcRate [2])me umc_me.cpp 898
再度、配列インデックスのタイプミス。 最後のインデックスは2ではなく3です。正しいバージョンのコード:
Ipp32s BestAC = IPP_MIN(IPP_MIN(m_cur.AcRate [0]、m_cur.AcRate [1])、 IPP_MIN(m_cur.AcRate [2]、m_cur.AcRate [3]);
このようなエラーは、コードが「ほとんど機能する」という点で不快です。 エラーは、最小要素が「m_cur.AcRate [3]」に保存されている場合にのみ現れます。 このようなエラーは、テスト中ではなく、ユーザーが入力データセットを使用して証明するのが好きです。
最大値。これは完全に最大ではありません
最大値では、常にうまくいくとは限りません。
Ipp32s ippVideoEncoderMPEG4 :: Init(mp4_Param * par) { ... i = IPP_MAX(mBVOPsearchHorBack、mBVOPsearchHorBack); ... }
PVS-Studio診断メッセージ:V501 '>'演算子の左右に同じサブ式 '(mBVOPsearchHorBack)'があります。 mpeg4_enc mp4_enc_misc.cpp 547
mBVOPsearchHorBack変数は2回使用されます。 実際には、mBVOPsearchHorBackおよびmBVOPsearchVerBackを使用することが計画されていました。
i = IPP_MAX(mBVOPsearchHorBack、mBVOPsearchVerBack);
指で空を打つ
typedef構造体 { ... VM_ALIGN16_DECL(Ipp32f)nb_short [2] [3] [__ ALIGNED(MAX_PPT_SHORT)]; ... } mpaPsychoacousticBlock; static void mp3encPsy_short_window(...) { ... if(win_counter == 0){ nb_s = pBlock-> nb_short [0] [3]; } ... }
PVS-Studio診断メッセージ:V557アレイのオーバーランが可能です。 「3」インデックスは、配列の境界を超えています。 mp3_enc mp3enc_psychoacoustic_fp.c 726
明らかに簡単なタイプミスがあります。 誤ってインデックス「2」ではなく「3」を使用していました。 結果は理解できると思います。
作業速度の低下エラー
void lNormalizeVector_32f_P3IM(Ipp32f * vec [3]、Ipp32s *マスク、 Ippps len){ ipp32s i; Ipppfノルム; for(i = 0; i <len; i ++){ if(mask <0)continue; norm = 1.0f / sqrt(vec [0] [i] * vec [0] [i] + vec [1] [i] * vec [1] [i] + vec [2] [i] * vec [2] [i]); vec [0] [i] * =ノルム; vec [1] [i] * =ノルム; vec [2] [i] * =ノルム; } }
PVS-Studio診断メッセージ:V503これは無意味な比較です:ポインター<0。ipprsample ippr_sample.cpp 501
これは、エラーが原因で動作が遅くなることがあるコードの美しい例です。 アルゴリズムは、マスク配列でマークされている要素のみを正規化する必要があります。 しかし、上記のコードはすべての要素の正規化を行います。 エラーの状態は「if(mask <0)」です。 ここでは、「i」インデックスの使用を忘れていました。 ほとんどの場合、マスクポインターはゼロ以上になります。つまり、すべての要素を処理します。
正しいチェック:
if(mask [i] <0)continue;
減算の結果は常に0です
int ec_fb_GetSubbandNum(void * stat) { _fbECState * state =(_ fbECState *)stat; return(state-> freq-state-> freq); }
PVS-Studio:V501診断メッセージ「-」演算子の左右に同じ副次式があります:state-> freq-state-> freq speech ec_fb.c 250
ここでは、タイプミスにより、関数は常に値0を返します。何かが間違っているので、ここで減算します。 あなたが減算する必要があるもの、私は知りません。
バッファー不足の不適切な処理
typedef unsigned int Ipp32u; UMC ::ステータスの初期化(...、Ipp32u memSize、...) { ... memSize-= UMC :: align_value <Ipp32u>(m_nFrames * sizeof(Frame)); if(memSize <0) return UMC :: UMC_ERR_NOT_ENOUGH_BUFFER; ... }
PVS-Studio診断メッセージ:V547式 'memSize <0'は常にfalseです。 符号なしの型の値が0未満になることはありませんvc1_enc umc_vc1_enc_planes.h 200
誤って、操作のバッファーサイズが不十分な場合に状況が処理されます。 エラーコードを返す代わりに、プログラムは引き続き動作し、ほとんどの場合クラッシュします。 実際、変数「memSize」のタイプは「unsigned int」です。 したがって、条件「memSize <0」は常にfalseであり、サイズが不十分なバッファーで作業を続けます。
これはおそらく、攻撃に対するプログラムの脆弱性の良い例です。 誤ったデータをスリップしたら、バッファをオーバーフローさせて使用しようとすることができます。 ちなみに、このような脆弱性は約10件ありましたが、テキストが乱雑にならないようにするために、これらの脆弱性は持ち込みません。
誤ったチェック、およびその結果、配列の境界から出る
Ipp32u m_iCurrMBIndex; VC1EncoderMBInfo * VC1EncoderMBs :: GetPevMBInfo(Ipp32s x、Ipp32s y) { Ipp32s行=(y> 0)? m_iPrevRowIndex:m_iCurrRowIndex; return((m_iCurrMBIndex-x <0 || row <0)?0: &m_MBInfo [row] [m_iCurrMBIndex-x]); }
PVS-Studio診断メッセージ:V547式 'm_iCurrMBIndex-x <0'は常にfalseです。 符号なしの型の値が<0になることはありませんvc1_enc umc_vc1_enc_mb.cpp 188
変数「m_iCurrMBIndex」のタイプは「unsigned」です。 このため、式「m_iCurrMBIndex-x」も「unsigned」タイプです。 したがって、条件「m_iCurrMBIndex-x <0」は常にfalseです。 結果を考慮してください。
変数「m_iCurrMBIndex」を5、変数「x」を10とします。
式「m_iCurrMBIndex-x」は、5u-10i = 0xFFFFFFFBuです。
条件「m_iCurrMBIndex-x <0」は偽です。
式「m_MBInfo [row] [0xFFFFFFFBu]」が実行され、配列を超えています。
三項演算子 '?:'の使用中にエラーが発生しました。
三項演算子は間違いを犯しやすいため、非常に危険です。 ただし、プログラマーは短い文章を書き、興味深い言語構成を使用するのが大好きです。 C ++言語はこれを罰します。
vm_file * vm_file_fopen(...) { ... mds [3] = FILE_ATTRIBUTE_NORMAL | (islog == 0)? 0:FILE_FLAG_NO_BUFFERING; ... }
PVS-Studio診断メッセージ:V502おそらく '?:'オペレーターは予想とは異なる方法で動作します。 「?:」演算子の優先順位は「|」よりも低い 演算子。 vm vm_file_win.c 393
コードは、FILE_ATTRIBUTE_NORMALフラグとFILE_FLAG_NO_BUFFERINGフラグの組み合わせである必要があります。 しかし、実際には、「mds [3]」要素には常に値0が割り当てられます。
プログラマーは、オペレーターが 「?:」演算子の優先度よりも高い。 次の式がコードに記述されていることがわかります(括弧に注意してください)。
(FILE_ATTRIBUTE_NORMAL |(islog == 0))?
0:FILE_FLAG_NO_BUFFERING;
条件FILE_ATTRIBUTE_NORMAL | (islog == 0)「常に真であり、要素を設定します」mds [3]「0にします。
正しい式は次のようになります(繰り返しますが、括弧に注意してください)。
FILE_ATTRIBUTE_NORMAL | ((islog == 0))? 0:FILE_FLAG_NO_BUFFERING);
配列の奇妙な仕事
AACStatus alsdecGetFrame(...) { ... for(i = 0; i <num; i ++){ ... * tmpPtr =(Ipp32s)((tmp << 24)+((tmp&0xff00)<< 8)+ ((tmp >> 8)&0xff00)+(tmp >> 24)); * tmpPtr = * srcPrt; ... } ... }
PVS-Studio診断メッセージ:V519「* tmpPtr」オブジェクトには、値が連続して2回割り当てられます。 おそらくこれは間違いです。 aac_dec als_dec_api.c 928
読者にコードを調べて結論を出すことをお勧めします。 このコードを「オリジナル」という言葉で説明します。
超常的な割り当て
静的 IPLStatus ownRemap8u_Pixel(...){ ... saveXMask = xMap-> maskROI; saveXMask = NULL; saveYMask = yMap-> maskROI; saveYMask = NULL; ... }
PVS-Studio診断メッセージ:
V519「saveXMask」オブジェクトには、連続して2回値が割り当てられます。 おそらくこれは間違いです。 ipl iplremap.c 36
V519「saveYMask」オブジェクトには、連続して2回値が割り当てられます。 おそらくこれは間違いです。 ipl iplremap.c 38
このような奇妙なコードが表示される理由は、私には明らかではありません。 さらに、同様のブロックが異なる機能で8回繰り返されます!
1つの変数の他の疑わしい割り当てがあります。
Ipp32s ippVideoEncoderMPEG4 :: Init(mp4_Param * par) { ... mNumOfFrames = par-> NumOfFrames; mNumOfFrames = -1; ... }
PVS-Studio診断メッセージ:V519「mNumOfFrames」オブジェクトには、連続して2回値が割り当てられます。 おそらくこれは間違いです。 mpeg4_enc mp4_enc_misc.cpp 276
おわりに
この記事では、IPP Samples for Windowsで見つかったエラーの一部のみをリストしています。 それらは私が記事で調べた例の双子の兄弟であり、それらについて読むのはおもしろくないので、私はいくつかの誤りを挙げませんでした。 ここでは軽微なエラーを挙げませんでした。 例としてassert()があります。これは、タイプミスのために常に真です。 コードの多くのセクションを見逃しました。これが間違いなのか、単にsimplyい文章なのかわからないからです。 ただし、説明されている欠陥は、プロの開発者でさえ大規模なプロジェクトを書くことの難しさを示すのに十分だと思います。
もう一度、記事の冒頭で述べたアイデアを策定します。 優れたプログラマーでさえ、タイプミス、物忘れ、コピー貼り付けの欲求、ロジックのエラーから免れません。 将来、この記事へのリンクは、「コードを正しく書く必要があります」というフレーズを発音することでエラーから保護されると確信している人々にとって良い答えになると思います。
C / C ++ / C ++ 0xプロジェクトの皆さんに幸運を。 そして、私に愛されている静的解析手法を使用して、より多くのエラーを見つけてほしい。