私はこれに相当する XS を実行しようとしています:
package RefTestPP;
use strict;
use warnings;
sub new {
my ($class, $self) = (@_, {});
return bless $self, $class;
}
1;
この種のコンストラクタは、 として呼び出されたときにそのベースを「自動有効化」するRefTestPP->new()
か、 のように指定された参照をベースとして使用することになっていRefTestPP->new({ stuff => 123 });
ます。
ただし、説明のつかないリークが発生しています。これが私のRefTest.xs
ファイルです:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = RefTest PACKAGE = RefTest
PROTOTYPES: ENABLE
void
new(sclass="RefTest", base=sv_2mortal(newRV_noinc((SV *) newHV())))
const char *sclass
SV *base
PREINIT:
HV *stash;
PPCODE:
stash = gv_stashpv(sclass, 0);
ST(0) = sv_bless(base, stash);
XSRETURN(1);
void
new_leaky(sclass="RefTest", base=newRV_noinc(sv_2mortal((SV *) newHV())))
const char *sclass
SV *base
PREINIT:
HV *stash;
PPCODE:
stash = gv_stashpv(sclass, 0);
ST(0) = sv_bless(base, stash);
XSRETURN(1);
そして、RefTest.t
リークを検出するファイル:
use strict;
use warnings;
use Devel::Leak;
use Test::More;
BEGIN { use_ok('RefTest') };
sub test_leak (&$;$) {
my ($code, $descr, $maxleak) = (@_, 0);
my $n1 = Devel::Leak::NoteSV(my $handle);
$code->() for 1 .. 1000;
my $n2 = Devel::Leak::CheckSV($handle);
cmp_ok($n1 + $maxleak, '>=', $n2, $descr);
}
# OK
test_leak { my $ref = RefTest->new() or die }
'first sv_2mortal(); then newRV_noinc()', 2;
# also OK
test_leak { my $ref = RefTest->new_leaky({}) or die }
'first sv_2mortal(); then newRV_noinc(); pre-init base', 2;
# leaks!
test_leak { my $ref = RefTest->new_leaky() or die }
'first newRV_noinc(); then sv_2mortal()', 2;
done_testing 4;
(適切なコンパイルに必要な残りのファイルは、によって生成されるデフォルトですh2xs -A -n RefTest
)
ポイントは:
- コンストラクターにパラメーターとして渡された基本参照は決してリークしません。
- XSコード内で作成されたベース
sv_2mortal(newRV_noinc((SV *) newHV()))
もリークしません。 - で作成されたベース
newRV_noinc(sv_2mortal((SV *) newHV()))
はリークします (そして最終的にはグローバルな破壊中に悪名高いAttempt to free unreferenced scalar: SV 0xdeadbeef
メッセージを引き起こします)。
sv_2mortal(newRV_noinc(...))
と異なる理由はありますnewRV_noinc(sv_2mortal(...))
か?私は単にそれを間違っていますか?