Problem with mapping structure from C to Java using Java Native Access

140 views
Skip to first unread message

Yavuz Akin

unread,
Oct 27, 2023, 9:08:18 AM10/27/23
to Java Native Access

I have the following extract of C header from the project that I would like to map to Java using JNA:

...

typedef size_t ObjectHandle;

typedef const char *FfiStr;

typedef struct FfiList_FfiStr {
  size_t count;
  const FfiStr *data;
} FfiList_FfiStr;

typedef struct FfiList_FfiStr FfiStrList;

int create_schema(FfiStr schema_name,
                  FfiStr schema_version,
                  FfiStr issuer_id,
                  FfiStrList attr_names,
                  ObjectHandle *result_p);
...

I cannot find the right mapping to Java for the FfiStrList type.

Here is the mapping I have tried in Java:

public interface CredLibrary extends Library {
    CredLibrary INSTANCE = (CredLibrary) Native.load("credlibrary", CredLibrary.class);

    public class FfiList_FfiStr extends Structure {
        public Size_t count;
        public Pointer data ;

        public FfiList_FfiStr(String[] attr) {
            count = new Size_t(attr.length);
            data = new StringArray(attr);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList("count", "data");
        }
    }


    int create_link_secret(PointerByReference link_secret_p);
    int generate_nonce(PointerByReference nonce_p);
    int create_schema(String schema_name, String schema_version, String issuer_id,FfiList_FfiStr attr_names, IntByReference result_p)
;

}

The first create_link_secret and generate_nonce functions work fine, create_schema doesn't work.

And here is the test I have tried:

String schema_name= new String("test");
String schema_version = new String("v1");
String issuer_id =new String( "123");

String[] attr = new String[2];
attr[0]="age";
attr[1]="name";

CredLibrary.FfiList_FfiStr attrib = new Anoncreds.FfiList_FfiStr(attr);
IntByReference pref3= new IntByReference();
int c=
lib.create_schema(schema_name,schema_version,issuer_id,attrib,pref3);

To be more precise, in my logs I first receive the following warning :

malloc(3219533512759680) failed: returning null pointer

And then I receive an handle_alloc_error inside create_schema although I know that with the original code this function works perfectly fine. 

Would it be possible to indicate what I do wrong? it seems like the malloc function is receiving the wrong argument. It seems like it is receiving something like a pointer whereas it should normally receive a much smaller value. Maybe something is wrong with my java FfiList_FfiStr structure that makes it like that.

Daniel B. Widdis

unread,
Oct 27, 2023, 12:52:29 PM10/27/23
to jna-...@googlegroups.com
You're mapping the pointer ObjectHandle as IntByReference but the type is size_t which is probably 8 bytes.

JNA has size_t mappings including their ByReference counterparts that you should use here.

Which operating system are you using? 

--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jna-users/592d0ff5-a283-45ef-b827-e4c099999009n%40googlegroups.com.


--
Dan Widdis

Matthias Bläsing

unread,
Oct 27, 2023, 3:26:35 PM10/27/23
to jna-...@googlegroups.com
Hi Yavuz,

Am Freitag, dem 27.10.2023 um 06:08 -0700 schrieb Yavuz Akin:

I have the following extract of C header from the project that I would like to map to Java using JNA:

typedef struct FfiList_FfiStr {


  size_t count;
  const FfiStr *data;
} FfiList_FfiStr;

typedef struct FfiList_FfiStr FfiStrList;

int create_schema(FfiStr schema_name,
                  FfiStr schema_version,
                  FfiStr issuer_id,
                  FfiStrList attr_names,
                  ObjectHandle *result_p);
...

I cannot find the right mapping to Java for the FfiStrList type.

Here is the mapping I have tried in Java:

public interface CredLibrary extends Library {
    CredLibrary INSTANCE = (CredLibrary) Native.load("credlibrary", CredLibrary.class);

    public class FfiList_FfiStr extends Structure {
        public Size_t count;
        public Pointer data ;
    }


    int create_schema(String schema_name, String schema_version, String issuer_id,FfiList_FfiStr attr_names, IntByReference result_p)
;

}


in addition to the issue Daniel found, the binding of create_schema is not correct. If you declare a structure in the signature of a method, JNA defaults to pass the pointer of the structure to the function. However the header definition defines that the structure is passed by value.

See "Structure by Value Arguments/Returns" in the Javadoc: http://java-native-access.github.io/jna/5.13.0/javadoc/

Greetings

Matthias

Yavuz Akin

unread,
Nov 3, 2023, 10:05:07 AM11/3/23
to Java Native Access
Hello Dan and Widdis,

Thank you very much for your help.

I would like to get a bit more information on both your indications :

First on the remarks regarding the use of size_t :

The operating system I want this code to work in is Android OS.

As you've indicated I've tried using the size_t mappings and its ByReference counterpart but I've came across the following problems :
  • I found two size_t types in the documentation. The first one is com.sun.jna.Structure.FFIType.size_t and the second one is com.sun.jna.platform.unix.LibCAPI.size_t and I don't know which one is the correct one to use. 
  • So I tried using both either way, for com.sun.jna.Structure.FFIType.size_t but I received the following error during build : 'com.sun.jna.Structure.FFIType' is not public in 'com.sun.jna.Structure'. Cannot be accessed from outside package.
  • I also tried using com.sun.jna.platform.unix.LibCAPI.size_t but I received the errors cannot resolve symbol 'unix' when i import com.sun.jna.platform.unix or I receive cannot resolve symbol 'LibCAPI' when i import com.sun.jna.platform.unix.LibCAPI.size_t
On the remarks regarding the binding of create_schema :

I have checked the documentation you have referred to and adapted my code accordingly (in bold):


  public class FfiList_FfiStr extends Structure {
       public static class ByValue extends FfiList_FfiStr implements Structure.ByValue{
            public ByValue(String[] attr) {
                super(attr);
            }
        }
        public Size_t count;
        public Pointer data ;

        public FfiList_FfiStr(String[] attr) {
            count = new Size_t(attr.length);
            data = new StringArray(attr);
        }

        @Override
        protected List getFieldOrder() {
            return Arrays.asList("count", "data");
        }
    }

...

int create_schema(String schema_name, String schema_version, String issuer_id,FfiList_FfiStr.ByValue attr_names, IntByReference result_p);

and in my tests I did the following :

String schema_name= new String("test");
String schema_version = new String("v1");
String issuer_id =new String( "123");

String[] attr = new String[2];
attr[0]="age";
attr[1]="name";

CredLibrary.FfiList_FfiStr.ByValue attrib = new CredLibrary.FfiList_FfiStr.ByValue(attr);

IntByReference pref3= new IntByReference();
int c=lib.create_schema(schema_name,schema_version,issuer_id,attrib,pref3);

First of all, As you can see I could not put an empty constructor for the FfiList_FfiStr.ByValue since FfiList_FfiStr does not have an empty constructor itself. I hope this does not create any problem.
 
Secondly, my code now executes without error (although I haven't changed the IntByReference mentionned by Dan yet). BUT I don't think this means the code works. Create_schema is such that it outputs an int which outputs 0 if the code was successful or another number if there was a problem somewhere. create_schema outputs 1 which is the code with problems related to the input. This probably means that the mapping of my code is still wrong somewhere and what probably is happening is that the code isn't executed because its input is wrong I assume. What is weird is that is that before making this change I didn't receive this output, so my questions are :

- Why passing FfiList_FfiStr by value makes it such that my code has a wrong input and why didn't this happen with my previous code ?
- Could this possibly be related to the use of IntByReference mentionned by Dan ? (But probably not because my previous code also used IntByReference and I didn't receive this error code before)
- Would you have any other idea what could make the input/mapping incorrect ?

Thank you again very much for the help.

Yavuz.

Matthias Bläsing

unread,
Nov 4, 2023, 12:01:04 PM11/4/23
to jna-...@googlegroups.com
Hi,

for Android (a Linux derivate) you can use com.sun.jna.platform.unix.LibCAPI.size_t or if you need the a size_t* com.sun.jna.platform.unix.LibCAPI.size_t.ByReference.

size_t on 64bit systems is at least 64bit wide to enable addressing all allocatable objects. So you definition results in an out-of-bounds write.

pref3 points to 32bit memory block, you pass it to a function, that will write sizeof(size_t) (on 64bit at least 64bits) there. If you are lucky the 32bit behind the memory block is unused, if you are unlucky an important information gets overwritten.

TL;DR: You must get the correct mappings.

If you need more help:

a) show your code (for example on github)
b) make the code a minimal example
c) show the header (in a readable version, i.e. also in the sample code)
d) show the documentation

Greetings

Matthias

Am Freitag, dem 03.11.2023 um 07:05 -0700 schrieb Yavuz Akin:
> Hello Dan and Widdis,
>
> Thank you very much for your help.
>
> I would like to get a bit more information on both your indications :
>
> First on the remarks regarding the use of size_t :
>
> The operating system I want this code to work in is Android OS.
>
> As you've indicated I've tried using the size_t mappings and its ByReference counterpart but I've came across the following problems :
>  * I found two size_t types in the documentation. The first one is com.sun.jna.Structure.FFIType.size_t and the second one is com.sun.jna.platform.unix.LibCAPI.size_t and I don't know which one is the correct one to use. 
>  * So I tried using both either way, for com.sun.jna.Structure.FFIType.size_t but I received the following error during build : 'com.sun.jna.Structure.FFIType' is not public in 'com.sun.jna.Structure'. Cannot be accessed from outside package.
>  * I also tried using com.sun.jna.platform.unix.LibCAPI.size_t but I received the errors cannot resolve symbol 'unix' when i import com.sun.jna.platform.unix or I receive cannot resolve symbol 'LibCAPI' when i import com.sun.jna.platform.unix.LibCAPI.size_t
> --
> You received this message because you are subscribed to the Google Groups "Java Native Access" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/jna-users/83520b80-08c9-425f-b5e3-8ec8292876a0n%40googlegroups.com.

Reply all
Reply to author
Forward
0 new messages