gpt4 book ai didi

perl - 为什么这个返回 PerlIO* 的 XS 代码会泄漏?

转载 作者:行者123 更新时间:2023-12-04 11:55:58 24 4
gpt4 key购买 nike

我正在尝试编写一些 XS 代码来公开库的片段
Perl 代码作为可以写入的流接口(interface)。这get_stream下面的函数应该是一个构造函数
准备并返回一个 PerlIO 对象。我想我只需要WriteClose方法,所以我将所有其他功能槽留空。

typedef struct {
struct _PerlIO base;
mylib_context* ctx;
} PerlIOmylib;

/* [...] */

PERLIO_FUNCS_DECL(PerlIO_mylib_funcs) = {
.fsize = sizeof(PerlIO_funcs),
.name = "mylib",
.size = sizeof(PerlIOmylib,
.Write = mylib_write,
.Close = mylib_close,
};

/* XS below */

PerlIO*
get_stream (SV* context_obj)
CODE:
mylib_context* ctx = (mylib_context*) SvIV (SvRV (context_obj));
PerlIO* f = PerlIO_allocate (aTHX);
f = PerlIO_push (aTHX, f, PERLIO_FUNCS_CAST(&PerlIO_mylib_funcs), "a", NULL);
PerlIOSelf(f, PerlIOmylib)->ctx = ctx;
PerlIOBase(f)->flags |= PERLIO_F_OPEN;
RETVAL = f;
OUTPUT:
RETVAL

当我像这样使用提供的界面时......
{
my $fh = MyLib::get_stream($lib_ctx);
print $fh "x" x 300;
}

... mylib_write函数被调用,所以我还没有完全
到目前为止搞砸了。 (我通过插入调试 printf 验证了这一点
声明。)但是,我希望 PerlIO 对象在 $fh超出范围,就像正常工作的方式一样 open 创建的文件句柄.但目前, mylib_close函数仅在解释器关闭期间调用。

直接调用 close工作正常,设置 $fhundef
不是。

更新:根据 ikegami 的建议,我使用了 Devel::Peek::Dumpsv_dump发现句柄返回 get_stream功能是“房车”
指向 SV = PVGV(...) . glob ( PVGV ) 有它的
引用计数器设置为 3 这似乎不正确。

我添加了
CLEANUP:
SvREFCNT_dec (SvRV (ST(0)));
SvREFCNT_dec (SvRV (ST(0)));

对症下药: close $fh 时调用函数
在 block 的末尾超出范围。但我还是不太懂
了解根本问题。

这是为 OUTPUT 生成的 C 代码部分:
ST(0) = sv_newmortal();
{
GV *gv = newGVgen("MyLib");
if (do_open(gv, "+<&", 3, FALSE, 0, 0, RETVAL) )
sv_setsv(ST(0), sv_bless(newRV((SV*)gv), gv_stashpv("MyLib",1)));
else
ST(0) = &PL_sv_undef;
}
XSRETURN(1);

GV 的引用计数如何最终达到 3?

最佳答案

如果 close在全局销毁时调用,这意味着您的句柄在全局销毁时仍然存在。你在泄密!

在 C/XS 代码中,可以使用 sv_dump(sv)将标量转储到标准错误。在 Perl 代码中,您可以使用 Devel::PeekDump获得相同的功能。这将向您显示引用计数。

在回答你的新问题时,

您有三个分配,但只有一个释放(来自 sv_2mortal 的延迟一个)。

  • gv : 指针总是被丢弃。内存泄漏!

    您可以减少 gv 的 refcnt出错时,或者在使用 newRV_inc 后无条件地减少 refcnt打开成功时将所有权“转移”给 RV。
  • SV 来自 newRV : 指针总是被丢弃。内存泄漏!

    为什么不直接退回而不是复制呢?只需将其标记为 mortal 以使 Perl 在调用者获取它后减少其 refcnt。

  • 固定的:
    {
    GV *gv = newGVgen("MyLib");
    if (!do_open(gv, "+<&", 3, FALSE, 0, 0, RETVAL) ) {
    SvREFCNT_dec(gv);
    XSRETURN_UNDEF;
    }

    ST(0) = sv_2mortal(sv_bless(newRV_noinc((SV*)gv), gv_stashpv("MyLib",1))));
    XSRETURN(1);
    }

    关于perl - 为什么这个返回 PerlIO* 的 XS 代码会泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12729545/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com