OpenSSL 1.0.2はcrashして良いのです
悪いのはcrashログを吐きまくるMacOS Xではないかな
その後、更に調べたら EXC_BAD_INSTRUCTION例外(SIGILL)はPowerPCの種類を調べるための意図的なものだと分かりました。当該ソースは "crypto/ppccap.c" です。この中の OPENSSL_cpuid_setup() 関数が問題の OPENSSL_ppc64_probe() の呼びだし元ですね。その一部を抜粋すると、
memset(&ill_act, 0, sizeof(ill_act));
ill_act.sa_handler = ill_handler;
ill_act.sa_mask = all_masked;
sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
sigaction(SIGILL, &ill_act, &ill_oact);
if (sizeof(size_t) == 4) {
#ifdef __linux
struct utsname uts;
if (uname(&uts) == 0 && strcmp(uts.machine, "ppc64") == 0)
#endif
if (sigsetjmp(ill_jmp, 1) == 0) {
OPENSSL_ppc64_probe();
OPENSSL_ppccap_P |= PPC_FPU64;
}
} else {
/*
* Wanted code detecting POWER6 CPU and setting PPC_FPU64
*/
}
|
この部分のロジックは以下のとおり。
- SIGILL例外にシグナルハンドラ ill_handler() を設定しておく。
- sigsetjmp() のif文を実行、sigsetjmp()の復帰値は 0 なので OPENSSL_ppc64_probe() が呼び出される。
- OPENSSL_ppc64_probe() で SIGILL例外が発生するとシグナルハンドラ ill_handler() が呼び出される。
- ill_handler() から siglongjmp() で sigsetjmp() のif文に復帰する。
- すると今度は sigsetjmp() の復帰値が 1にになるため、==0 判定が成立せずに if文を抜ける。
- OPENSSL_ppc64_probe() で SIGILL例外が発生しなかった場合は、シグナルハンドラ ill_handler() が呼び出されずにOPENSSL_ppc64_probe()から復帰して来るため、OPENSSL_ppccap_P |= PPC_FPU64; が実行される。
このようにして PowerPCの 64bit命令が実行可能か調べているのですね。この後、同じように Altivec(ベクトル)命令が使用できるか等を調べています。SIGILL例外は意図的に起されていたわけで、バグではなかったのです。
そうなると、明示的にシグナルハンドラを指定しているにも関わらず crashログを吐きまくり、それを繰り返すと動作がおかしくなる MacOS X 10.4.11 Tiger の方に問題があるように思えますね。OpenSSLは様々なプログラムで使用されていますから、それらのプログラムについても crashログが吐き出されており、crashログだけで結構な容量を食っています。
とは言え MacOS X を修正するのは無理ですから、OpenSSL の方で例外を起さないように修正するしかないですね。PowerPC G4前程にするなら、64bit命令なし、Altivec命令ありに決め打ちしてしまって、検査のための命令を実行しないようにソースを修正してしまえば良いのではないかな。
memset(&ill_act, 0, sizeof(ill_act));
ill_act.sa_handler = ill_handler;
ill_act.sa_mask = all_masked;
sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
sigaction(SIGILL, &ill_act, &ill_oact);
if (sizeof(size_t) == 4) {
#ifdef __linux
struct utsname uts;
if (uname(&uts) == 0 && strcmp(uts.machine, "ppc64") == 0)
#endif
/*
if (sigsetjmp(ill_jmp, 1) == 0) {
OPENSSL_ppc64_probe();
OPENSSL_ppccap_P |= PPC_FPU64;
}
*/
} else {
/*
* Wanted code detecting POWER6 CPU and setting PPC_FPU64
*/
}
if (sigsetjmp(ill_jmp, 1) == 0) {
/*OPENSSL_altivec_probe();*/
OPENSSL_ppccap_P |= PPC_ALTIVEC;
/*
if (sigsetjmp(ill_jmp, 1) == 0) {
OPENSSL_crypto207_probe();
OPENSSL_ppccap_P |= PPC_CRYPTO207;
}
*/
}
|
でどうだろう?
PowerPC G5前程なら64bit命令あり、Altivec命令ありに決め打ちで、
memset(&ill_act, 0, sizeof(ill_act));
ill_act.sa_handler = ill_handler;
ill_act.sa_mask = all_masked;
sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
sigaction(SIGILL, &ill_act, &ill_oact);
if (sizeof(size_t) == 4) {
#ifdef __linux
struct utsname uts;
if (uname(&uts) == 0 && strcmp(uts.machine, "ppc64") == 0)
#endif
if (sigsetjmp(ill_jmp, 1) == 0) {
/*OPENSSL_ppc64_probe();*/
OPENSSL_ppccap_P |= PPC_FPU64;
}
} else {
/*
* Wanted code detecting POWER6 CPU and setting PPC_FPU64
*/
}
if (sigsetjmp(ill_jmp, 1) == 0) {
/*OPENSSL_altivec_probe();*/
OPENSSL_ppccap_P |= PPC_ALTIVEC;
/*
if (sigsetjmp(ill_jmp, 1) == 0) {
OPENSSL_crypto207_probe();
OPENSSL_ppccap_P |= PPC_CRYPTO207;
}
*/
}
|
で良いのではないかな?
|