hkoba blog

プログラマーです。プログラミング言語ミーハーです。ツッコミ歓迎です。よろしくどうぞ(能代口調)

とある方のブログでみたスクリプトが、なぜ暴走したのかについて

Twitter で流れてきたリンクで、Perl を勉強中の方のブログが目に止まりました。

note103.hateblo.jp

読んでいて気付いた点があったので、それについて書いてみます。 (最初はコメントで書いていたら文字数制限で途切れてしまったので… 途切れるなら字数制限の警告が欲しい…)

id:note103 様、はじめまして

id:note103 様、はじめまして、興味深く読ませて頂きました。

上記の現象のうち、 Perl 関連の部分について、多分こうではないか?と気付いた所があるので書かせて下さい。

なぜこのスクリプトは暴走したのか

第一に、 Sample.pm の中に間違って init(); が書かれた状態で何が起きるかです。 この場合、 単に use や require で他のスクリプトから読み込んだだけで Sample::init() の実行が始まる ことになります。 このことは以下のようにして確認できます。

perl -e 'require Sample'

第二に、状況からの推測ですが、 MacVim の syntastic (perl の構文間違いの自動検査) が呼び出した perl -wc main.pl の中で Sample.pm が読み込まれるので、そこで Sample::init() が呼ばれて入力待ちが発生。 syntastic が応答しない→ MacVim も固まる、となったのではないかと。

ここから先は、ご自身で書いておられる通り、 "具体的には最後のelse文の中で同じサブルーチンを呼び出しているのが悪手" となり、無限に再帰呼出しを行う状況だったのではないかと。

試しに

perl -we 'use Sample' </dev/null

と端末で打ってみると、無限ループが再現できるはずです。 (端末からなら ^C で停止させることが出来ます。)

あと、この Sample::init で使っている

chomp($bar = <STDIN>);

は、perl の普通の入力待ちループ

while ($bar = <STDIN>) {...}

と違って defined 検査が足りていないため、 eof が来ても停止しない、という点も、無限ループになった要因の一つですね。

ではこの辺りで失礼します〜