字符串的Perl XS内存处理

时间:2015-07-31 18:57:19

标签: perl memory-leaks xs

我有一个像这样的XSUB:

char *
string4()
CODE:
    char *str = strdup("Hello World4");
    int len = strlen(str) + 1;
    New(0, RETVAL, len, char);
    Copy(str, RETVAL, len, char);
    free(str);
OUTPUT:
    RETVAL

但是这显示为内存泄漏,在New(),valgrind中,如果我在循环中运行它,常驻内存将继续增长。

如果我也使用这个,我也会得到同样的东西:

char *
string2()
CODE:
    char *str = strdup("Hello World2");
    RETVAL = str;
OUTPUT:
    RETVAL

我可以通过执行以下操作来防止泄漏和增加内存大小:

char *
string3()
PPCODE:
    char *str = strdup("Hello World3");
    XPUSHs(sv_2mortal(newSVpv(str, 0)));
    free(str);

但是这个解决方案的问题是,当我使用-Werror进行编译时,我收到以下警告/错误。

test.c: In function ‘XS_test_string3’:
/usr/lib/x86_64-linux-gnu/perl/5.20/CORE/XSUB.h:175:28: error: unused variable ‘targ’ [-Werror=unused-variable]
 #define dXSTARG SV * const targ = ((PL_op->op_private & OPpENTERSUB_HASTARG) \
                            ^
test.c:270:2: note: in expansion of macro ‘dXSTARG’
  dXSTARG;
  ^
test.c:269:9: error: unused variable ‘RETVAL’ [-Werror=unused-variable]
  char * RETVAL;

使用未使用的RETVAL生成c文件:

XS_EUPXS(XS_test_string3); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_test_string3)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
    char *  RETVAL;
    dXSTARG;
#line 61 "test.xs"
    char *str = strdup("Hello World3");
    XPUSHs(sv_2mortal(newSVpv(str, 0)));
    free(str);
#line 276 "test.c"
    PUTBACK;
    return;
    }
}

那么有更好的方法来处理在XS中返回已分配的字符串吗?有没有办法使用RETVAL返回字符串并释放内存?我感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

Among other problems[1], your first snippet allocates memory using New, but never deallocates it.

Among other problems, your second snippet allocates memory using strdup, but never deallocates it.

The underlying problem with your third snippet is that you claim the XS function returns a value and it doesn't. That value would have been assigned to RETVAL, which is automatically created for that very purpose. The variable won't be created if you correctly specify that you don't return anything.

void
string3()
PREINIT:
    char *str;
PPCODE:
    str = strdup("Hello World3");
    XPUSHs(sv_2mortal(newSVpv(str, 0)));
    free(str);

or just

void
string3()
PPCODE:
    XPUSHs(sv_2mortal(newSVpv("Hello World3", 0)));

Note that I moved your declarations out of PPCODE. In C, declarations can't appear after non-declarations, and the code in PPCODE can appear after non-declarations (depending on the options used to build Perl). Declarations belong in PREINIT. You could also use curlies around the code in PPCODE.


  1. One of them is the use of New. You shoudln't be using New. New was deprecated in favour of Newx ages ago. New hasn't even been in the documentation for as long as I can remember.