業務で出会ったバグの話です。
現象
- どういう訳かグローバルなカウンタ変数がリセットされる
- メモリブレイクを仕掛けても、リセットされる瞬間が引っかからない
解析結果
#define true 1u
#define false 0u
/* グローバル変数 */
unsigned char g_is_error_flg;
extern unsigned int g_is_error_flg;
void func1( void )
{
g_is_error_flg = false;
return;
}
/* グローバル変数 */
unsigned char g_loop_counter;
void func2( void )
{
if( priority ) {
g_loop_counter++;
}
}
リセットされるカウンタは g_loop_counter
です。
いったい何がいけないのか、わかりますか?
mapファイルで確認すると、g_loop_counter
は g_is_error_flg
の次のアドレスでした。
ステップ実行して g_is_error_flg = false;
で g_loop_counter
に 0
が書き込まれるのを確認できました。
ただ、g_is_error_flg = false;
の何がいけないのか、しばらくは分かりませんでした。
mogemoge.c
から見ると、g_is_error_flg
の宣言はどっか別の所にあって、mogemoge.c
内では unsigned int
として扱うしかない訳です。
ところが、アドレスの割り付けとしてはg_is_error_flg
と g_loop_counter
で1バイトずつでしか割り当てられていない訳で。
困った事に、他のいくつかのファイルでも g_is_error_flg
は使われていたんですが、mogemoge.c
以外のファイルでは正しく extern
宣言されていたんですよねー。
今は、他に同様のケースがないかどうか、どうやって確認しようかをプロジェクト内で相談中です。
grepによる力技は避けたいよなあ、と誰もが口に出して言ってます。
どなたか、いい知恵ありませんか?
IARっていう統合開発環境を使ってたんですが、
静的解析では引っかかりませんでした。
ただ、メモリブレイクでも引っかからなかったのは、なんか納得いかなかったですね。
教訓
extern 宣言は変数宣言のコピペで作ろう!