Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing an inlined CArray in a CStruct to a shared library using NativeCall

This is a follow-up question to "How to declare native array of fixed size in Perl 6?".

In that question it was discussed how to incorporate an array of a fixed size into a CStruct. In this answer it was suggested to use HAS to inline a CArray in the CStruct. When I tested this idea, I ran into some strange behavior that could not be resolved in the comments section below the question, so I decided to write it up as a new question. Here is is my C test library code:

slib.c:

#include <stdio.h>

struct myStruct
{
    int A; 
    int B[3];
    int C;
};

void use_struct (struct myStruct *s) {
    printf("sizeof(struct myStruct): %ld\n", sizeof( struct myStruct ));
    printf("sizeof(struct myStruct *): %ld\n", sizeof( struct myStruct *));
    printf("A = %d\n", s->A);
    printf("B[0] = %d\n", s->B[0]);
    printf("B[1] = %d\n", s->B[1]);
    printf("B[2] = %d\n", s->B[2]);
    printf("C = %d\n", s->C);
}

To generate a shared library from this i used:

gcc -c -fpic slib.c
gcc -shared -o libslib.so slib.o

Then, the Perl 6 code:

p.p6:

use v6;
use NativeCall;

class myStruct is repr('CStruct') {
    has int32 $.A is rw;
    HAS int32 @.B[3] is CArray is rw;
    has int32 $.C is rw;
}

sub use_struct(myStruct $s) is native("./libslib.so") { * };

my $s = myStruct.new();
$s.A = 1;
$s.B[0] = 2;
$s.B[1] = 3;
$s.B[2] = 4;
$s.C = 5;
say "Expected size of Perl 6 struct: ", (nativesizeof(int32) * 5);
say "Actual size of Perl 6 struct: ", nativesizeof( $s );
say 'Number of elements of $s.B: ', $s.B.elems;
say "B[0] = ", $s.B[0];
say "B[1] = ", $s.B[1];
say "B[2] = ", $s.B[2];
say "Calling library function..";
say "--------------------------";
use_struct( $s );

The output from the script is:

Expected size of Perl 6 struct: 20
Actual size of Perl 6 struct: 24
Number of elements of $s.B: 3
B[0] = 2
B[1] = 3
B[2] = 4
Calling library function..
--------------------------
sizeof(struct myStruct): 20
sizeof(struct myStruct *): 8
A = 1
B[0] = 0         # <-- Expected 2
B[1] = 653252032 # <-- Expected 3
B[2] = 22030     # <-- Expected 4
C = 5

Questions:

  • Why does nativesizeof( $s ) give 24 (and not the expected value of 20)?

  • Why is the content of the array B in the structure not as expected when printed from the C function?

Note:

I am using Ubuntu 18.04 and Perl 6 Rakudo version 2018.04.01, but have also tested with version 2018.05

like image 698
Håkon Hægland Avatar asked Jun 09 '18 19:06

Håkon Hægland


1 Answers

Your code is correct. I just fixed that bug in MoarVM, and added tests to rakudo, similar to your code:

In C:

typedef struct {
    int a;
    int b[3];
    int c;
} InlinedArrayInStruct;

In Perl 6:

class InlinedArrayInStruct is repr('CStruct') {
    has int32 $.a is rw;
    HAS int32 @.b[3] is CArray;
    has int32 $.c is rw;
}

See these patches: https://github.com/MoarVM/MoarVM/commit/ac3d3c76954fa3c1b1db14ea999bf3248c2eda1c https://github.com/rakudo/rakudo/commit/f8b79306cc1900b7991490eef822480f304a56d9

If you are not building rakudo (and also NQP and MoarVM) directly from latest source from github, you probably have to wait for the 2018.08 release that will appear here: https://rakudo.org/files

like image 104
Tobias Leich Avatar answered Oct 20 '22 12:10

Tobias Leich