libsvm を使用する Python パッケージをいくつかの実稼働サーバーに移植していて、奇妙なセグメンテーション エラーに遭遇し、それを ctypes 関数ポインターに追跡しました。ctypes ラッパーが失敗した場所と、これがディストリビューション固有の問題であるかどうかを判断しようとしています。
私がこれを実行しているシステムは、ほとんど何もインストールされていない非常にクリーンな仮想マシンです: Solaris 5.11 amd64 pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86 Python 2.7.2
問題の説明と、ctypes に絞り込む方法について説明します。void (*print_func)(const char *)
libsvm では、ポインターを関数に渡すことで印刷関数を指定できますsvm_set_print_string_function
。NULL ポインターのデフォルトは、stdout に出力することです。ここで興味深いのは、libsvm の Python ラッパー (他のさまざまなシステムで正常に動作する) が、次の方法でサイレント モード (印刷なし) を要求するときに、そのような関数ポインターを作成することです。
PRINT_STRING_FUN = CFUNCTYPE(None, c_char_p)
def print_null(s):
return
if argv[i] == "-q":
self.print_func = PRINT_STRING_FUN(print_null)
libsvm.svm_set_print_string_function(self.print_func)
svm_train
クワイエット モードを設定すると、libsvm は関数ポインタを受け入れますが、seg faultを呼び出すと数秒後にハングします。引数関数ポインターを作成しvoid *
てから、それを関数ポインターにキャストして同じ結果を得ようとしました。つまり、PyStringObjectconst char *
からの変換ではありませんでした。const char *
次に、関数ポインターをライブラリー自体のノーオペレーションに設定する C++ 関数を最終的に作成しました。
void print_null(const char *) {}
void svm_set_print_null() {
svm_set_print_string_function(&print_null);
}
セグメンテーション違反なしで期待どおりに機能しました。これにより、関数ポインター変換の内部ポイントで ctypes が失敗していると思います。ctypes のソース ファイルを調べても明らかなことはわかりませんが、ctypes を明示的に扱ったことはあまりないので、バグがどこにあるのかを絞り込むのは困難です。
今のところ、ライブラリ追加ソリューションを使用できますが、リターンをサイレントに処理したい場合は、実際に関数ポインタを libsvm に渡すことができる必要があります。さらに、問題の真の根本原因が何であるかを知らずにそのような回避策を実装する必要がある場合、安定性について安心することはできません。
Solaris 上の libsvm 印刷関数、または特に Solaris 上の Python の ctypes 関数ポインターで問題が発生した人はいますか? Solaris のこのような問題について、オンラインで検索しても何も見つかりませんでした。私はライブラリ呼び出しをいじって、いくつかの関数処理ライブラリを作成して、失敗の正確な境界を見つけることを計画していますが、他の誰かの入力により、デバッグ テストを 1 日か 2 日節約できるかもしれません。
アップデート
この問題は、Solaris 5.11 の 32 ビット バージョンでも再現可能です。