Search code examples
javajnaallocation

JNA structure memory allocation in array is incorrect


I have the problem that the memory allocation is incorrect. I think so because the bits are shifted between the attributes.

this is the native code:

typedef struct s_xl_channel_config {
    char                name [32];
    unsigned char       hwType;                               
    unsigned char       hwIndex;                             
    unsigned char       hwChannel;                           
    unsigned short      transceiverType;                     
    unsigned short      transceiverState;                   
    unsigned short      configError;                         
    unsigned char       channelIndex;                       
    unsigned __int64    channelMask;                         
    unsigned int        channelCapabilities;                 
    unsigned int        channelBusCapabilities;                       
    unsigned char       isOnBus;                             
    unsigned int        connectedBusType;                   
    XLbusParams         busParams;
    unsigned int        _doNotUse;                                                                         
    unsigned int        driverVersion;           
    unsigned int        interfaceVersion;                   
    unsigned int        raw_data[10];                   
    unsigned int        serialNumber;
    unsigned int        articleNumber;
    char                transceiverName [32]; 
    unsigned int        specialCabFlags;                     
    unsigned int        dominantTimeout;                     
    unsigned char       dominantRecessiveDelay;             
    unsigned char       recessiveDominantDelay;             
    unsigned char       connectionInfo;                     
    unsigned char       currentlyAvailableTimestamps;         
    unsigned short      minimalSupplyVoltage;                 
    unsigned short      maximalSupplyVoltage;                 
    unsigned int        maximalBaudrate;                     
    unsigned char       fpgaCoreCapabilities;               
    unsigned char       specialDeviceStatus;                 
    unsigned short      channelBusActiveCapabilities;       
    unsigned short      breakOffset;                         
    unsigned short      delimiterOffset;                     
    unsigned int        reserved[3];
} XL_CHANNEL_CONFIG;

My java Code is this:

@FieldOrder ({"name", "hwType", "hwIndex", "hwChannel", "transceiverType",
  "transceiverState", "configError", "channelIndex", "channelMask", 
  "channelCapabilities", "channelBusCapabilities", "isOnBus", "connectedBusType", 
  "busParams",    "_doNotUse", "driverVersion", "interfaceVersion", "raw_data", 
  "serialNumber", "articleNumber", "transceiverName", "specialCabFlags", 
  "dominantTimeout", "dominantRecessiveDelay", "recessiveDominantDelay", 
  "connectionInfo", "currentlyAvailableTimestamps", "minimalSupplyVoltage", 
  "maximalSupplyVoltage", "maximalBaudrate", "fpgaCoreCapabilities", 
  "specialDeviceStatus", "channelBusActiveCapabilities", "breakOffset", 
  "delimiterOffset", "reserved"})
public class XLchannelConfig extends Structure{

    public byte[] name = new byte[32];
    public byte hwType;
    public byte hwIndex;
    public byte hwChannel;
    public short transceiverType;
    public short transceiverState;
    public short configError;
    public byte channelIndex;
    public Nativelong channelMask;
    public int channelCapabilities;
    public int channelBusCapabilities;
    public byte isOnBus;
    public int connectedBusType;
    public XLbusParams busParams= new XLbusParams();
    public int _doNotUse;
    public int driverVersion;
    public int interfaceVersion;
    public int[] raw_data = new int[(10)];
    public int serialNumber;
    public int articleNumber;
    public byte[] transceiverName = new byte[32];
    public int specialCabFlags;
    public int dominantTimeout;
    public byte dominantRecessiveDelay;
    public byte recessiveDominantDelay;
    public byte connectionInfo;
    public byte currentlyAvailableTimestamps;
    public short minimalSupplyVoltage;
    public short maximalSupplyVoltage;
    public int maximalBaudrate;
    public byte fpgaCoreCapabilities;
    public byte specialDeviceStatus;
    public short channelBusActiveCapabilities;
    public short breakOffset;
    public short delimiterOffset;
    public int[] reserved = new int[3];
    
    public XLchannelConfig() {
        super();        
    }

The XLchannelConfig class is in an array that I initialized with .toArray(). When I output the attributes, I see that the values ​​are shifted. It looks like the bits have shifted from one attribute to the next. I suspect that it is due to the wrong data type, but I cannot determine which it is.

The toString print this out:

XLchannelConfig [name=Virtual Channel 1               , hwType=1, hwIndex=0, hwChannel=0, transceiverType=0, transceiverState=0, channelIndex=1, channelMask=0, channelCapabilities=458752, channelBusCapabilities=106496, isOnBus=1, connectedBusType=16777216, driverVersion=67830784, interfaceVersion=0, raw_data=[0, 0, 0, 65536, 0, 0, 0, 0, 0, 0], serialNumber=0, articleNumber=536870912, transceiverName=Virtual CAN                    , specialCabFlags=0, dominantTimeout=0, reserved=[0, 0, 1442840576], busParams=XLbusParams [busType=536870912]]

XLchannelConfig [name=irtual Channel 2               , hwType=0, hwIndex=1, hwChannel=22, transceiverType=0, transceiverState=0, channelIndex=0, channelMask=0, channelCapabilities=1792, channelBusCapabilities=16777632, isOnBus=0, connectedBusType=65536, driverVersion=264964, interfaceVersion=0, raw_data=[0, 0, 0, 256, 0, 0, 0, 0, 0, 0], serialNumber=0, articleNumber=1444937728, transceiverName=irtual CAN                    , specialCabFlags=0, dominantTimeout=0, reserved=[0, 0, 0], busParams=XLbusParams [busType=-1591738368]]


Solution

  • The symptoms show an an extra single byte in your mapping. The last element of the reserved field includes the byte 0x56 which corresponds to the letter "V" missing from the second element. So we need to look for that extra byte.

    The header file bus types go only up to 0x100. Your output has the bus type as 0x20000000 suggesting the error is occurring before the XLbusParams union. It's definitely occurring before the transcieverName which shows an extra non-null byte as the last character. Other than channelMask (see below, would be 4-byte offset) the mappings look correct.

    One possible mismatch that could explain a single byte could be alignment of the structure fields. The name takes 32 bytes, and then there are three 1-byte fields followed by three 2-byte fields. This would have one of the short fields crossing a 4-byte or 8-byte boundary. You might consider using different JNA Structure alignments, such as Structure.ALIGN_NONE:

    public XLchannelConfig() {
        super(Structure.ALIGN_NONE);
    }
    

    Other mapping comments:

    The channelMask field in the C header is an explicit 64-bit type (int64), and thus should be directly mapped to Java's 64-bit long. The only time you should use NativeLong as a mapping is when the native type is long. This can be either 32-bit or 64-bit, depending on both operating system and bitness. This would (possibly) under-allocate by 4 bytes, however, and may not be the problem.

    In copies of the header file in the API, I do not see the _doNotUse field that you include. Are you sure it should be included? This adds 4 bytes to the mapping. Are you certain the header file you've copied matches the version of the API binary that you're using?

    Another potential source of an issue is the XLbusParams type. The API shows that's a union with an int type and 32 bytes of data. If you have not properly mapped the union (at least the largest member) that could also cause an offset.