[kansaipm] Re: [kansaipm] 暗黙のuse utf8

Dan Kogai dankogai at dan.co.jp
Sun Oct 5 07:52:44 CDT 2003


On Sunday, Oct 5, 2003, at 18:48 Asia/Tokyo, Yasushi Nakajima wrote:
>  ちょうど弾さんが顔を出して下さったので、弾さん向けの(^^)質問を一つ。
>
>  以下、Perl5.8(テストはWindows上の5.8.0でやってます)での話。
>
>  いま、PDFJのXMLフロントエンドであるXPDFJが、ようやくリリースに近づいて
> きたのですが、その中で「明示的にuse utf8;していないコードをeval(正確に
> はSafe::reval)するときに、暗黙にuse utf8;されることがある」という事態に
> 突き当たって悩んでいます。どうもutf8::SWASHNEWなんかを呼んでいるようです。

うーん、なかなか高度な奴ですね。encodingもそうですが、pragmaというのは、moduleとして提供されはしていますが、あくまで 
pragmatic な役割をすることもあり、この場合はその影響は可能な限りlexical 
scopeとして処理されるようになっています。そうでない場合には perldoc に警告文が書いてあります(i.e. encoding).

それで、utf8 pragmaなのですが、これは lexical scope です。有名な strict 
もそうです。ですから暗黙に、例えば別moduleがすでに一旦useしている場合が多く、通常はそれを気にする必要は全くないはずなのですが。

>  まだ、どんな時に起きるのか、短い再現コードにまで追いつめられていないの
> ですが、実行するコードを少し変えただけで起きたり起きなかったりです。

実際のcodeを見ていないのでなんとも言えないのですが、いづれの場合も utf8.pm はすでに use 
されているように見えます。それ自体は多分中嶋さんも問題にはしていないと思いますが、utf8::SWASHNEWというのは、実は utf8.pm 
内部ではなく、utf8_heavy.pl という外部scriptに存在しています。

# utf8.pm の全て
package utf8;

$utf8::hint_bits = 0x00800000;

our $VERSION = '1.00';

sub import {
     $^H |= $utf8::hint_bits;
     $enc{caller()} = $_[1] if $_[1];
}

sub unimport {
     $^H &= ~$utf8::hint_bits;
}

sub AUTOLOAD {
     require "utf8_heavy.pl";
     goto &$AUTOLOAD if defined &$AUTOLOAD;
     Carp::croak("Undefined subroutine $AUTOLOAD called");
}

1;
# 本当にこれだけ!

見ての通り、未定義の utf8::function() が呼ばれた時に、 utf8_heavy.pl 
が読まれるような仕組みになっていて、具体的には、regex中のUnicodeを扱う時に呼ばれます。普通は

>  安全のためにSafe環境はpermit_only(':default')にして、その中で実行した
> いのですが、そうするとrequireがダメなので、上記の現象が起こると当然エラー
> になります。実行したいコード自体は、変数を使った数式の評価ができればよく、
> 外部とやりとりする機能は殺しておきたいので、requireを許可したくはありま
> せん。

しかし、やはりpragmaは許可をしておかないとこれ以外でも結構大変ですよね。というわけで perldoc Safe 
を見てみると、こういう方法で可能にしておくというのは考えられます。

$cpt = new Safe;
sub wrapper {
     use utf8 ();
     require "utf8_heavy.pl";
}
$cpt->share('&wrapper');
$cpt->reval("wrapper()");

>  質問は、いったいどんな条件の時に上記の現象が起こるのか、抑止する方法が
> あるのかどうか、です。
>
>  書き忘れましたが、実行するコードはXMLデータ中に埋め込まれていて、
> XML::Parserで読み込んでいるので、utf8になった状態でrevalに渡されています。

ああ、多分これだ!状況によってutf8_heavy.plが読み込まれるかどうかというのは、読み込んだXMLデータ中に、<本当の>、すなわち 
\x80 よりもordが大きな文字が含まれるかどうかによって決まるわけです。すなわち

$cpt->reval(qq/print "Hello, World\n"/);   # OK
$cpt->reval(qq/print "世界にようこそ\n"/); # NG

ですから、これはもう素直に上記のような方法で、先に utf8_heavy.pl をあらかじめ require しておいた方がいいでしょう。

Dan the Camel Vet




More information about the Kansai-pm mailing list