Perl 在XS代码中添加空引用时泄漏
我正在尝试做一个与此类似的XS:Perl 在XS代码中添加空引用时泄漏,perl,memory-leaks,reference,garbage-collection,xs,Perl,Memory Leaks,Reference,Garbage Collection,Xs,我正在尝试做一个与此类似的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文件:
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
生成的默认文件)
重点是:
作为参数传递给构造函数的基引用永远不会泄漏李>
用sv2motal(newRV_noinc((sv*)newHV())在XS代码内部创建的基也不会泄漏李>
使用newRV_noinc(sv_2mortal((sv*)newHV())
创建的基将泄漏(并最终导致臭名昭著的尝试在全局销毁期间释放未引用的标量:sv 0xdeadbeef
消息)
是否有任何原因使sv\u2mortal(newRV\unoinc(…)
不同于newRV\unoinc(sv\u2mortal(…)
?我只是做错了吗?sv\u 2mortal
是一个延迟的refcount递减。(这发生在调用方有机会获得引用或复制它之后。)在这篇文章中,我将给出ref计数,就像sv2mortal
立即递减一样,但将使用星号(“*”)来表示这一点
以下代码使引用无效:
sv_2mortal(newRV_noinc((SV*)newHV()))
所以
哈希的REFCNT=1。这很好,因为您创建的引用保留了对它的引用
该引用的REFCNT=0*。这是好的,因为没有任何引用它
下面的代码将使散列无效:
newRV_noinc(sv_2mortal((SV*)newHV()))
所以
散列的REFCNT=0*。这是错误的,因为您创建的引用保留了对它的引用。这将导致过早释放(这就是为什么在释放引用时会出现“尝试释放未引用的标量”)
该引用的REFCNT=1。这是不好的,因为没有任何引用它。这是个漏洞
非常感谢@ikegami,这件事困扰了我好几个月。顺便问一下,有没有更合适的方法来创建XS代码内部的引用?