恐怖! 64bitと0と可変長引数の組み合わせ
32bit用に書かれたC++のプログラムを
64bit環境で動かそうとした時にハマったのでメモ。
void GetParam(const char* key, int size, ...) { ... for (int i = 0; i < size; ++i) { int* var = va_arg(va, int*); if (var) *var = values[i]; } ... } ... GetParam("foo", 4, &bar, 0, &baz, 0); // ここでsegmentation fault ...
上記のプログラムを動かしたらsegmentation faultで死んでしまいました。
if (var) *var = values[i];
のあたりが怪しいと目星をつけて調べてみると、
なんということでしょう。var
の値が0であると期待している箇所で、
0x7fffffff00000000といういかにも怪しい値が入っていました。
恐らく、可変長引数を使っているため、コンパイラは引数の型が分からず、
0
を32bitの整数として扱ってしまったのでしょう。
0をNULLに書き換えたら無事動きました。
「C++ではNULLと0は等価」だと思っていたのですが、
少なくても可変長引数が絡んでくる場合は異なるようです。恐ろしや。
呼出側のNULLの書き方が悪かったんでしょ。ふつーすぎる。
現在のC++ならnullptrキーワードがベストというゴタクはさておき、使ったコンパイラはGCCですよね?
GCCでは、NULLマクロの結果がポインタと同じサイズになるよう、こういう小細工が仕掛けられています。
http://www.wdic.org/w/TECH/__null