Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting data out of Native pointers

It's no big deal to get data into Perl 6 Native pointers:

sub memcpy( Pointer[void] $source, Pointer[void] $destination, int32 $size ) is native { * };
my Blob $blob = Blob.new(0x22, 0x33);
my Pointer[void] $src-memcpy = nativecast(Pointer[void], $blob);
my Pointer[void] $dest-memcpy = malloc( 32 );
memcpy($src-memcpy,$dest-memcpy,2);
my Pointer[int] $inter = nativecast(Pointer[int], $dest-memcpy);
say $inter; # prints NativeCall::Types::Pointer[int]<0x4499560>

However, I see no way of getting them out of the Pointer[int] other than creating a function to do it, since nativecast apparently works in the opposite direction, or at least not in the direction of casting to non-native types (which should be obvious by its name). How would you do that?

Update: For instance, using an Array would make it more workable. However

my $inter = nativecast(CArray[int16], $dest);
.say for $inter.list;

This works, but yields the error: Don't know how many elements a C array returned from a library

Update 2: Following Christoph's answer (thanks!), we can ellaborate it a little bit more into this, and we get to put the values back into a Buf

sub malloc(size_t $size --> Pointer) is native {*}
sub memcpy(Pointer $dest, Pointer $src, size_t $size --> Pointer) is native {*}

my $blob = Blob.new(0x22, 0x33);
my $src = nativecast(Pointer, $blob);
my $dest = malloc( $blob.bytes );
memcpy($dest, $src, $blob.bytes);
my $inter = nativecast(Pointer[int8], $dest);

my $cursor = $inter;

my Buf $new-blob .= new() ;
for 1..$blob.bytes {
    $new-blob.append: $cursor.deref;
    $cursor++;
}

say $new-blob;

We need to cast the pointer to exactly the same type used by the buffer, and then we use pointer arithmetic to run over it. However, we use $blob.bytes to know when to end the loop, and it's still kind of hacky. Would there be a more direct way? Or just a way of working with Bufs/Blobs so that they can be copied easily to the Native realm and back?

like image 211
jjmerelo Avatar asked Jun 28 '18 11:06

jjmerelo


1 Answers

Complete example:

use NativeCall;

sub malloc(size_t $size --> Pointer) is native {*}
sub memcpy(Pointer $dest, Pointer $src, size_t $size --> Pointer) is native {*}

my $blob = Blob.new(0x22, 0x33);
my $src = nativecast(Pointer, $blob);
my $dest = malloc(nativesizeof(int16));
memcpy($dest, $src, nativesizeof(int16));
my $inter = nativecast(Pointer[int16], $dest);
say $inter.deref.fmt('%x');

I assume you were looking for the deref method, but there were a few other issues with your code:

  • use of int32 instead of size_t in the declaration of memcpy
  • wrong order of the arguments to memcpy, which means you were copying two bytes read from uninitialized memory into your supposedly immutable Blob
  • use of plain int where you probably should have used a sized integer type such as int16

Also note the use of plain Pointer in the declaration of memcpy, which will allow you to pass in any pointer type without having to cast constantly.

like image 53
Christoph Avatar answered Sep 22 '22 23:09

Christoph