MacOSX で Security Update 2009-001したら Perl がこけるようになった。 緊急対策に慌てる。

...
Encode object version 2.12 does not match bootstrap parameter 2.26
at /System/Library/Perl/5.8.8/darwin-thread-multi-2level/XSLoader.pm line 94.
Compilation failed in require at /Library/Perl/Noon/Persistent/DBI.pm line 40.
...

Encode のオブジェクトが XSLoader に文句を言われている。
Compilation failed を起こしたモジュールを見るとたしかに use Encode; の行でこけている。

てことは use Encode してるモジュール、全滅中...

MacOSX Leopard で Perl のコアモジュールを CPAN install でアップデート、 つまりコアモジュールを上書きしちゃったりしてると、やばいらしい。 Security Update がさらに上書きするであろうから、整合がとれなくなりそうなのは、わかる。 こういう事態を避けるなら「Perl を二系統にしておく」のが筋ですね。

MacOSX 標準の /System/Library/Perl/ はいじらない。 標準と自前で Perl を分ける。 普通の unix なら自前ものは /usr/local/bin/, /usr/local/lib/ に入れるのが筋。

時間がない。とりあえず、Encode の最新版 2.29 を force install してみたりして。

% sudo -s
# cpan
cpan> get Encode
cpan> make Encode
cpan> test Encode (たぶん NOT OK になるはず)
cpan> force install Encode
cpan> quit
# apachectl stop
# apachectl start

とにかく回避できた模様。うーん、気持ちは悪い。 あせった。

話は変わって、Encode の使いこなし。

どたばたついでにフレームワーク NOON のコードを見直した。 あちこちのクラスで use Encode; するのをやめた。 use Encode; するクラスをひとつだけにする。 アプリケーションが Encode のオブジェクトをひとつ持っておくようにする。 Encode をよく使うクラスでは2倍から3倍速くなった。

Encode の最適解

Encode を aggregate

package App;
use strict;
use warnings;
use Encode;

sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    my $self = { @_ };
    bless($self, $class);
    $self->{encode} = Encode::find_encodings('utf8');
    return $self;
}

sub hello_world {
    my ($self, $noise_from_outerspace) = @_;
    my $e = $self->{encode};
    my $string = $e->decode($noise_from_outerspace);
    $string = do_something($string);
    my $octets = $e->encode($string);
    print $octets, "\n";
}

Encode 作法

とにかくさっさと decode してしまっておく。
外へ出す直前に encode すればいい。

各クラスは引数のデータが decode されてることを前提に仕事をする。 decode されてないデータなんか渡してくるほうが悪いと考える。 外へ出す用事があればその都度 encode する。

use Encode;
my $e = Encode::find_encodings('utf8');
my $string = $e->decode($octets);
$string = do_something($string);
$octets = $e->encode($string);
Dan the Encode Maintainer writes: Encodeでは文字コード名の名前解決もしている。 "sjis"も"Shift_JIS"も同じに扱うためには、 当然なんらかの形でこれらが同じであることを判定しなければならない。 それを担うのが、Encode::find_encoding()だ。 実はこの Encode::find_encoding()、 返すのは正規化された名前ではなくオブジェクトである。 そして、実のところこのオブジェクトこそが 実際の(en|de)codeを行うtranscoderなのである。 Encodeは適切に使えばかなり高速なのである。 find_encoding()を使ったテクニックは意外とまだ知られていないので、 これを機会に紹介してみた。 Encode 2.20でもこのテクニックをPODで紹介している。

参考文献:
Mac OS X Security Update 2009-001 might break your Perl (CPAN) http://bulknews.typepad.com/blog/2009/02/mac-os-x-security-update-2009001-breaks-perl-cpan.html
MacのSecurity Update 2009-001でperlが動かんくなった http://journal.soffritto.org/entry/334
perl tips - Encodeを速く使う方法 http://blog.livedoor.jp/dankogai/archives/50815457.html
perl - Mac OS X - perlをDIYする http://blog.livedoor.jp/dankogai/archives/51177425.html
perl - EncodeでXSSを防ぐ http://blog.livedoor.jp/dankogai/archives/51184112.html

topic: perl
first posted: 2009-02-13 16:44:45
last modified: 2009-03-05 20:55:10