in reply to FFI::Platypus: Replace malloc with GC_MALLOC?

The issue is that you don't want to forget to free the buffer.

Another approach is to not use FFI directly, but hide the glue in a module, where you could use an END block to ensure it's freed on exit.

package My::StringUtils; use strict; use warnings; use Export qw( import ); use FFI::Platypus 2.00; our @EXPORT_OK = qw( string_reverse ); my $ffi = FFI::Platypus->new( api => 2, lib => './string_reverse.so', ); $ffi->attach( string_reverse => [ 'string' ] => 'string' ); END { string_reverse( undef ); } 1
use strict; use warnings; use feature qw( say ); use My::StringUtils qw( string_reverse ); say string_reverse( "Hello world" );

(Fine, you don't need a module to use END, but using a module means you don't forget to use END.)

Replies are listed 'Best First'.
Re^2: FFI::Platypus: Replace malloc with GC_MALLOC?
by syphilis (Archbishop) on Dec 14, 2022 at 22:49 UTC
    you could use an END block to ensure it's freed on exit

    I don't see the point of this. AIUI, on exit, perl's garbage collector will free that memory anyway.

    Also, as I mentioned above, I'm not convinced that string_reverse(undef) does not assign additional memory after it frees the previously allocated memory.
    I am convinced that, with Inline::C, it will assign more memory because XS does not equate the undef argument to NULL.
    Is there any reason to believe that it would be different under FFI::Platypus ?

    Cheers,
    Rob

      I don't see the point of this. AIUI, on exit, perl's garbage collector will free that memory anyway.

      Because the OP asked how to do it.

      And there's plenty of reason to want to learn how to perform cleanup.

      As for the specific case, it's a question of debate whether you should free memory on exit. But it does have benefits. One major benefit is that allows us to use valgrind or similar to find meaningful leaks.

      Finally, you're incorrect assuming that the termination of a Perl interpreter only occurs when the program is unloaded (i.e. when process exits, execs, etc). Each threads of a process has its own interpreter, for example. A process embedding Perl could load and unload the interpreter without exiting.

      Is there any reason to believe that it would be different under FFI::Platypus?

      There's no reason to believe it would be the same.

      And the OP specifically quoted someone saying it was different (that it results in a NULL argument).

      If there's a bug, fine. Point it out, fix it, whatever. But it has nothing to do with my answer. The question is about ensuring that cleanup is performed, and that's what I was addressing. The exact interface and implementation doesn't matter, so that's a separate topic you've already addressed and didn't need to bring up here.

        And there's plenty of reason to want to learn how to perform cleanup.

        Frankly, I can't think of a worse way of doing it than in an END{} block - especially if it's one that actually allocates more memory.

        There's no reason to believe it would be the same.

        You haven't checked ??
        You tell someone to do END { string_reverse( undef ); }, but you don't know if it will work as intended ....
        Update: I finally got FFI::Platypus working and was able to verify for myself that, with FFI::Platypus, "undef" does, indeed, get received as "NULL". The END{} block is therefore working as intended.

        Finally, you're incorrect assuming that the termination of a Perl interpreter only occurs when the program is unloaded (i.e. when process exits, execs, etc).

        I didn't even know that I had made such an assumption. Thank you for that information. (I've learned so much about myself from you, over the years ;-)
        I believe that whenever an END{} block is executed, it is immediately followed by a cleanup that would have freed any memory that the END{} block frees.
        I don't see any point in using an END{} block to do something that would have happened next anyway.

        Of course, it's a different matter if it turns out that there are instances where an END{} block will be executed, but without the following cleanup.
        In such a case, I agree that the END{} block approach is better than nothing, but it still defers the freeing of memory to much later than a half-decent programmer would allow.
        The best way that I know of is to have the function that assigns the memory, free the memory. But we haven't even touched upon that in this thread.

        Cheers,
        Rob
Re^2: FFI::Platypus: Replace malloc with GC_MALLOC?
by karlgoethebier (Abbot) on Dec 13, 2022 at 16:24 UTC

    This looks good - very good . I also don't know why I didn't come up with the END block idea myself to hide that ugly second call. Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»