Name: ddT132432 Date: 08/24/2001 java version "1.3.1" Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24) Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode) 0) First Note -------------- Java Code is not involved in this problem. Program crashes when calling JNI_CreateJavaVM invocation API function. Native Code is provided below with Makefile. Java Code is provided as well. 1) Description of Native Program. --------------------------------- I wrote a program in C++, based on a recursive function which has two parameters. Let's call it ContructOrCall, its prototype is void ContructOrCall(int construct, int level). This function calls itself ContructOrCall(construct, level - 1) until level is 0. If level is 0, then ContructOrCall constructs a Java Object (by calling a function named TJSI_RunJavaApp, see description below) if construct equals 1, else ContructOrCall calls a method of the constrcuted Java Object (done by a call to TJSI_CallMethod). Before testing the value of level, ContructOrCall fills in a local array whose role is to fill in the CPU stack. 2) Bug rises ------------ Depending on the recursive depth, loading the Java VM may fail as the call to JNI_CreateJavaVM displays the following error message, followed by a core dump due to a segmentation fault : # # HotSpot Virtual Machine Error, Internal Error # Please report this error at # http://java.sun.com/cgi-bin/bugreport.cgi # # Error ID: 5448524541440E4350500630 FF # # Problematic Thread: Segmentation Fault (core dumped) 3) Native Source Code and MakeFile ----------------------------------- 3.1 Main2.cpp ------------- #include <iostream.h> #include <stdio.h> #define GARBAGE_SIZE 5000 #define GARBAGE_VAL 10 TJSI_Handle h; int *dummy; void ContructOrCall(int construct, int level) { int i; int garbage[GARBAGE_SIZE]; for(i = 0;i < GARBAGE_SIZE;i++) { garbage[i] = (int)dummy; } cout << "ContructOrCall[" << construct << "] : level = " << level << " " << (unsigned int) &i << "," << (unsigned int) &dummy << endl; if(level > 0) { ContructOrCall(construct, level - 1); } else { if(construct) { cout << "Construct!!" << endl; h = TJSI_RunJavaApp("ProgressBarDemo", "<init>"); cout << "ContructOrCall : construct : h = " << h << endl; } else { cout << "Call!!" << endl; int k = TJSI_CallMethod(h, "SetProgressBarVal", 50); } } } int main(void) { int k,level; dummy = (int*)malloc(sizeof(int)); // (int*)10; // level=25; cout << "ContructOrCall(1, " << level << ")" << endl; ContructOrCall(1, level); level=15; cout << "ContructOrCall(0, " << level << ")" << endl; ContructOrCall(0, level); return 0; } 3.2) tjsi.cpp ------------- #include "tjsi.h" #include <stdarg.h> #include <jni.h> #include <iostream.h> #include <string.h> #define USER_CLASSPATH "." typedef struct TJSI_VMRecord_struct { JNIEnv *env; JavaVM *jvm; char *ClassName; JDK1_1InitArgs vm_args; jclass cls; jobject object; } TJSI_VMRecord; static TJSI_VMRecord VMRecordArray[TJSI_MAXVMINSTANCES]; static int VMRecordArrayIndex = 0; void PrintRecordFields(TJSI_VMRecord aRecord) { cout << "PrintRecordFields : env = " << aRecord.env << endl; cout << "PrintRecordFields : jvm = " << aRecord.jvm << endl; cout << "PrintRecordFields : ClassName = " << aRecord.ClassName << endl; cout << "PrintRecordFields : cls = " << aRecord.cls << endl; cout << "PrintRecordFields : object = " << aRecord.object << endl; return; } TJSI_Handle TJSI_RunJavaApp(char *ClassName, char *ConstrutorName) { static char classpath[1024]; char *tmp; static void *venv; if(VMRecordArrayIndex < TJSI_MAXVMINSTANCES) // OK. Room available. So we go further in creation of VM { VMRecordArray[VMRecordArrayIndex].vm_args.version = JNI_VERSION_1_2; cout << "Before JNI_GetDefaultJavaVMInitArgs(" << VMRecordArrayIndex << ")"<<endl; JNI_GetDefaultJavaVMInitArgs(&(VMRecordArray[VMRecordArrayIndex].vm_args)); cout << "TJSI_RunJavaApp : vm_args.classpath = " << endl; cout <<(VMRecordArray[VMRecordArrayIndex].vm_args).classpath << endl; if(((VMRecordArray[VMRecordArrayIndex].vm_args).classpath) != NULL) { sprintf(classpath, "%s%c%s", ((VMRecordArray[VMRecordArrayIndex].vm_args).classpath), PATH_SEPARATOR, USER_CLASSPATH); } else { sprintf(classpath, "%c%s", PATH_SEPARATOR, USER_CLASSPATH); } cout << "TJSI_RunJavaApp : classpath = <" << classpath << ">" << endl; tmp=strdup(classpath); cout << "tmp" << endl; VMRecordArray[VMRecordArrayIndex].vm_args.classpath = tmp; jint res; VMRecordArray[VMRecordArrayIndex].vm_args.nativeStackSize = 1000000; cout << "Before JNI_CreateJavaVM(" << VMRecordArrayIndex << ")"<< endl; res = JNI_CreateJavaVM(&(VMRecordArray[VMRecordArrayIndex].jvm),&venv,&(VMRecordArray[VMRecordArrayIndex].vm_args)); cout << "OK" << endl; if(res < 0) { // Sorry Folk : Creation of Java VM has failed. return TJSI_CANNOTCREATEVM; } // Creation of Java VM has successed. VMRecordArray[VMRecordArrayIndex].env = (JNIEnv *)venv; cout << "TJSI_RunJavaApp : env = " << VMRecordArray[VMRecordArrayIndex].env <<endl; VMRecordArray[VMRecordArrayIndex].ClassName = strdup(ClassName); VMRecordArray[VMRecordArrayIndex].cls = VMRecordArray[VMRecordArrayIndex].env->FindClass(ClassName); cout << "TJSI_RunJavaApp : cls = " << VMRecordArray[VMRecordArrayIndex].cls <<endl; if(VMRecordArray[VMRecordArrayIndex].cls == 0) { // Sorry Folk : the class name was not found. return TJSI_CANNOTFINDCLASS; } jmethodID mid = VMRecordArray[VMRecordArrayIndex].env->GetMethodID(VMRecordArray[VMRecordArrayIndex].cls, "<init>", "()V"); if(mid == 0) { // Sorry Folk : Could not find a constructor with Signature ()V return TJSI_CANNOTFINDCONTR; } VMRecordArray[VMRecordArrayIndex].object = VMRecordArray[VMRecordArrayIndex].env->NewObject(VMRecordArray[VMRecordArrayIndex].cls, mid); if(VMRecordArray[VMRecordArrayIndex].object == 0) { // Sorry Folk : the class instance could not be created. return TJSI_CANNOTCREATEOBJECT; } ////// jmethodID mid2 = VMRecordArray[VMRecordArrayIndex].env->GetMethodID( VMRecordArray[VMRecordArrayIndex].cls, "SetProgressBarVal","(I)V"); cout << "TJSI_RunJavaApp : mid2 = " << mid2 << endl; VMRecordArray[VMRecordArrayIndex].env->CallVoidMethod(VMRecordArray[VMRecordArrayIndex].object, mid2, 200); ///// // PrintRecordFields(VMRecordArray[VMRecordArrayIndex]); // Reaching this point means erveything is alright : Java VM is now created // and class instance has successfully been created. return VMRecordArrayIndex++; } else // No more room in VMRecordArray. { return TJSI_NOMOREVMHANDLE; } } int TJSI_CallMethod(TJSI_Handle handle, char *MethodName, int i) { if(handle < VMRecordArrayIndex) { TJSI_VMRecord Record = VMRecordArray[handle]; // cout << "TJSI_CallMethod : Record =" << endl; // PrintRecordFields(Record); // cout << "TJSI_CallMethod : VMRecordArray[handle] =" << endl; // PrintRecordFields(VMRecordArray[handle]); jmethodID mid = Record.env->GetMethodID(Record.cls, MethodName, "(I)V"); if(mid == 0) { // Sorry Folk : invalid method. return TJSI_INVALIDMETHODNAME; } Record.env->CallVoidMethod(Record.object, mid, i); } else { // Sorry Folk : got an invalid index. return TJSI_INVALIDHANDLE; } } 3.3) tjsi.h ----------- #ifndef __TJSI_H__ #define __TJSI_H__ // This is an interface to create a VM and instanciate objects typedef int TJSI_Handle; #define TJSI_CANNOTCREATEVM -1 #define TJSI_CANNOTFINDCLASS -2 #define TJSI_CANNOTFINDMETHOD -3 #define TJSI_CANNOTCREATEOBJECT -4 #define TJSI_INVALIDMETHODSIG -5 #define TJSI_INVALIDMETHODNAME -6 #define TJSI_NOMOREVMHANDLE -7 #define TJSI_CANNOTFINDCONTR -8 #define TJSI_INVALIDHANDLE -9 #define TJSI_MAXVMINSTANCES 1024 #ifdef _WIN32 #define PATH_SEPARATOR ';' #else /* UNIX */ #define PATH_SEPARATOR ':' #endif // Instanciate an object of class ClassName by calling Constructor of // name ConstrutorName. It is assumed the signature of constructor is // ()V which is not limitative. // If an error occurs, returns value < 0. Meaning is defined Above. TJSI_Handle TJSI_RunJavaApp(char *, char *); int TJSI_CallMethod(TJSI_Handle , char *, int); #endif JAVA CODE ------------- import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ProgressBarDemo extends JFrame { static private JProgressBar progressBar; private JLabel label; private JLabel overflow; private String newline = "\n"; static void main(String[] args) { int i , j,k; ProgressBarDemo P = new ProgressBarDemo(); for(j = 0; j< 4;j++) { for(i = 0; i < 1024; i++) { ProgressBarDemo.SetProgressBarVal(i ); for(k=0;k<10000;k++){ } } } } public ProgressBarDemo() { super("ProgressBarDemo"); progressBar = new JProgressBar(JProgressBar.HORIZONTAL, 0, 1024); progressBar.setValue(0); progressBar.setStringPainted(true); label = new JLabel("FIFO Filling"); JPanel panel = new JPanel(); panel.add(progressBar); panel.add(label); overflow = new JLabel("No Overflow"); JPanel contentPane = new JPanel(); contentPane.setLayout(new BorderLayout()); contentPane.add(panel, BorderLayout.NORTH); contentPane.add(overflow, BorderLayout.CENTER); setContentPane(contentPane); //Create a timer. addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }}); pack(); setVisible(true); } /** * The actionPerformed method in this class * is called when the user presses the start button. */ static public void SetProgressBarVal(int i) { progressBar.setValue(i); } } 3.4) Makefile !! Set JAVAHOME var accordingly to your environment. -------------- JAVAHOME = JAVALIB = $(JAVAHOME)/jre/lib/sparc IFLAGS = -I$(JAVAHOME)/include -I$(JAVAHOME)/include/solaris -I. LFLAGS = -L$(JAVAHOME)/jre/lib/sparc -L$(JAVAHOME)/lib/sparc # CC = gcc CC = g++ OBJECTS = main2.o tjsi.o .cpp.o: $(CC) -c -g $(IFLAGS) $< all: myjavamake myjavamake: main2.o tjsi.o $(CC) -o $@ $(LFLAGS) $(OBJECTS) -ljava 4) Further Notes. ------------------ TJSI_RunJavaApp : its goal is to hide details of loading a JVM and details of contructing an objet to the user. User gives java class name and contructor name (it is assumed the constructor signature is "()V"), the function returns a handle to the user. If this handle is > 0, TJSI_RunJavaApp successed. Otherwise it failed. TJSI_RunJavaApp manages handles so we can create more than one VM and identify them. TJSI_RunJavaApp manages an array of records of type TJSI_VMRecord. On of TJSI_VMRecord fields is the contructed object ID of which user may later call methods. TJSI_CallMethod : its goal is to hide details of calling a java object method to the user. Prototype of TJSI_CallMethod is int TJSI_CallMethod(TJSI_Handle handle, char *MethodName, int i) The user gives the name of the method he wants to call, with parameter i (it is assumed that method signature is "(I)V"), and gives the handle returned by TJSI_RunJavaApp. (Review ID: 130145) ======================================================================
|