JNA 在 Linux 上以 64 位 libmx.so 崩溃

JNA crashes with 64 bit libmx.so on Linux

我有一个遗留 Java 应用程序,它使用 JNA 与 Matlab C 矩阵交互 API。

/**
 * Load a MAT-file. Must be synchronized because of native libraries calls.
 *
 * @param file MAT file
 * @return map with the variables in the MAT file
 */
public static synchronized Map<String, MObj> load(final File file) {
    if (file == null) {
        throw new InvalidMatFileException(null, ERROR_MSG_FILE_NOT_FOUND);
    }
    if (!file.isFile()) {
        throw new InvalidMatFileException(file.getName(), ERROR_MSG_FILE_NOT_FOUND);
    }
    final Map<String, MObj> vars = new HashMap<String, MObj>();
    final Pointer matfile = MAT_LIB.matOpen(file.getAbsolutePath(), "r");
    if (matfile == null) {
        throw new InvalidMatFileException(file.getName(), ERROR_MSG_NOT_A_PROPER_MAT_FILE);
    }
    for (;;) {
        final PointerByReference name = new PointerByReference();
        final Pointer ar = MAT_LIB.matGetNextVariable(matfile, name);
        if (ar == null) {
            break;
        }
        final MObj obj = ToJava.convert(MX_LIB, ar);
        MX_LIB.mxDestroyArray(ar);
        vars.put(name.getValue().getString(0), obj);
    }
    MAT_LIB.matClose(matfile);
    return vars;
}

//ToJava class has the following methods that are called from the code above
 /**
 * Convert a single mxArray
 *
 * @param mx MX library
 * @param ar mxArray
 * @return MObj instance
 */
public static MObj convert(MX mx, Pointer ar) {
    final ToJava tr = new ToJava(mx);
    tr.transform(ar);
    return tr.obj;
}

/**
 * Top-level transform
 *
 * @param ar mxArray
 */
private void transform(Pointer ar) {
    final ClassID classID = ClassID.valueOf(mx.mxGetClassID(ar));
    switch (classID) {

    case DOUBLE:
        transformDoubleArray(ar);
        break;

for 循环内

ToJava.convert
调用

mx.mxGetClassID(ar)

引擎盖下。这是 defined in the api

mxClassID mxGetClassID(const mxArray *pm);

其中 mxClassID 是一个枚举。这在 JNA 中映射为

int mxGetClassID(Pointer ar);

这正是导致下面崩溃的代码

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fbb7fcd45f0, pid=13363, tid=140445588428544
#
# JRE version: 6.0_45-b06
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.45-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libmx.so+0x615f0]  matrix::detail::noninlined::mx_array_api::mxGetClassID(mxArray_tag const*)+0x0
Register to memory mapping:

RAX=0x0000000000000000 is an unknown value
RBX=0x0000000000000008 is an unknown value
RCX=0x00007fbc04252a7a is an unknown value
RDX=0x00007fbc04252a7a is an unknown value
RSP=0x00007fbc09686888 is pointing into the stack for thread: 0x00007fbc04006800
RBP=0x00007fbc09686890 is pointing into the stack for thread: 0x00007fbc04006800
RSI=0x00007fbc04252a7a is an unknown value
RDI=0x0000000000000000 is an unknown value
R8 =0x00007fbc04252a7a is an unknown value
R9 =0x00007fbc04252a95 is an unknown value
R10=0x0000000000000000 is an unknown value
R11=0x00007fbb7fd46800: mxGetClassID+0 in /var/opt/Matlab_MCR/v91/bin/glnxa64/libmx.so at 0x00007fbb7fc73000
R12=0x00007fbc096869d0 is pointing into the stack for thread: 0x00007fbc04006800
R13=0x0000000000000008 is an unknown value
R14=0x0000000000000001 is an unknown value
R15=0x00007fbc096869b0 is pointing into the stack for thread: 0x00007fbc04006800

 Stack: [0x00007fbc09589000,0x00007fbc0968a000],  sp=0x00007fbc09686888,  free space=1014k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libmx.so+0x615f0]  matrix::detail::noninlined::mx_array_api::mxGetClassID(mxArray_tag const*)+0x0

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  com.sun.jna.Native.invokeInt(Lcom/sun/jna/Function;JI[Ljava/lang/Object;)I+0
j  com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;ZI)Ljava/lang/Object;+211
j  com.sun.jna.Function.invoke(Ljava/lang/reflect/Method;[Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+271
j  com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+390
j  com.sun.proxy.$Proxy12.mxGetClassID(Lcom/sun/jna/Pointer;)I+16

总而言之,

到目前为止,我尝试设置 LD_LIBRARY_PATH 和 java.library.path 并将两者都指向文件系统上的 MCR 位置

/var/opt/Matlab_MCR/v91/runtime/glnxa64:/var/opt/Matlab_MCR/v91/bin/glnxa64:/var/opt/Matlab_MCR/v91/sys/os/glnxa64

有人知道如何进一步解决这个问题吗?

本题代码通过JNA调用Matlab Compiler Runtime暴露的函数。事实证明 对于 64 位架构,Matlab 端的接口已更改。他们在原生 API 签名中使用 mwSize 类型,而我们的 JNA 映射使用 int。在 mwSize 等于 size_t 的 64 位机器上,int 将为 32 位。因此,JNA 映射和本机 API 签名不再匹配。通过JNA反复调用这些函数后,甚至导致JNA崩溃。

解决方向是将Java上的int替换为64位整数code.This可以通过扩展JNA提供的名为IntegerType的抽象class并使用这个扩展来完成class 适用时

来自 Matlab 的参考文章: https://nl.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html