线程“主”中的JNA异常java.lang.Error:无效的内存访问(未知源) [英] JNA Exception in thread "main" java.lang.Error: Invalid memory access(Unknown Source)

查看:196
本文介绍了线程“主”中的JNA异常java.lang.Error:无效的内存访问(未知源)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JNA 4.0.0从Java访问某些DLL函数,该DLL本机函数声明如下:

I'm using JNA 4.0.0 to access some DLL function from Java, this DLL Native Function is declared as the following:

int ApplicationInit(HANDLE hEMV, TLV *tlv_Appl, TLV *tlv_AIP);

输入参数的类型如下所述

Types of the input parameters are described below

/* Opaque structure */
typedef void *HANDLE;

typedef struct
{
    unsigned char *_lenptr;     /* pointer to 'len' field (Private member) */
    unsigned int _len;          /* 'outer' length, specified by user (Private member) */
    unsigned short _offset;
    unsigned short len;         /* number of bytes (Public member) */

    unsigned long tag;          /* Tag tag  (Public member) */
    unsigned char *val;         /* byte string  (Public member) */
    unsigned char _tagptr[256]; /* Container for TLV data (Private member) */
} TLV;

因此,我在库接口中声明如下:

and so, I declared it inside the library interface as follows:

public static class HANDLE extends PointerType {
        public HANDLE(Pointer address) {
            super(address);
        }
        public EMV_HANDLE() {
            super();
        }
    }

public class TLV extends Structure {
    /**
     * pointer to 'len' field (Private member)<br>
     * C type : unsigned char*
     */
    public Pointer _lenptr;
    /** 'outer' length, specified by user (Private member) */
    public int _len;
    public short _offset;
    /** number of bytes (Public member) */
    public short len;
    /** Tag tag  (Public member) */
    public NativeLong tag;
    /**
     * byte string  (Public member)<br>
     * C type : unsigned char*
     */
    public Pointer val;
    /**
     * Container for TLV data (Private member)<br>
     * C type : unsigned char[256]
     */
    public byte[] _tagptr = new byte[256];
    public TLV() {
        super();
    }
    protected List<? > getFieldOrder() {
        return Arrays.asList("_lenptr", "_len", "_offset", "len", "tag", "val", "_tagptr");
    }
    /**
     * @param _lenptr pointer to 'len' field (Private member)<br>
     * C type : unsigned char*<br>
     * @param _len 'outer' length, specified by user (Private member)<br>
     * @param len number of bytes (Public member)<br>
     * @param tag Tag tag  (Public member)<br>
     * @param val byte string  (Public member)<br>
     * C type : unsigned char*<br>
     * @param _tagptr Container for TLV data (Private member)<br>
     * C type : unsigned char[256]
     */
    public TLV(Pointer _lenptr, int _len, short _offset, short len, NativeLong tag, Pointer val, byte _tagptr[]) {
        super();
        this._lenptr = _lenptr;
        this._len = _len;
        this._offset = _offset;
        this.len = len;
        this.tag = tag;
        this.val = val;
        if ((_tagptr.length != this._tagptr.length)) 
            throw new IllegalArgumentException("Wrong array size !");
        this._tagptr = _tagptr;
    }
    public static class ByReference extends TLV implements Structure.ByReference {

    };
    public static class ByValue extends TLV implements Structure.ByValue {

    };
}

int EMV_ApplicationInit(AppdefLibrary_EMVCT.EMV_HANDLE hEMV, TLV.ByReference tlv_Appl, TLV.ByReference tlv_AIP);

然后我用以下方式称呼它:

and then I call it in the following way:

EMV_HANDLE hEMV= new EMV_HANDLE();
TLV.ByReference tlv_Appl=new TLV.ByReference();
TLV.ByReference tlv_AIP=new TLV.ByReference();

System.out.println(AppdefLibrary.INSTANCE.ApplicationInit(hEMV, tlv_Appl, tlv_AIP));

但我收到以下异常:

Exception in thread "main" java.lang.Error: Invalid memory access
    at com.sun.jna.Native.invokeInt(Native Method)
    at com.sun.jna.Function.invoke(Function.java:383)
    at com.sun.jna.Function.invoke(Function.java:315)
    at com.sun.jna.Library$Handler.invoke(Library.java:212)
    at com.sun.proxy.$Proxy1.ApplicationInit(Unknown Source)
    at test.Test.main(Test.java:192)

请帮助并感谢您的关注!

Please help and thank you for your attention!

推荐答案

当您尝试访问未正确分配的本机端内存时,将导致无效内存访问错误。

The Invalid Memory Access error results when you're trying to access native-side memory that you haven't properly allocated.

完全是如何分配内存可能有几种方式,您必须追捕它们以找出问题所在……您必须剥去洋葱的几层才能解决实际问题。

Exactly how that memory gets allocated can occur a few ways and you must hunt them down to figure out your problem... you have to peel off a few layers of the onion to get to the actual problem.

f首先要检查的是您的JNA类型映射。众所周知,这里的结构尺寸是有缺陷的。但是,您的结构看起来是正确的。

The first thing to check is your JNA type mappings. Structure sizes are notoriously at fault here. However, your structure looks correct.

下一个可能的来源是您尚未为结构本身分配本机端内存。这是您选择使用ByReference处理结构的副作用。如果您选择这条路线,则会有更多的开销。但是,这都是不必要的。 JNA在后台进行了所有繁重的工作,当您将Structure作为参数传递给JNA库时,它实际上仅将指针发送到本机端...但是处理内存分配等。

The next likely source is that you've not allocated the native-side memory for the structures themselves; this is a side effect of your choice to use ByReference to deal with the structures. If you go this route you've got a lot more overhead. However, this is all unnecessary; JNA does all the heavy lifting under the hood and when you pass a Structure as an argument to a JNA library, it really sends just the pointer to the native side... but handles the memory allocation, etc.

您应该只在代码中直接引用TLV结构。

You should just reference the TLV structure directly in your code.

在库中:

int EMV_ApplicationInit(AppdefLibrary_EMVCT.EMV_HANDLE hEMV, TLV tlv_Appl, TLV tlv_AIP);

在您的访问代码中:

TLV tlv_Appl=new TLV();
TLV tlv_AIP=new TLV();

System.out.println(AppdefLibrary.INSTANCE.ApplicationInit(hEMV, tlv_Appl, tlv_AIP));

如果解决方案不能解决您的问题,则另一种可能性是,尽管您拥有足够的内存为Java结构分配的C方法在内部引用了其他内存,API希望您以某种方式初始化变量,以便它们指向其他地方的(已分配)内存。未初始化的指针很可能是罪魁祸首,特别是如果打算将其作为用户的输入,而不仅仅是该函数将要填充的回调。您需要仔细查看API文档,以查看是否是这种情况,以及是否需要初始化任何指针。

If fixing this doesn't solve your problem, another possibility is that while you've got the memory allocated for your Java structures, the C method refers internally to other memory and the API expects you to have initialized your variables in some way so that they point to (allocated) memory elsewhere. Uninitialized pointers are a likely culprit, especially if intended as "input" from the user rather than simply a callback that the function will populate. You need to carefully review the API documentation to see if this is the case and if it requires any of the pointers to be initialized.

例如,空值 HANDLE 可能不被该方法接受;可能需要您通过其他方法初始化 HANDLE (然后再发布)。

For example, a null HANDLE may not be acceptable to the method; it may require you to initialize the HANDLE by some other method (and later release it).

或者,您可能需要对TLV结构进行一些操作以初始化其内部指针成员。例如, val 字段指向字节字符串。 API是否期望您已经分配了内存并提供了分配的内存长度(例如, Pointer val = new Memory(256); tlv_Appl.val = val; tlv_Appl.len = 256; )?

Or, you may have needed to do something to the TLV structures to initialize their internal pointer members. The val field, for example, points to a "byte string". Does the API expect you to have allocated that already and provided the length of the memory you allocated (e.g., Pointer val = new Memory(256); tlv_Appl.val = val; tlv_Appl.len = 256;)? What exactly is the _lenptr pointing to (the comment indicates an int field but it's a char pointer, that seems odd)?

此外,4.0.0是JNA的旧版本; 4.2.2是当前版本,除非出于其他原因需要较旧的版本,否则应使用它。

Also, as an aside, 4.0.0 is a much older version of JNA; 4.2.2 is the current version and you should use it unless you need an older version for some other reason.

此外,JNA已经包含了< a href = https://java-native-access.github.io/jna/4.2.1/com/sun/jna/platform/win32/WinNT.HANDLE.html rel = nofollow> WinNT.HANDLE 可能比自己动手更可取。

Also as another aside, JNA already includes a mapping for WinNT.HANDLE which may be preferable to rolling your own.

这篇关于线程“主”中的JNA异常java.lang.Error:无效的内存访问(未知源)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆