SheWolf has asked for the wisdom of the Perl Monks concerning the following question:

Hi folks,

I've recently had to dive back into C to link some old C code with Perl.

My basic problem is this:
I have C code that mallocs memory (for a string, specifically)
In my XS I have this declaration to mimic the one in C
char * proc_desc(a,b) char * a char b OUTPUT: RETVAL

I get the string back in Perl, but the memory for the string is never released when the receiving variable goes out of scope.

I'm trying to understand the XS world for my glue logic, but haven't had a lot of success. I've been looking into using sv_2mortal, but every string example I find allocates the string in the XS code.

So, my question is, how do I tell perl that it must deallocate the memory C handed back to it? I feel like this is such a simple, obvious thing to do.

Replies are listed 'Best First'.
Re: Perl, C and deallocation responsibility
by etj (Priest) on Apr 26, 2023 at 23:59 UTC
    I believe (having been dabbling in XS stuff recently for PDL and PDL::OpenCV) that your best bet here would be to return an SV* from your XS function. Then your CODE section would do:
    char *tmp = proc_desc(a,b); sv_setpv(RETVAL, tmp, 0); free(tmp);
      A belated further thought: you could typedef the return type (char*) to a new type-name, then have a typemap entry that handles the OUTPUT of that with that code-snippet: https://perldoc.perl.org/perlxstypemap.

        Thanks for those suggestions. I'll see if I can get time to play with them today.

        Given time constraints I came up with a much hackier solution (static pointer to a string which is used every call. Not thread safe, but in this case, not an issue), but I want to do it cleanly!

Re: Perl, C and deallocation responsibility
by Marshall (Canon) on Apr 29, 2023 at 06:31 UTC
    There is a typedef mechanism that translates standard C types into an appropriate Perl type. I haven't used that myself. I have only written XS code using the Perl types directly. I find it less confusing as to who is doing what in terms of memory management. You will need to use Perl functions to allocate memory if you expect Perl to manage that memory. Of course, Perl will never release any memory back to the O/S, but it will reuse it for its own purposes!

    See Inline Cookbook Pod for the greeting() program (shown below). This code works on my machine and discusses memory management. I would use SV types for input to your proc_desc() subroutine and manipulate them appropriately. Perhaps allowing for something more complex than just an 8 bit ASCII string (UTF-8?).

    I think you will wind up with 2 input SV's and one output SV: SV* proc_desc(SV* a, SV* b) { ....code... }

    use strict; use warnings; use Inline 'C'; print greeting('Ingy'); __END__ See https://metacpan.org/dist/Inline-C/view/lib/Inline/C/Cookbook.pod and the example for "greeting" subroutine. "I would urge you to stay away from mallocing your own buffer. Just us +e Perl's built in memory management. In other words, just create a new Perl string scala +r. The function newSVpv does just that. And newSVpvf includes sprintf functionality. The other problem is getting rid of this new scalar. How will the ref +count get decremented after we pass the scalar back? Perl also provides a functi +on called sv_2mortal. Mortal variables die when the context goes out of scope. I +n other words, Perl will wait until the new scalar gets passed back and then decrement the + ref count for you, thereby making it eligible for garbage collection. See perldoc perlgut +s. In this example the sv_2mortal call gets done under the hood by XS, be +cause we declared the return type to be SV*." __C__ SV* greeting(SV* sv_name) { return (newSVpvf("Hello %s!\n", SvPV(sv_name, PL_na))); }
        Thanks for the info!
        I haven't seen memory go back to the O/S, but I haven't had the need to look closely on Win 10. The last time I got really anxious about memory was when developing a Perl application for Win XP. I had a memory budget for that one. Often for Perl applications, I see memory usage approach a limit in an asymptotic way and then just stay flat forever. Of course, mileage varies a lot depending on the application's needs.

        I think in the context of the OP's question, one question is whether anybody is going to do anything to either free or reuse the memory allocated for the char*. I was happy to have found an explicit statement about what is going to happen if the listed memory allocation routine is used. I was and am not at all clear what actually happens with the char* declaration (instead of an SV that Perl will reference count upon). There is obviously some type mangling that happens underneath the covers, but I'm not sure how.

        BTW, I have found that SQLite is very good at returning memory if you adjust its memory usage during run time. Giving an SQL indexing operation a lot of memory can have a huge positive performance effect. And then shrink down memory size for normal usage.

      Thank you. I hadn't thought of doing that. I think I was stuck on the whole 'must be a PV' thing.

      I'll try to play with that when I can!

        I would say what's most relevant in your decision is how Perl-dependent you want your C code to be:
        • If you're comfortable with it being Perl-dependent, you would probably want to have all memory allocation/management done by Perl, using probably-mortal SVs, and PVs from the start.
        • If you want to maintain the C code as purely C, then you can use the typemap stuff in the various notes here to copy the C-created data into Perl-land, and then free the C-allocated memory.