FFI::P...:Buffer(3pm)

πŸ’… FFI::Platypus::Buffer β€” like, the Perl doc page for it (User Contributed Perl Documentation)

okay so bestie, you found it: FFI::Platypus::Buffer. This is the page. Buckle up πŸ’–


✨ NAME ✨

FFI::Platypus::Buffer β€” convert scalars to C buffers. that's the whole vibe. πŸ¦‹

πŸŽ€ VERSION πŸŽ€

version 2.11

🌸 SYNOPSIS 🌸

use FFI::Platypus::Buffer;
my($pointer, $size) = scalar_to_buffer $scalar;
my $scalar2 = buffer_to_scalar $pointer, $size;

πŸ’œ DESCRIPTION πŸ’œ

so. here's the thing. there's this super common pattern in C where you hand a function a "buffer" β€” a chunk of memory β€” and you do it with a pair of arguments: an opaque pointer, plus the size of that memory region. iconic duo tbh. and in Perl, the equivalent structure? a scalar holding a string of bytes. literally that's it. so this module gives you portable functions that convert a Perl string/scalar into a buffer and back again. 🫢

these functions are implemented using pack and unpack, which is why they're relatively fast. no cap. ⚑

both functions are exported by default, but you can explicitly export one of them, or neither, if you so choose. your call, main character. πŸ‘‘

a better way to do this might be with custom types β€” see FFI::Platypus::API and FFI::Platypus::Type. these functions were taken from the now-obsolete FFI::Util module, since they may be useful in some cases. πŸ’«
Caution: ⚠️ this module provides great power in the way that you interact with C code, but with that power comes great responsibility (yes, we're doing the quote, it's earned). since you are dealing with blocks of memory, you need to take care to understand the underlying ownership model of these pointers. like, actually understand it. please. 😭

πŸ”₯ FUNCTIONS πŸ”₯

🧚 scalar_to_buffer

my($pointer, $size) = scalar_to_buffer $scalar;

converts a string scalar into a buffer. what you get back, in order: a pointer to the start of the string scalar's memory region, and the size of that region. ✨

you should NEVER try to free $pointer. seriously. don't. πŸ’€

when you pass this pointer + size into a C function, that function has direct access to the data stored in your scalar β€” so it is important that you do not resize or free the scalar while the C code is using it. typically, if you're passing a buffer into a C function that reads from or writes to the buffer but does not keep the pointer for later use, you're okay. if the buffer is in use long-term by the C code, then you should consider copying the buffer instead. for example:

use FFI::Platypus::Buffer qw( scalar_to_buffer );
use FFI::Platypus::Memory qw( malloc memcpy free )

my($ptr, $size) = scalar_to_buffer $string;
c_function_that_does_not_keep_ptr( $ptr, $size); # okay

my($ptr, $size) = scalar_to_buffer $string;
my $ptr_copy = malloc($size);
memcpy($ptr_copy, $ptr, $size);
c_function_that_DOES_keep_ptr( $ptr_copy, $size); # also okay

...

# later when you know that the c code is no longer using the pointer
# Since you allocated the copy, you are responsible for free'ing it.
free($ptr_copy);

πŸ¦‹ scalar_to_pointer

my $pointer = scalar_to_pointer $scalar;

gets you the pointer to the scalar. (similar to scalar_to_buffer up above πŸ‘†, except the size of the scalar is not computed or returned.)

not exported by default, but may be exported on request. ✨

🌈 buffer_to_scalar

my $scalar = buffer_to_scalar $pointer, $size;

converts the buffer region β€” defined by the pointer and the size β€” into a string scalar. πŸŽ€

because of the way memory management works in Perl, the buffer is copied from the buffer into the scalar. and if this pointer was returned from C land, then you should only free it if you allocated it. iykyk. πŸ™ˆ

πŸ‘‘ grow

grow $scalar, $size, \%options;

ensures the scalar can contain at least $size bytes. the following are recognized:

  • clear => boolean β€” if true, $scalar is cleared prior to being enlarged. this avoids copying the existing contents to the reallocated memory if they're not needed. for example, after
$scalar = "my string";
grow $scalar, 100, { clear => 0 };

"$scalar == "my string"", while after

$scalar = "my string";
grow $scalar, 100;

"length($scalar) == 0"

it defaults to "true".

  • set_length => boolean β€” if true, the length of the string in the $scalar is set to $size. (see the discussion in set_used_length.) this is useful if a foreign function writes exactly $size bytes to $scalar, since it avoids a subsequent call to "set_used_length". contrast this:
grow my $scalar, 100;
read_exactly_100_bytes_into_scalar( scalar_to_pointer($scalar) );
@chars = unpack( 'c*', $scalar );

with this:

grow my $scalar, 100, { set_length => 0 };
read_exactly_100_bytes_into_scalar( scalar_to_pointer($scalar) );
set_used_length( $scalar, 100 );
@chars = unpack( 'c*', $scalar );

it defaults to "true".

⚠️ any pointers obtained with "scalar_to_pointer" or "scalar_to_buffer" are no longer valid after growing the scalar. gone. expired. don't touch. πŸ’€

not exported by default, but may be exported on request. ✨

πŸ’– set_used_length

set_used_length $scalar, $length;

updates Perl's notion of the length of the string in the scalar. here's the lore: a string scalar keeps track of two lengths β€” the number of available bytes and the number of used bytes. when a string scalar is used as a buffer by a foreign function, it's necessary to tell Perl how many bytes were actually written to it so that Perl's string functions (like "substr" or "unpack") will work correctly. πŸ’…

if $length is larger than what the scalar can hold, it's set to the maximum possible size.

in the following example, the foreign routine read_doubles may fill the buffer with up to a set number of doubles, returning the number actually written:

my $sizeof_double = $ffi->sizeof( 'double' );
my $max_doubles = 100;
my $max_length = $max_doubles * $sizeof_double;

my $buffer;                   # length($buffer) == 0
grow $buffer, $max_length;    # length($buffer) is still  0
my $pointer = scalar_to_pointer($buffer);

my $num_read = read_doubles( $pointer, $max_doubles );
                              # length($buffer) is still == 0

set_used_length $buffer, $num_read * $sizeof_double;
                              # length($buffer) is finally != 0

# unpack the native doubles into a Perl array
my @doubles = unpack( 'd*', $buffer );  # @doubles == $num_read

not exported by default, but may be exported on request. ✨

🫢 window

window $scalar, $pointer;
window $scalar, $pointer, $size;
window $scalar, $pointer, $size, $utf8;

this makes the scalar a read-only window into the arbitrary region of memory defined by $pointer (pointing at the start of the region) and $size (the size of the region). if $size is omitted, then it assumes a C style string and uses the C "strlen" function to determine the size (the terminating '\0' will not be included). πŸͺŸβœ¨

this can be useful if you have a C function that returns a buffer pair (pointer, size) and you want to access it from Perl without having to copy the data. it can also be useful when interfacing with programming languages that store strings as an address/length pair instead of as a pointer to a null-terminated sequence of bytes. πŸ¦‹

you can specify $utf8 to set the UTF-8 flag on the scalar. > ⚠️ note that the behavior of setting the UTF-8 flag on a buffer that does not contain UTF-8 as understood by the version of Perl that you are running is undefined. so like, be careful. 😬

Hint: if you have a buffer that needs to be freed by C once the scalar falls out of scope, you can use Variable::Magic to apply magic to the scalar and free the pointer once it falls out of scope. πŸͺ„

use FFI::Platypus::Buffer qw( scalar_to_pointer );
use FFI::Platypus::Memory qw( strdup free );
use Variable::Magic qw( wizard cast );

my $free_when_out_of_scope = wizard(
  free => sub {
    my $ptr = scalar_to_pointer ${$_[0]};
    free $ptr;
  }
);

my $ptr = strdup "Hello Perl";
my $scalar;
window $scalar, $ptr, 10;
cast $scalar, $free_when_out_of_scope;
undef $ptr;  # don't need to track the pointer anymore.

# we can now use scalar as a regular read-only Perl variable
print $scalar, "\n";  # prints "Hello Perl" without the \0

# this will free the C pointer
undef $scalar;

Hint: returning a scalar string from a Perl function actually copies the value. if you want to return a string without copying, then you need to return a reference. 🎯

sub c_string
{
  my $ptr = strdup "Hello Perl";
  my $scalar;
  window $scalar, $ptr, 10;
  cast $scalar, $free_when_out_of_scope;
  \$scalar;
}

my $ref = c_string();
print $$ref, "\n";  # prints "Hello Perl" without the \0

not exported by default, but may be exported on request. ✨


🌟 SEE ALSO 🌟

  • FFI::Platypus β€” the main Platypus documentation. go read it bestie πŸ“š

πŸ’ AUTHOR πŸ’

Author: Graham Ollis <plicease@cpan.org>

Contributors:

  • Bakkiaraj Murugesan (bakkiaraj)
  • Dylan Cali (calid)
  • pipcet
  • Zaki Mughal (zmughal)
  • Fitz Elliott (felliott)
  • Vickenty Fesunov (vyf)
  • Gregor Herrmann (gregoa)
  • Shlomi Fish (shlomif)
  • Damyan Ivanov
  • Ilya Pavlov (Ilya33)
  • Petr PΓ­saΕ™ (ppisar)
  • Mohammad S Anwar (MANWAR)
  • HΓ₯kon HΓ¦gland (hakonhagland, HAKONH)
  • Meredith (merrilymeredith, MHOWARD)
  • Diab Jerius (DJERIUS)
  • Eric Brine (IKEGAMI)
  • szTheory
  • JosΓ© JoaquΓ­n Atria (JJATRIA)
  • Pete Houston (openstrike, HOUSTON)
  • Lukas Mai (MAUKE)

this software is copyright (c) 2015-2022 by Graham Ollis. 🫢

this is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. slay, honestly πŸ’…


⭐ and that's the page!! sign-off time: this was perl v5.42.3, dated 2026-08-20, and you've been reading FFI::Platypus::Buffer(3pm). go forth and buffer responsibly, bestie πŸŽ€πŸ¦‹πŸ’–

πŸ“¦ where this page comes from