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
总而言之,
- Linux 32 位 MCR(matlab 编译器运行时)+ 32 位 Java6/7/8:有效
- Windows 32 位 MCR(matlab 编译器运行时)+ 32 位 Java6/7/8:有效
- Windows 64 位 MCR(matlab 编译器运行时)+ 64 位 Java6/7/8:有效
- Linux 64 位 MCR(matlab 编译器运行时)+ 64 位 Java6/7/8:JNA 崩溃
到目前为止,我尝试设置 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
我有一个遗留 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
总而言之,
- Linux 32 位 MCR(matlab 编译器运行时)+ 32 位 Java6/7/8:有效
- Windows 32 位 MCR(matlab 编译器运行时)+ 32 位 Java6/7/8:有效
- Windows 64 位 MCR(matlab 编译器运行时)+ 64 位 Java6/7/8:有效
- Linux 64 位 MCR(matlab 编译器运行时)+ 64 位 Java6/7/8:JNA 崩溃
到目前为止,我尝试设置 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