C++ プログラミング
プログラミングで出逢った出来事
dirent の複製で EXC_BAD_ACCESS が発生する
C++ を混ぜて作成していた OS X アプリが、実行時に「ときどき落ちる」エラーに見舞われました。
エラーの原因はEXC_BAD_ACCESS
のようで、エラーの場所はだいたいが C++ のstd::ostrstream
にstd::string
のデータを書き込んでいるときのstd::ostrstream
内でのエラーのようでした。ただ、別のところでエラーが発生することもあり、エラー自体が発生したりしなかったりだったため、ぱっと見で原因はよくわかりません。
ただ、このような掴みづらいエラーのときは C++ のメモリ確保まわりでミスがあることが多いような気がします。
メモリまわりのデバッグ機能を有効化
メモリ確保まわりでエラーがあるとすれば、もしかするとXcode
でメモリまわりのデバッグ機能を有効にすれば何か判るかもしれないと思い、Run アクションのDiagnostics
設定を調整してみることにしました。
ここにあるMemory Management
カテゴリのEnable Guard Malloc
にチェックをいれてアプリを実行してみたところ、ディレクトリエントリの一覧を取得するscandir
関数で取得したdirent
の値を代入演算子でコピーしようとしたところでEXC_BAD_ACCESS
エラーが発生するようになりました。
dirent dstEntry = *srcEntryPtr;
代入方法を要素毎のコピーに変更
構造体と言えば、代入演算子で中の要素がそのままコピーできそうにも思えますが、このdirent
構造体の場合は、要素のd_name
が文字の配列のためか、代入演算子では上手くコピーできないようです。
そこで次のように、要素をひとつひとつ代入して、d_name
の値だけはstrcpy
関数でコピーするようにしてみました。
dirent& direntCopy(dirent& dstEntry, const dirent& srcEntry)
{
dstEntry.d_ino = srcEntry.d_ino;
strcpy(dstEntry.d_name, srcEntry.d_name);
dstEntry.d_namlen = srcEntry.d_namlen;
dstEntry.d_reclen = srcEntry.d_reclen;
dstEntry.d_seekoff = srcEntry.d_seekoff;
dstEntry.d_type = srcEntry.d_type;
return dstEntry;
}
そうしたところ、EXC_BAD_ACCESS
エラーは発生しなくなりました。
EXC_BAD_ACCESS
は解消されませんでした。理解しきれていないのですけど、
d_name
が固定長配列でのアドレスがおかしくなるのでしょうか。