Reputation: 185
I have an XSUB like this:
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
But this shows up as a memory leak, on the New(), in valgrind and if I run it in a loop the resident memory will continue to grow.
I get the same thing if I use this one too:
char *
string2()
CODE:
char *str = strdup("Hello World2");
RETVAL = str;
OUTPUT:
RETVAL
I'm able to prevent the leak and the increasing memory size by doing:
char *
string3()
PPCODE:
char *str = strdup("Hello World3");
XPUSHs(sv_2mortal(newSVpv(str, 0)));
free(str);
but the problem with this solution is that when I compile with -Werror I get the following warnings/errors.
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;
the c file gets built with an unused RETVAL:
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;
}
}
So is there a better way to handle the returning of allocated strings in XS? Is there a way to return the string using RETVAL and free the memory? I appreciate any help.
Upvotes: 0
Views: 473
Reputation: 385897
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
.
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.Upvotes: 1