datchの日記

気がついたら社会人。気になる技術的なことについて少しずつ書いていけたらと思っております。

【技術メモ】Boost::program_optionsがVSのDebugモードで動かなかった件

今日は内定者懇親会で色々な仲間と会えました。

エンジニアの内定者と話をしているとみんな自分よりも技術力が高そうでなかなか怖い。

いい加減あの研究ソースコードリファクタリング終わらせたいし、先生からの煽りとリファクタリングが一瞬で終わると思っている幻想をぶち壊したい。

今日は逃げでストックしておいたBoostの仕様?でちょっと詰まった話。

Boostとは?



C++のライブラリ。
C++標準化委員会が多くコミュニティに参加しており、C++の仕様や標準化に大きな影響力を持ったライブラリで、ここで採用された機能がC++11やC++14でもいくつか採用されている。
他のプログラミング言語において、標準ライブラリが貧弱なC++Java程度まで引き上げてくれる。

Boost.program_optionsって?



boost/program_optionsはコマンドライン引数やファイルから入力されるオプション情報(i.e. -i hoge.txt "入力ファイルをhoge.txtに指定する")を自動的にパースし、変数に入れてくるすぐれもの。
従来のCのgetopt()関数では単一の文字しか扱えず、複数文字のオプションは自身で実装する必要性があったが、その必要性がなくなった。

自身の環境



今回発生した問題を語る前にまずは自分の環境について書き連ねたいと思う。
環境名詳細
Boost Version1.55.0
OSwindows7 64bit
コンパイラVisualStudio2010 Professional
CPUcorei7 2600 3.4G

問題の内容



自分で作ったオプション処理のライブラリからboost/program_optionsに置き換えたのだが、問題が発生した
それはソリューション構成を『Debug』にした時のみ発生するものだった。
コマンドプロンプトには以下のように表示される。

Assertion failed: n == name.size()-2, file libs\program_options\src\options_description.cpp, line 118

当初はこれを無視してなんとか開発を進めていたのだが、テストコードを実行するにはどうしてもDebugモードで実行する必要性が出たため、原因の究明・解決をすることになった。

過程を色々とすっとばすが、Boostの公式サイトのチケットにこの問題についての記述があった。
#773 (program_options find assert fails with multibyte characters) – Boost C++ Libraries

チケットの状態を見ると既にバグが修正された状態となっていた…

チケット欄の書き込みの流れ



まず、一番初めの7年前の書き込みでは
「マルチバイト文字列については考えたくないから直さないよ」
となっている。

しかし、沈黙から二年(現在から5年前)してまた状態が変わった。
windowsのDebugモードでは使いづらいからこの問題について扱おうぜ!」
という感じでまたこのバグが陽の目を浴びた。

そしてこの問題はソリューション構成が「Debug」かつ、ランタイムライブラリが「Multi-threaded Debug DLL(/MDd)」のみ発現するという流れになっている。そして、このバグは唐突に解決へと向かった。

「問題の行をこいつに置き換えれば大丈夫さ!もし、何か問題があったらもう一回openにしてくれよ」

assert(n == (name.size() - 2*sizeof(std::string::value_type)));

となり、状態がcloseになった。
チケット[58232](Changeset 58232 – Boost C++ Libraries)として修正されたことになった。

しかし、その後もいくつかの投稿がありこの問題が完全には解決されてないようにも見える。

自分の問題へのアプローチ



さて、もちろんこのチケットの内容をみて以下の事を試した。

  1. /MDd から /MTdに変更して、ライブラリを動的リンクから静的リンクへ変更
  2. 「プロジェクト」→「プロパティ」→「全般」タブにある文字セットを「Unicode」↔「マルチバイト」を切り替えてみる

しかし、直らない。

それでも直らないのでソースコードを見てみる。
すると不思議なことに気づいた。

問題の行が古いままになっているのだ…
チケットの内容をみるとこの問題はすでに4年前に直されており、Fixされたものになっているはずなのだが。
そのため、私はソースコードを以下のように変更した。

// assert(n == name.size()-2); // old assertion
assert(n == name.size() - 2*sizeof(string::value_type)); 

よし、もうこの問題は解決だあぁぁあぁぁああぁぁ!!!
しかし、非情にも実行時にエラー!

完全にすがるものがなくなった。
そして、私は最悪の決断を行った。

ソースを以下のように書き換えたのだ。

// assert(n == name.size() - 2*sizeof(string::value_type)); 

無情なコメントアウト
私はこのバグに完全に屈した。
自身の文字コードに対する知識の少なさを呪いながら、私は『Debug』モードの時だけこれに変更されたコードが実行されるようにした。

ああ、悲しきかな。



なぜ私のソースが古かったのか。
prebuild済みのver1.55.0のmsvc-10x64だけこうなっているのか?
そして、prebuild済みのコードからもう一度buildしたのが問題だったのか?
その原因を究明する力も気力も自分には残っていなかったので諦めた。

最後に



最後まで読んで頂きありがとうございました。
結局、何も解決出来てないじゃん!と思った方も多いでしょう。
誰か私の代わりにこのバグを直してくれるとありがたいです。
もし直せない人は私のようにコメントアウトしましょう。