2018/03/06

[c/c++][lmdb]同じ名前のDBが複数出来てしまう謎 (2) - やはり私か

なんとなく予想できていたと思うが、昨日の件はやはり私が悪かった・・・。
疑って済まん、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 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。