Perl 5.24 - Can't use 'defined(%hash)' エラー

弊サイト http://yasuda.homeip.net/ ではサイト内の検索のために Unicode msearch を設置している。FreeBSD 11.1-RELEASE への OS バージョンアップに伴い,Perl のバージョンを 5.24.1 にアップグレードしたら,msearch の実行で,End of script output before headers とのエラーが出て検索できなくなっていた。

Apache24 のエラーログを確認する。

[Tue Sep 19 22:45:31.464098 2017] [cgi:error] [pid 96126] [client 192.168.1.6:52
057] AH01215: Can't use 'defined(%hash)' (Maybe you should just omit the defined
()?) at ./jcode.pl line 684.: /usr/local/www/apache24/cgi-bin/msearch/msearch.cg
i, referer: http://yasuda.homeip.net/
[Tue Sep 19 22:45:31.464137 2017] [cgi:error] [pid 96126] [client 192.168.1.6:52
057] AH01215: Compilation failed in require at ./utfjp.pl line 68.: /usr/local/w
ww/apache24/cgi-bin/msearch/msearch.cgi, referer: http://yasuda.homeip.net/
[Tue Sep 19 22:45:31.464168 2017] [cgi:error] [pid 96126] [client 192.168.1.6:52
057] AH01215: Compilation failed in require at /usr/local/www/apache24/cgi-bin/m
search/msearch.cgi line 37.: /usr/local/www/apache24/cgi-bin/msearch/msearch.cgi
, referer: http://yasuda.homeip.net/
[Tue Sep 19 22:45:31.464310 2017] [cgi:error] [pid 96126] [client 192.168.1.6:52
057] End of script output before headers: msearch.cgi, referer: http://yasuda.ho
meip.net/

msearch.cgi が 37 行目で utfjp.pl をコールし,その utfjp.pl が 68 行目で jcode.pl をコールし,その jcode.pl が 684 行目でエラーとなって停止,ってのがバックトレース。つまりは,AH01215: Can't use 'defined(%hash)' (Maybe you should just omit the defined ()?) at ./jcode.pl line 684. が根本原因を指し示している。

ハッシュ変数に対して defined で検査をかけるのは,最近の Perl では禁止となったようである。ん? なんか前も同じような問題に遭って手を打たなかったか? ま,いいや。というわけで,jcode.pl プログラムについて,問題となった 684 行目以外にも defined %xxx で検査しているところを探り当て,問題は以下のコードの部分だけだと判断した。

 
sub z2h_euc {
    local(*s, $n) = @_;
    &init_z2h_euc unless defined %z2h_euc;
    $s =~ s/($re_euc_c|$re_euc_kana)/
    $z2h_euc{$1} ? ($n++, $z2h_euc{$1}) : $1
    /geo;
    $n;
}
 
sub z2h_sjis {
    local(*s, $n) = @_;
    &init_z2h_sjis unless defined %z2h_sjis;
    $s =~ s/($re_sjis_c)/$z2h_sjis{$1} ? ($n++, $z2h_sjis{$1}) : $1/geo;
    $n;
}

対策は,defined %z2h_euc%z2h_euc とするように,defined を削除するだけ。エラーメッセージが Maybe you should just omit the defined ()? と推察するとおり,ということだ。訂正後の上記コードは以下のとおり。これで msearch は動くようになった。

 
sub z2h_euc {
    local(*s, $n) = @_;
    &init_z2h_euc unless %z2h_euc;
    $s =~ s/($re_euc_c|$re_euc_kana)/
    $z2h_euc{$1} ? ($n++, $z2h_euc{$1}) : $1
    /geo;
    $n;
}
 
sub z2h_sjis {
    local(*s, $n) = @_;
    &init_z2h_sjis unless %z2h_sjis;
    $s =~ s/($re_sjis_c)/$z2h_sjis{$1} ? ($n++, $z2h_sjis{$1}) : $1/geo;
    $n;
}

それにしても,Perl の新バージョンは正規表現の検査についても堅苦しくなっている。これからも既存のコードについていろいろ出てきそうである。んー。

付記:その後,Unicode msearch のページをよく見たら,上記問題対策を含む Perl 5.22 / 5.24 対応版 msearch Version 1.52 (U5) が出ていた。こちらを適用するのが正しい方法である。失礼しました。