作業には、プリプロセッサの直後にファイルが必要です。 AVR Studio環境はこれを行うことができますが、1つの小さな例外があります-「プリプロセッサのみ」フラグをオンにした後、プリプロセッサの後のファイルは実際に出力に表示されますが、予想される.iの代わりに.o拡張子が付いています。 さて、5分間のPythonスクリプトでこの誤解が解決され、アナライザーは正常に起動します!
驚くべきことに、メッセージはほとんどありません。 それらのほとんどは取るに足りない発言または誤検知です(同じ値のレジスタに埋め込まれたレコードで2回連続して発生し、アナライザーはこれを潜在的な問題と見なします(一般的には同意します-安全にプレイしてそのような場所をチェックする方が良いです)。
いくつかの場所で、実際のタイプミスとコピーアンドペーストのエラーが見つかりました。 たとえば、あるenum-aのタイプの変数は、別のenum-aの値と比較されます。 または、1つの変数に2つの異なる値が連続して割り当てられます(ただし、上記のように、ほとんどの場合、これはレジスタにシーケンスを登録するための誤検知でした)。
しかし、最も興味深いのは、この投稿を書いている理由であり、唯一の行「Possible NULL pointer dereferenceencing」でした...
コードのどこでもフォームの構造を使用していることが起こった
void fun(error_t * perr) { *perr = SUCCESS; ... if (something) { *perr = SOME_ERROR; } }
そして、文字通りいくつかの機能で設計が少し異なっていました:
void init(void) { error_t err = SUCCESS; ... fun(&err); }
いずれかの場所での小さなリファクタリングの1日後、次のようになりました。
void some_init(void) { error_t *perr = SUCCESS; ... some_fun(perr); }
実際、この行ではアナライザーも呪われていました。 もちろん、SUCCESSの値は0でした。
この変更がリポジトリにヒットした時点に少し戻って時間を巻き戻します。
リファクタリング後、非常に大きな一連の自動テストが引き続き正常に実行されました。 コードレビューにより、この行は気付かれませんでした(コードで* perr = SUCCESS行がちらつくことが多すぎます)。
そのコミットの約30日後に、夜間テストが初めて低下しました。 プレイフォールは機能しませんでした。
その後、テストは再び落ちました。 その他。 テストスイートの30回の実行ごとに平均してドロップが発生することが実験的に確立されました。
チームは約50時間かけてエラーを探しました。 無駄に。 確かに、コミットをローカライズした後、すべてが開始されましたが、理由は見つかりませんでした。
ちなみに、理由は2段階下がっていました。 それ自体の中の関数some_fun(perr)はsome_other_fun(perr)を呼び出し、その関数はsome_third_fun(perr)を呼び出しました。 そして、すでにsome_third_fun(perr)にエラーをチェックするコードがありました:
for(number_of_loops) { some_action(perr); if (*perr != SUCCESS) return; }
つまり some_action関数(非常に重要であり、外部周辺機器の束を含む-問題をローカライズするためであり、簡単なタスクではなかったため)でエラーが発生しなかったという事実にもかかわらず、サイクルの継続は0アドレスに書き込まれた値に依存していました(埋め込みでほとんどの場合、ゼロアドレスは完全に合法です)。 そして圧倒的に、このアドレスには0が書き込まれました。
要約:検出に約50時間かかったエラーは、アナライザーを1回実行するだけで1時間以内に検出および修正されました。
アナライザーを使用する説得力のある議論ですか? 悲しいかな、いつもではない。 特に、まさにそのケースです。時間と材料のスキームに応じた支払いを伴うプロジェクトです。 検索に費やした50時間は顧客が支払うため、ガイダンスとして、アナライザーの実装は直接的な損失を意味します:(((
また、ところで:プロジェクトはFreeRTOSを使用します。 そのため、彼女のコードには警告が1つもありませんでした!
そして、はい、この投稿は