PerlIOのメモリアロケーション

PerlIOのデータ構造の前に。
CレベルのPerlIO*については、PerlIOシステムがメモリ管理をしてくれる。そのメモリ管理を行うのがPerlIO_allocate()で、これが呼び出されると利用していないPerlIO*ポインタを探して返す。利用されていないPerlIO*ポインタがなければ、malloc(3)でまとめてメモリを割り当てる。
この「利用しているか否か」というのが曖昧な定義となっており、現状では少なくとも「Perlからアクセスできるか否か」という意味ではない。したがって、この曖昧な定義を利用して奇妙な動作を引き起こすことが出来る。
以下、そのコードを示す。

#!perl -w
use strict;
use 5.010_000;
use PerlIO::Util;

open my $fh1, '<', \'';
1 while $fh1->pop_layer();
{
	open my $fh2, '<', '/dev/null';

	say 'fh1 ', $fh1->inspect();
	say 'fh2 ', $fh2->inspect();
}
say 'fh1 ', $fh1->inspect();

実行結果:

fh1  PerlIO 0x1003e228
  0x10066c40:perlio(3) CANREAD FASTGETS
  0x10044838:unix(3) CANREAD OPEN

fh2  PerlIO 0x1003e228
  0x10066c40:perlio(3) CANREAD FASTGETS
  0x10044838:unix(3) CANREAD OPEN

fh1  PerlIO 0x1003e228
  (Invalid filehandle)

$fh1と$fh2が持つPerlIO* fpが同じ値(0x1003e228)になっている。
"1 while $fh1->pop_layer();"によって$fh1の実体であるPerlIO* fpが空(PerlIO_valid(fp)が偽)になるのだが、その結果$fh1の持つPerlIO* fpはPerlIOアロケータに「利用されていない」と判断される。その結果として、PerlIOアロケータが$fh2のためのPerlIO*を要求されたときに、$fh1の持つPerlIO* fpを返す。そのため元々無効なファイルハンドルであった$fh1までも、一時的に$fh2と同じく有効になるが、$fh2のスコープが終わり自動的にクローズされると、$fh1もまた無効なファイルハンドルに戻る。
そして、その後も新しいファイルハンドルを開くと、$fh1はその新しいファイルと同一になる。