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)
======================================================================