Running c++ application using JNI functions in debug build causes segmentation fault - java

I've got a c++ application that uses jni to get access to java functions.
As long as I build my application in release everything is fine and works. But when I build the application in debug, the application crashes as soon as it calls the jni code.
I'm using QTCreator under Ubuntu 14.04 x64 with gcc 4.8.2 and java 1.7.0_75
Example Methode:
void JNICommunicator::queryJNI_deleteIndividual(std::string path, std::string individualName){
if(jvmStatus != JNI_ERR){
jclass cls = env->FindClass("de/myclasspacked/MyClass"); //when getting to this point, the application crashes
if(env->ExceptionOccurred()){
env->ExceptionDescribe();
}
if(cls != 0){
jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
jobject object = env->NewObject(cls, constructor);
jmethodID mAC = env->GetMethodID(cls, "deleteIndividual", "(Ljava/lang/String;Ljava/lang/String;)V");
if(mAC != 0){
jstring path = env->NewStringUTF(owlPath.c_str());
jstring individualNameTemp = env->NewStringUTF(individualName.c_str());
jobject jAdd = env->CallObjectMethod(object, mAC, path, individualNameTemp);
if(env->ExceptionOccurred()){
env->ExceptionDescribe();
}
}
}
}
}
any ideas why it crashes or how I can get the application working under debug? Its hard do develop an application without the ability to use debug functions.
Thanks
Best Regards
I get my env from here. This is how I initiate my JVM:
void initJVM(){
std::string dPath = "-Djava.class.path=/svn/owl/OWLApiExample/bin";
char *cstr = new char[dPath .length()+1];
strcpy(cstr, dPath .c_str());
options[0].optionString = cstr;
options[1].optionString = "-Djava.library.path=/svn/owl/OWLApiExample/lib";
options[2].optionString = "-verbose:jni";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = 0;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
jvmStatus = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if(jvmStatus != JNI_ERR){
//log
}else{
jsize nVMs;
jvmStatus = JNI_GetCreatedJavaVMs(NULL, 0, &nVMs); // 1. just get the required array length
jvmStatus = JNI_GetCreatedJavaVMs(&jvm, nVMs, &nVMs); // 2. get the data
jvmStatus = jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
if (jvmStatus == JNI_EDETACHED){
if (jvm->AttachCurrentThread((void **) &env, NULL) != 0) {
//log
}else{
}else if (jvmStatus == JNI_EVERSION) {
//log
}
}
}

Related

How to Set C++ variables with Java Methods?

Making a C++ program and want to receive values from a Java Api using Java method calls.
I have tried using Java Virtual Machines in C++ but it did not work so far. (New to C++ and Java)
How can I set C++ variables with the outputs from Java Methods?
--
Pseudo code of Desired Outcome:
//This example getnumber() Java Method returns back the number you give it
//C++ variables get the results from the Java getnumber() function
double Number1 = getnumber(7.00);
double Number2 = getnumber(9.00);
Code so far:
#include "C:\\Program Files\\Java\\jdk-19\\include\\win32\\jni_md.h"
#include "C:\\Program Files\\Java\\jdk-19\\include\\jni.h"
JavaVM* vm;
jsize vmCount;
if (JNI_GetCreatedJavaVMs(&vm, 1, &vmCount) != JNI_OK || vmCount == 0) {
fprintf(stderr, "Could not get active VM\n");
return NULL;
}
JNIEnv* env;
jint result = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (result == JNI_EDETACHED) {
result = vm->AttachCurrentThread((void**)&env, NULL);
}
if (result != JNI_OK) {
fprintf(stderr, "Failed to get JNIEnv\n");
return NULL;
}
jclass cls = env->FindClass("JMyService");
jmethodID ctor = env->GetMethodID(cls, "<init>", "()V");
jobject service = env->NewObject(cls, ctor);
jmethodID loadMethod = env->GetMethodID(cls, "loadContactInformation", "(I)Ljava/lang/String;");
jobject serviceResult = env->CallObjectMethod(service, loadMethod, userId);
return serviceResult;

JNI Native Interface and JavaFX - NoClassDefFoundError

I have a bash script that launches my program using an embedded JRE. This script works:
#!/bin/bash
exec ./jre/bin/java \
--module-path ./jre/jfx \
--add-modules=javafx.controls,javafx.swing \
--add-opens javafx.controls/javafx.scene.control=ALL-UNNAMED \
-jar hypnos.jar "$#" --base-dir="$ROOT"
I am trying to write a C++ program that uses the JNI Native Interface to replace that bash script. As you can see, they provide identical arguments to the JVM:
#include <jni.h>
int main() {
JavaVM *jvm;
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[4];
options[0].optionString = (char *)"-Djava.class.path=jre/lib/server/:./hypnos.jar";
options[1].optionString = (char *)"--module-path ./jre/jfx";
options[2].optionString = (char *)"--add-modules=javafx.controls,javafx.swing";
options[3].optionString = (char *)"--add-opens javafx.controls/javafx.scene.control=ALL-UNNAMED";
vm_args.version = JNI_VERSION_10;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
delete options;
jmethodID main = NULL;
jclass cls = NULL;
cls = env->FindClass("net/joshuad/hypnos/Hypnos");
if(env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
if (cls != NULL) {
main = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
} else {
printf("Unable to find the requested class\n");
}
if (main != NULL) {
env->CallStaticVoidMethod( cls, main, " ");
} else {
printf("main method not found") ;
}
jvm->DestroyJavaVM();
return 0;
}
However, the bash script works while the C++ program gives me:
Exception in thread "main" java.lang.NoClassDefFoundError: javafx/application/Application with a stack trace.
I can't understand this, because it seems that the C++ program is doing the same thing that the bash script is doing.
I have an almost-identical version of this C++ program that launches a "hello world" java program that doesn't depend on javafx, and it works. So the issue seems to be the JVM created by C++ can't find JavaFX. However, I'm pointing it all the same places that the working bash script is being pointed at, so I'm not sure why it can't find JavaFX.
Any idea how to address this?
This
vm_args.nOptions = 1;
needs to be
vm_args.nOptions = 4;

Calling Java functions from C language

I am tying to call java functions from c code.
I used the JNI as discussed in the example at http://www.ishaanguliani.com/content/calling-java-functions-c-linux-ubuntu-jni
I used the same code and followed the same steps but I am getting unable to find the class print.
I debugged but I didnt find what I did wrong.
Sharing my code here
unions#universe:~/uni_tmp/jni/vvn$ cat MyC.c
#include <stdio.h>
#include <jni.h>
#include "MyJava.h"
#include <string.h>
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
options.optionString = "-Djava.class.path=./"; //Path to the java source code
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args);
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;
}
int main(void)
{
JNIEnv *env;
JavaVM *jvm;
jmethodID mainMethod = NULL;
jmethodID smfnMethod = NULL;
jclass clsJava=NULL;
jstring StringArg=NULL;
env = create_vm(&jvm);
if (env == NULL)
{
printf("\n Unable to create environment");
return 1;
}
clsJava = (*env)->FindClass(env,"MyJava");
if (clsJava != NULL)
{
printf("\n Able to find the requested class\n");
} else {
printf("\n Unable to find the requested class\n");
return 0;
}
mainMethod = (*env)->GetStaticMethodID(env, clsJava, "main", " ([Ljava/lang/String;)V");
smfnMethod = (*env)->GetStaticMethodID(env, clsJava,"sampleStaticFunc", "(Ljava/lang/String;)V");
if (mainMethod != NULL)
{
printf("\n Calling the Java Main method");
(*env)->CallStaticVoidMethod(env, clsJava, mainMethod, NULL);
}
StringArg = (*env)->NewStringUTF(env, "Argument from C");
if (smfnMethod != NULL)
{
printf("\n Calling the Static Function method");
(*env)->CallStaticVoidMethod(env, clsJava, smfnMethod, StringArg);
}
printf("\n End C main \n");
return 0;
}
Java code
cat unions#universe:~/uni_tmp/jni/vvn$ cat MyJava.java
public class MyJava
{
public MyJava()
{
System.out.println("\n Inside the constrcutor of Java Function \n ");
}
private void sampleFunc(String str)
{
System.out.println("\n Inside sampleFunc value of string = " + str);
}
public static void sampleStaticFunc(String str)
{
System.out.println("\n Inside static sampleFunc value of string = " + str);
}
public static void main(String[] args)
{
MyJava obj = new MyJava();
obj.sampleFunc("Ishaan is my name");
System.out.println("\n Calling Java from C function \n");
}
}
After that Ran these commands
unions#universe:~/uni_tmp/jni/vvn$ javac MyJava.java
unions#universe:~/uni_tmp/jni/vvn$ javah -jni MyJava
When I compiled and Ran I got this output
export LD_LIBRARY_PATH=/usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server
unions#universe:~/uni_tmp/jni/vvn$ gcc -I /usr/lib/jvm/java-6-openjdk-amd64/include -I /usr/lib/jvm/java-6-openjdk-amd64/include/linux -L /usr/bin/java -L /usr/lib/jvm/java-6-openjdk-amd64/jre/lib/amd64/server MyC.c -ljvm ; ./a.out
Unable to find the requested class
Where I did wrong?
I changed the options.optionString to like this too
options.optionString = "-Djava.class.path=/home/vpraveen/uni_tmp/jni/vvn";
Even though There is no change in the output.
Any suggestions?
I solved this by making my class into my own package.
When we did not define any package it is taking as default package.
So I created my own package something like this
package com.aqu.vvn
I know its a work around but doing this worked for me.
I will let u know the exact way when I figured out.

What is in android.util.Log#println_native()?

Here is the android.util.Log source code.
At the very bottom (line 340), what is in the method:
public static native int println_native(int bufID,
int priority, String tag, String msg);
i guess println_native() is more or less like its println(), just with an int bufID different.
But even i got the codes of println_native(), i still lack com.android.internal.os.RuntimeInit (line 19, the import) to simulate android.util.Log in old Android version.
Just did some digging in the android source code. This function maps to
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
const char* tag = NULL;
const char* msg = NULL;
if (msgObj == NULL) {
jniThrowNullPointerException(env, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -1;
}
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
msg = env->GetStringUTFChars(msgObj, NULL);
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
Basically this then passes the arguments to the driver in the system which goes and writes to the Log buffer. Log buffer is pointed by /dev/log in the Linux kernel.
Once you have downloaded the sdk, you can use find to dig files.
Java code is linked to cpp code through jni.
In your case, you can use this command to find the related files:
find framework -type f -name "*.cpp" -exec grep "println_native" {} \; -ls
then you'll see that your java function is linked to this file : framework/base/core/jni/android_util_Log.cpp

Undefined Reference Trying to invoke Java from C++

I am trying to create a Java virtual machine from C++ and invoke the main method passing a String argument to the main method of the Java program. I am following this example found on Sun's website: http://java.sun.com/docs/books/jni/html/invoke.html#11202
Here is the simple Java Program:
public class TestJNIInvoke
{
public static void main(String[] args)
{
System.out.println(args[0]);
}
}
Here is the C++ program I am using to (try to) invoke the JVM:
#include <jni.h>
#include <cstdlib>
using namespace std;
int main()
{
JNIEnv *env;
JavaVM *jvm;
jint res;
jclass cls;
jmethodID mid;
jstring jstr;
jclass stringClass;
jobjectArray args;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1]; //LINE 18 ERROR
options[0].optionString =
(char*)&"-Djava.class.path=C:\\Program Files\\Java\\jdk1.7.0\\bin";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); //LINE 26 ERROR
if (res < 0)
{
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}
cls = env->FindClass("TestJNIInvoke");
if (cls == NULL)
{
goto destroy;
}
mid = env->GetStaticMethodID(cls, "main",
"([Ljava/lang/String;)V");
if (mid == NULL)
{
goto destroy;
}
jstr = env->NewStringUTF(" from CPP!");
if (jstr == NULL)
{
goto destroy;
}
stringClass = env->FindClass("java/lang/String");
args = env->NewObjectArray(1, stringClass, jstr);
if (args == NULL)
{
goto destroy;
}
env->CallStaticVoidMethod(cls, mid, args);
destroy:
if (env->ExceptionOccurred())
{
env->ExceptionDescribe();
}
jvm->DestroyJavaVM();
}
Anyway If I just compile the file with:
gcc -I"c:\Program Files\Java\jdk1.7.0\include"
-I"c:\Program Files\Java\jdk1.7.0\include\win32" -c TestJNIInvoke.cpp
It compiles fine, but when I try to compile and link:
gcc -I"c:\Program Files\Java\jdk1.7.0\include"
-I"c:\Program Files\Java\jdk1.7.0\include\win32" -g TestJNIInvoke.cpp
I get two weird errors that I don't understand:
TestJNIInvoke.cpp:18: undefined reference to `operator new[](unsigned int)'
TestJNIInvoke.cpp:26: undefined reference to `_imp__JNI_CreateJavaVM#12'
collect2: ld returned 1 exit status
I marked the lines in the above code where the error is occuring, has anyone encountered this problem before?
Any ideas/links would be great
Thanks
First, don't use gcc. By default, it assumes the code it's handling is written in C. When you want it to compile or link C++ code, you should run g++. This will bring in the C++ standard headers and libraries.
Second, you need to include the java libraries. Section 7.2.1 in the page you linked discusses this.
Your command line should look more like this:
g++ -I"C:\Program Files\Java\jdk1.7.0\include" -L"C:\Program Files\Java\jdk1.7.0\lib" -lthread -ljava TestJNIInvoke.cpp
Note that you might have to add additional include (-I) or linker (-L) directories.

Categories