JNI“env->GetStaticMethodID()”崩溃的程序

发布于 2024-12-06 17:35:55 字数 2664 浏览 0 评论 0原文

我正在尝试从 C++ 调用 Java 函数。 到目前为止,这是我的代码:

#include <jni.h>

typedef struct JavaVMCreationResult {
    JavaVM* jvm;
    JNIEnv* env;
} JVMCreationResult;

JVMCreationResult* CreateJavaVM() {
    JavaVM* jvm;
    JNIEnv* env;

    JavaVMInitArgs args;

    JavaVMOption opts[1];
    opts[0].optionString = "-Djava.class.path=C:\\MyJavaClasses";

    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    args.options = opts;
    args.ignoreUnrecognized = JNI_TRUE;

    JNI_GetDefaultJavaVMInitArgs(&args);

    JNI_CreateJavaVM(&jvm, (void **) &env, &args);

    JavaVMCreationResult* cres;
    cres->jvm = jvm;
    cres->env = env;

    return cres;
}

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line
}

我在 Windows 7 上使用 Code::Blocks 和 MinGW GCC。
main() 函数中的最后一行使程序崩溃,但编译器不会抱怨任何事情。 (注释掉 jmethodID mid = env->GetSta... 行使程序“不会崩溃”)
我已经使用 javap -s Main 来获取正确的方法签名,并且该类也是有效的 Java 类。

你能告诉我程序崩溃的原因吗?这个例子在互联网上随处可见,但对我来说不起作用。 :(

这是 Java 类:

public class Main {
    public static void main(String[] args) {
        System.out.println("This is from Java !");
    }
}

解决方案

我没想到,当结构未初始化时程序没有提前崩溃,这对我来说似乎不合逻辑。但这确实是问题所在。
这是完整且有效的代码!

#include <jni.h>

#ifndef null
#define null NULL
#endif

typedef struct JavaVMCreationResult {
    JavaVM* jvm;
    JNIEnv* env;
} JVMCreationResult;

JVMCreationResult* CreateJavaVM() {
    JavaVM* jvm;
    JNIEnv* env;

    JavaVMInitArgs args;

    JavaVMOption opts[1];
    opts[0].optionString = "-Djava.class.path=C:\\Users\\Claudia\\Desktop";

    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    args.options = opts;
    args.ignoreUnrecognized = JNI_TRUE;

    JNI_GetDefaultJavaVMInitArgs(&args);

    JNI_CreateJavaVM(&jvm, (void **) &env, &args);

    JVMCreationResult* cres = new JVMCreationResult();
    cres->jvm = jvm;
    cres->env = env;

    return cres;
}

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    if (cls) {
        printf("Yes !\n");
    }
    else {
        printf("No !\n");
    }
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(cls, mid);

    printf("At end of Program.");
}

I'm trying to call a Java function from C++.
This is my code so far:

#include <jni.h>

typedef struct JavaVMCreationResult {
    JavaVM* jvm;
    JNIEnv* env;
} JVMCreationResult;

JVMCreationResult* CreateJavaVM() {
    JavaVM* jvm;
    JNIEnv* env;

    JavaVMInitArgs args;

    JavaVMOption opts[1];
    opts[0].optionString = "-Djava.class.path=C:\\MyJavaClasses";

    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    args.options = opts;
    args.ignoreUnrecognized = JNI_TRUE;

    JNI_GetDefaultJavaVMInitArgs(&args);

    JNI_CreateJavaVM(&jvm, (void **) &env, &args);

    JavaVMCreationResult* cres;
    cres->jvm = jvm;
    cres->env = env;

    return cres;
}

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line
}

I'm using Code::Blocks with MinGW GCC on Windows 7.
The last line in the main() function crashes the Program, but the compiler does not complain about anything. (Commenting out the jmethodID mid = env->GetSta... line makes the program "not crashing")
I have uses javap -s Main to obtain the right method signature, also the class is a valid Java class.

Can you tell me why the Program crashes ? This example is just shown everywhere on the Internet but it doesn't work for me. :(

This is the Java class:

public class Main {
    public static void main(String[] args) {
        System.out.println("This is from Java !");
    }
}

SOLUTION

I wouldn't have thought it, it seems unlogic to me that the program wasn't crashing earlier when the struct wasn't initialized. But this was really the issue.
This is the full and working code !

#include <jni.h>

#ifndef null
#define null NULL
#endif

typedef struct JavaVMCreationResult {
    JavaVM* jvm;
    JNIEnv* env;
} JVMCreationResult;

JVMCreationResult* CreateJavaVM() {
    JavaVM* jvm;
    JNIEnv* env;

    JavaVMInitArgs args;

    JavaVMOption opts[1];
    opts[0].optionString = "-Djava.class.path=C:\\Users\\Claudia\\Desktop";

    args.version = JNI_VERSION_1_6;
    args.nOptions = 1;
    args.options = opts;
    args.ignoreUnrecognized = JNI_TRUE;

    JNI_GetDefaultJavaVMInitArgs(&args);

    JNI_CreateJavaVM(&jvm, (void **) &env, &args);

    JVMCreationResult* cres = new JVMCreationResult();
    cres->jvm = jvm;
    cres->env = env;

    return cres;
}

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    if (cls) {
        printf("Yes !\n");
    }
    else {
        printf("No !\n");
    }
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(cls, mid);

    printf("At end of Program.");
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

孤独患者 2024-12-13 17:35:55

您的变量“cres”是 CreateJavaVM 调用中从未初始化的点,因此您可能在该点取消引用空指针或其他无效指针。

一种解决方案是在main中定义cres(不是指向cres的指针),并将指向that的指针作为参数传递给CreateJavaVM,然后在CreateJavaVM内部使用该参数返回结果。

此外,最好检查 JNI_CreateJavaVM 调用后 jvm 和 env 是否获取非空值,以及分别调用 FindClass 和 GetStaticMethodID 后 cls 和 mid 是否同样非空值。

Your variable "cres" is a point in the CreateJavaVM call that is never initialized, so you're probably dereferencing a null or otherwise invalid pointer at that point.

One solution is to define cres (not a pointer to cres) in main, and pass a pointer to that to CreateJavaVM as a parameter, and then use the parameter inside CreateJavaVM to return the result.

Also it's a good idea to check that jvm and env get non-null values after the JNI_CreateJavaVM call, and that cls and mid are likewise non-null after the calls to FindClass and GetStaticMethodID, respectively

黑白记忆 2024-12-13 17:35:55

cls 可能无效。我认为如果“cres”为空,您的程序会更早崩溃。

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    if(!cres) return -1;
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    if(env->ExceptionCheck()) {    // ClassNotFoundException ?
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
    if(!cls) return -2;    // this I think is your problem
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line
}

您确定您的类路径已正确指定吗?希望 FindClass("Main") 能够找到默认的包类。无论如何,请告诉我们您的 C/C++ main() 现在的返回值。

可能是“JavaVM* jvm = cres->jvm;”被优化掉,因为“jvm”从未被引用,并且语句“cres->jvm”没有副作用。一些评论者表示,如果生成代码然后执行,它应该会崩溃,嗯,也许是的。但一个像样的编译器可能会认为这是一个 no 操作。

然而语句“JNIEnv* env = cres->env;”无法优化掉,因为稍后会使用变量“env”。所以我们只能断言,如果 cres==0 那么它会在执行时或之前崩溃。由于“env”用于 FindClass() 调用,因此我们可以确定 env!=0,因此 cres!=0。

我猜你有类路径设置问题,FindClass() 在运行时找不到你的类,这导致“cls==0”为真。这就是我在这里的答案。

编辑:我看到其他人对“cres”的说法,但这并没有改变我最初的诊断,但你仍然有一个关于“cres”的错误,将行更改为:

JavaVMCreationResult* cres = new JavaVMCreationResult;

我认为你很幸运,cres 指向某个地方(可能),然后将这些值复制到本地 main() 堆栈并使用这些值。但这并不能使该技术正确,因为“cres”指向的初始内存是随机的,所以你很幸运没有发生崩溃,但你确实在不应该拥有的内存上乱写乱画。通过使用“cres = new JavaVMCreationResult;”这会导致指针被设置为已知的有效内存块。

如果您需要编译器帮助解决此问题(即它应该显示警告),请尝试在编译期间使用 MinGW“-Wall”和“-O2”选项。它应该警告变量“cres”的未初始化使用。

cls is probably invalid. I presume your program would have crashed earlier if 'cres' was null.

int main() {
    JVMCreationResult* cres = CreateJavaVM();
    if(!cres) return -1;
    JavaVM* jvm = cres->jvm;
    JNIEnv* env = cres->env;

    jclass cls = env->FindClass("Main");
    if(env->ExceptionCheck()) {    // ClassNotFoundException ?
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
    if(!cls) return -2;    // this I think is your problem
    jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); // the evil line
}

Are you sure your classpath has been specified correctly ? Hopefully FindClass("Main") will find a default package class. Anyhow tell us the return value if your C/C++ main() now.

It is possible for the "JavaVM* jvm = cres->jvm;" to be optimized away, since "jvm" is never referenced and the statement "cres->jvm" has no side effects. Some commenters state it should crash on this, hmm yes maybe, if code was generated and then executed. But a decent compiler might see it is a no operation.

However the statement "JNIEnv* env = cres->env;" can not be optimized away, since the variable "env" is used later on. So we can only claim that if cres==0 then it would crash at or before this point in execution. Since "env" is used for FindClass() call then we know for sure that env!=0 and therefore cres!=0.

I would guess you have a Class Path setup issue, FindClass() is not finding your class at runtime which is causing "cls==0" to be true. Which is my answer here.

EDITED: I see what the others are claiming over 'cres' however that does not change my original diagnosis, but you still have a bug regarding 'cres', change the line to:

JavaVMCreationResult* cres = new JavaVMCreationResult;

I think you are lucky that cres is pointing somewhere (probably on the stack), you then copied the values into the local main() stack and used the values. But that doesn't make the technique correct as the initial memory that 'cres' is pointing to is random, so you are lucky that no crash occured but you did scribble on memory you should not have. By using the "cres = new JavaVMCreationResult;" this causes the pointer to be set to a known valid block of memory.

If you want compiler assistance with this problem (i.e. it should show up a warning) try with MinGW "-Wall" and "-O2" options during compile. It should warn about uninitialized use of the variable 'cres'.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文