JNI DLL崩溃JVM(仅限32位)

时间:2014-06-30 08:11:23

标签: windows java-native-interface 32-bit jvm-crash

我有一个JNI DLL,它在类对象上使用GetFieldID()时会崩溃,并传递给函数。该库在Linux上运行良好,具有32位和64位JVM,在Windows下使用32位时只会崩溃 - 64位就可以了。

使用MinGW-w64 GCC 4.6.3在ubuntu 13.10 x86_64上交叉编译原始DLL,但我也使用MinGW-w64 GCC 4.6.3在Windows下本地编译它,我仍然遇到了同样的崩溃。使用带有MinGW-w64 4.8.2的ubuntu 14.04仍会产生相同的错误。

似乎存在一些内存损坏,因为当我使用未经优化的DLL时,崩溃不会发生在GetFieldID()上的第一次调用,但是在稍后的版本上(原始DLL的代码多于下面的简化示例)或者甚至在函数在JVM垃圾收集中的某处完成之后。

我使用的JVM是Java 7u60,但我也尝试使用8u5并得到了相同的结果。我在64位和32位系统上使用32位JVM对它进行了测试,因为我看到一篇文章说,32位JVM在64位Windows操作系统上可能不可靠(听起来有点)对我来说是虚假的,但只是为了确定。)

还有其他JNI DLL,它们根本不使用GetFieldID(),而且它们在32位工作正常。

来自hs_err_pid.log的崩溃数据

Current thread (0x00d5e000):  JavaThread "main" [_thread_in_native, id=1104, stack(0x00dd0000,0x00e20000)]

siginfo: ExceptionCode=0xc0000005, ExceptionInformation=0x00000008 0x3462c9e8

Registers:
EAX=0x00000000, EBX=0x00e1f1fc, ECX=0x97254d7c, EDX=0x00d5eac4
ESP=0x00e1f1dc, EBP=0x00e1f1ec, ESI=0x3462c6e8, EDI=0x00d5e000
EIP=0x3462c9e8, EFLAGS=0x00010246

Top of Stack: (sp=0x00e1f1dc)
0x00e1f1dc:   00000000 3462c6e8 00000000 00e1f1fc
0x00e1f1ec:   00e1f224 025f334f 246970c0 025f88c9
0x00e1f1fc:   24695668 2460b700 00e1f204 34628d1b
0x00e1f20c:   00e1f22c 34628ee8 00000000 34628d40
0x00e1f21c:   00e1f1fc 00e1f22c 00e1f25c 025f3207
0x00e1f22c:   24693760 24693760 00000001 24693758
0x00e1f23c:   00e1f234 34628c56 00e1f264 34628ee8
0x00e1f24c:   00000000 34628c88 00e1f22c 00e1f268 

Instructions: (pc=0x3462c9e8)
0x3462c9c8:   78 bc 62 34 50 bb 62 34 c0 bd 62 34 30 bd 62 34
0x3462c9d8:   00 00 00 00 00 00 00 00 0c 00 00 00 02 00 00 00
0x3462c9e8:   01 00 00 00 60 f9 5f 39 02 00 00 00 a0 b9 62 34
0x3462c9f8:   0a 00 b8 00 10 d6 00 39 00 00 00 00 01 00 40 80 


Register to memory mapping:

EAX=0x00000000 is an unknown value
EBX=0x00e1f1fc is pointing into the stack for thread: 0x00d5e000
ECX=0x97254d7c is an unknown value
EDX=0x00d5eac4 is an unknown value
ESP=0x00e1f1dc is pointing into the stack for thread: 0x00d5e000
EBP=0x00e1f1ec is pointing into the stack for thread: 0x00d5e000
ESI=0x3462c6e8 is an oop
{method} 
 - klass: {other class}
EDI=0x00d5e000 is a thread


Stack: [0x00dd0000,0x00e20000],  sp=0x00e1f1dc,  free space=316k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  0x3462c9e8
j  jnitest.JNIClass.<init>()V+27
j  jnitest.JNIClass.getInstance()Ljnitest/JNIClass;+22
j  jnitest.Program.main([Ljava/lang/String;)V+0
v  ~StubRoutines::call_stub
V  [jvm.dll+0x140e6a]
V  [jvm.dll+0x20529e]
V  [jvm.dll+0x140eed]
V  [jvm.dll+0x14d2ee]
V  [jvm.dll+0x14d515]
V  [jvm.dll+0xf1f99]
C  [java.dll+0x7d82]
j  sun.reflect.NativeMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+87
j  sun.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+6
j  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+57
j  com.intellij.rt.execution.application.AppMain.main([Ljava/lang/String;)V+163
v  ~StubRoutines::call_stub
V  [jvm.dll+0x140e6a]
V  [jvm.dll+0x20529e]
V  [jvm.dll+0x140eed]
V  [jvm.dll+0xca5c5]
V  [jvm.dll+0xd5267]
C  [java.exe+0x2063]
C  [java.exe+0xa5d1]
C  [java.exe+0xa65b]
C  [kernel32.dll+0x1338a]
C  [ntdll.dll+0x39f72]
C  [ntdll.dll+0x39f45]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  jnitest.JNIWrapper.createUuid(Ljnitest/JNIWrapper$sender_id_t;)I+25
j  jnitest.JNIClass.<init>()V+27
j  jnitest.JNIClass.getInstance()Ljnitest/JNIClass;+22
j  jnitest.Program.main([Ljava/lang/String;)V+0
v  ~StubRoutines::call_stub
j  sun.reflect.NativeMethodAccessorImpl.invoke0(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+0
j  sun.reflect.NativeMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+87
j  sun.reflect.DelegatingMethodAccessorImpl.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+6
j  java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;+57
j  com.intellij.rt.execution.application.AppMain.main([Ljava/lang/String;)V+163
v  ~StubRoutines::call_stub

Java类:

package jnitest;

public class JNIClass {
    static final Object _mutex = new Object();
    static JNIClass _instance = null;

    public static JNIClass getInstance()
    {
        if (_instance == null)
        {
            synchronized (_mutex)
            {
                if (_instance == null)
                    _instance = new JNIClass();
            }
        }
        return _instance;
    }

    JNIWrapper.sender_id_t sid = null;

    JNIClass() {
        //create uuid
        sid = new JNIWrapper.sender_id_t();
        System.out.print(JNIWrapper.createUuid(sid));
    }
}

JNI包装类:

package jnitest;

public final class JNIWrapper {
    static {
        System.loadLibrary("JNIWrapper");
    }

    public static class sender_id_t
    {
        public long phy_idx;
    }

    public static native int createUuid(JNIWrapper.sender_id_t id);
}

申请表:

package jnitest;

public class Program
{
    public static void main(String[] args)
    {
        JNIClass.getInstance();

        System.exit(0);
    }
}

自动生成的JNI DLL标头:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class jnitest_JNIWrapper */

#ifndef _Included_jnitest_JNIWrapper
#define _Included_jnitest_JNIWrapper
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     jnitest_JNIWrapper
 * Method:    createUuid
 * Signature: (Ljnitest/JNIWrapper/sender_id_t;)I
 */
JNIEXPORT jint JNICALL Java_jnitest_JNIWrapper_createUuid
  (JNIEnv *, jclass, jobject);

#ifdef __cplusplus
}
#endif
#endif

JNI DLL实现(更新为能够使用C或C ++接口):

#include "jnitest_JNIWrapper.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
#define JNIFUNC(e,f)    e->f()
#define JNIFUNCV(e,f,...)   e->f(__VA_ARGS__)
#else
#define JNIFUNC(e,f)    (*e)->f(e)
#define JNIFUNCV(e,f,...)   (*e)->f(e,__VA_ARGS__)
#endif

JNIEXPORT jint JNICALL Java_jnitest_JNIWrapper_createUuid(JNIEnv *env, jclass clazz, jobject sid)
{
    (void)clazz;
    jclass cls = JNIFUNCV(env,GetObjectClass, sid);
    jfieldID phyID = JNIFUNCV(env,GetFieldID, cls, "phy_idx", "J");
    (void)phyID;
    if (JNIFUNC(env,ExceptionCheck))
        return 100;
    return 0;
}

#ifdef __cplusplus
}
#endif

更新

编译命令:

i686-w64-mingw32-gcc -std=c99 -O3 -s -Wall -Wextra -Werror -o ../bin/JNIWrapper.dll -shared -Wl,--subsystem,windows dllmain.c JNIWrapper.c -I /usr/lib/jvm/java-7-openjdk-amd64/include

1 个答案:

答案 0 :(得分:0)

您正在尝试获取内部类的字段ID,但您的cls变量是外部类JNIWrapper。您可能需要运行类似(* env) - &gt; FindClass(env,&#34; jnitest / JNIWrapper $ sender_id_t&#34;)以获取正确的cl来调用get field id。 javap -c工具可以告诉您&#34; jnitest / JNIWrapper $ sender_id_t&#34;应该。