なんとなく予想できていたと思うが、昨日の件はやはり私が悪かった・・・。
疑って済まん、lmdbよ。
原因は・・・mdb_dbi_open()に与えるname(DB名)の末尾に、\0を付け忘れた、だッ!!
あああああ、恥ずかしい。。。。。
以下、全部言い訳だ。
DB名を作るのに、プレフィクスと16進数の組み合わせを使っていた。
"HK23a8bc24"みたいな感じだ。
16進数の部分は変数の値を文字列にしたもので、桁数が多いので関数を作っていた。
イメージとしては、こんな感じか。
char dbname[60 + 1];
strcpy(dbname, "HK");
hex2str(dbname + 2, hexarray);
これで、hex2str()で\0まで付けるようにしていた。
今まではそれでやっていたのだが、これの配列版がほしくなった。
for文で末尾に付ければいいや、と思ったのだが、ここで変なことを考えてしまった。
「桁数が決まっているのだから、strcat()とかで追加せずに、memcpy()でやった方が早いんじゃないの?」と。
プレフィクスも固定長だから、memcpy()した方がいいよねー(たぶん)、とか考えて、結果的にこうなった。
char dbname[60 + 3 + 1];
hex2str(dbname + 2, hexarray);
memcpy(dbname, "HK", 2);
for (int lp = 0; lp < xxx; lp++) {
char str[3 + 1];
sprintf("str, "%03d", lp);
memcpy(dbname + 60, str, 3);
mdb_dbi_open(xxx, dbname, ....);
}
はい、結果として、dbnameの末尾は未初期化のままとなったのでした。
なんとなく心配したので、printf()でdbnameをログに出していたのだけど、見事にゴミでは無いだったのだろう。
期待したdbnameしか出力されていなかったのだった。
わかったあとで"0x02x"でバイナリ出力させると、0x7Fだったり0x00だったり。
0x7FはDELだっけ? あれは出力に出てこないのか。
こういう話をすると「だからスタック変数は最初に初期化すべきだ!」という人が出てくる。
そして、こちらもやらかした身だから、全然強く言えない。
でも、やはり無条件でスタック変数を初期化するというのは、あまり好きになれないのだ。
初期化する処理だって、コードが発生するし、処理時間も発生してしまうと思うと、バグで苦労することになったとしても、極力最小限で抑えてしまう。
全くの未初期化であればコンパイラも検知できるのだが、今回のように\0だけ忘れた文字列、となると、ちょっと難しいだろう。
静的解析ツールでも無理なんじゃなかろうか。
そうなると、VCみたいに、デバッグモードの時は無意味な値(0xccだっけ)で埋められる方がよいのかもしれないが、今回のように「忘れた」となると、デバッグモードでは動作してリリースモードでバグが現れる、という、しばしば見られる事態が発生してしまう。
そう思うと・・・初期化しないことが悪なのだろうか。。。
何か私を力づける手法を見つけたいものだ。
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。