1

I used a C library in my Java code using JNA. I have these C structures of whose members I need to print in Java. Because of the memory alignment and padding the size was differing from what I was actually expecting. Therefore I used pragma pack and this is how the structures look like now.

#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )

PACK(
typedef struct 
{
    size_t size;
    uint8_t bytes[48];
} ipj_tid_t);


PACK(
typedef struct 
{
    bool has_epc; //1
    ipj_epc_t epc; //64+8
    bool has_tid; //1
    ipj_tid_t tid; //48+8
    bool has_pc; //1
    uint32_t pc; //4
    bool has_xpc; //1
    uint32_t xpc; //4
    bool has_crc; //1
    uint32_t crc; //4
    bool has_timestamp; //1
    uint64_t timestamp; //8
    bool has_rssi; //1
    int32_t rssi; //4
    bool has_phase; //1
    int32_t phase; //4
    bool has_channel; //1
    uint32_t channel; //4
    bool has_antenna; //1
    uint32_t antenna; //4
} ipj_tag); //total size= 174


PACK(
typedef struct 
{
    bool has_error;
    ipj_error error;
    bool has_test_id;
    uint32_t test_id;
    bool has_result_1;
    uint32_t result_1;
    bool has_result_2;
    uint32_t result_2;
    bool has_result_3;
    uint32_t result_3;
    size_t data_count;
    uint32_t data[16];
    bool has_timestamp;
    uint64_t timestamp;
    size_t lt_buffer_count;
    uint32_t lt_buffer[21];
} ipj_test_report);


PACK(
typedef struct
{
    size_t size;
    uint8_t bytes[64];
} ipj_tag_operation_data_t);


PACK(
typedef  struct
{
    bool has_error;  //1
    ipj_error error; //4
    bool has_tag; //1
    ipj_tag tag; //174
    bool has_tag_operation_type; //1
    ipj_tag_operation_type tag_operation_type; //4
    bool has_tag_operation_data; //1
    ipj_tag_operation_data_t tag_operation_data; //72
    bool has_retries; //1
    uint32_t retries; //4
    bool has_diagnostic; //1
    uint32_t diagnostic; //4
    bool has_timestamp; //1
    uint64_t timestamp; //8
    size_t lt_buffer_count; //8
    uint32_t lt_buffer[30]; //120
} ipj_tag_operation_report); //405

When I run the code from Visual Studio, I am not getting any errors, exceptions or crashes from it. But when I call this from Java, the jvm is crashing. Why is this happening? There are other structures in the C code too which are not packed. Could it be a reason? Please advice.

The structures I have shown above are used in C. What is returned from the C code is this structure after all the processing.

#define RX_MAX_SIZE     405
#pragma pack(push, 1)
typedef struct _report
{
    ipj_report_id report_id;
    uint32_t data_size;
    uint32_t data[RX_MAX_SIZE];
 } report;
 #pragma pack(pop)

The equivalent JNA structure that has been used is as follows.

public class _report extends Structure {

    public static class ByValue extends _report implements Structure.ByValue {

    }

    public _report() {
        super();
        setAlignType(ALIGN_NONE);
    }

    public _ipj_report_id reportid;
    public int data_size;
    public int[] data = new int[405]; 

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

}

public class _ipj_report_id extends Structure {

    public int ipj_report_id;

    public _ipj_report_id() {
        super();
        setAlignType(ALIGN_NONE);
    }

    @Override
    protected List getFieldOrder() {
        return Arrays.asList("ipj_report_id");
    }

}

Below is the structure I get when debugging the JNA code.

    _report$ByValue(auto-allocated@0x18918cc0 (1628 bytes)) {
   _ipj_report_id reportid@0=_ipj_report_id(allocated@0x18918cc0 (4 bytes) (shared from auto-allocated@0x18918cc0 (1628 bytes))) {
    int ipj_report_id@0=0
   }
   int data_size@4=195
   int data[405]@8=[I@78bb0ecb
 }

Below is how I call this method in JNA.

 rfidlib rlib = (rfidlib) Native.loadLibrary("rfidlib", rfidlib.class);
_report.ByValue report = new _report.ByValue();
 report = rlib.get_next_reports();
AnOldSoul
  • 4,017
  • 12
  • 57
  • 118
  • Can you show us any error output you might have? One possibility is the version of the JVM you are using (e.g. 32 versus 64 bit). – Tim Biegeleisen Jan 22 '16 at 06:51
  • It doesn't show any errors. I do get the output printed on the console. Then suddenly JVM crashes. When I remove the packing code it works fine. Its a 64bit JVM and 64 bit dll. Please advice. – AnOldSoul Jan 22 '16 at 06:53
  • 1
    [THIS](http://stackoverflow.com/questions/19856048/jni-structure-alignment) may help. – LPs Jan 22 '16 at 07:29
  • I tried the setAlignmentType to No alignment in my structure. Still no help. – AnOldSoul Jan 22 '16 at 11:00
  • Possible duplicate of [JNA structure mapping with no alignment and padding](http://stackoverflow.com/questions/34944616/jna-structure-mapping-with-no-alignment-and-padding) – technomage Jan 22 '16 at 22:27
  • @technomage I asked that question too. No answer yet for it :( – AnOldSoul Jan 22 '16 at 23:23
  • @technomage I have edited the question mate. Could you please help me out with this. – AnOldSoul Jan 25 '16 at 02:45
  • 1628 is exactly the size I would expect for no alignment/packing for the `_report` struct. What exactly doesn't match up? – technomage Jan 25 '16 at 11:35
  • If your `get_reports()` function returns a `struct` (as opposed to `struct*`), you need to declare it in JNA as returning `_report.ByValue`, otherwise the results will be unpredictable. Please include _all_ relevant native code _and_ the corresponding JNA mappings you're using. – technomage Jan 25 '16 at 11:38

1 Answers1

0

JNA assumes default structure layout for the current target platform (in this case, the MS compiler).

You can print the layout of the JNA-generated memory layout by calling Structure.toString() after invoking the JVM with -Djna.dump_memory=true.

You can then compare your desired structure layout with the actual layout generated by JNA to look for differences. If you generically use boolean in your Java structure, the default is to allocate a native int, so if that's not the same size as your native bool, you need to either use byte on the Java side or explicitly supply a TypeMapper to your Structure to indicate that boolean should be converted to a size compatible with native bool (note that the size of native bool is not defined by the C standard).

I would recommend not using #pragma pack in your code unless you explicitly need it.

Please update your question with your Java Structure implementation and its debug output.

technomage
  • 9,861
  • 2
  • 26
  • 40