JDK-4496402 : Call to JNI_CreateJavaVM crashes with Error ID 5448524541440E4350500630 FF
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 1.3.1
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: solaris_2.6
  • CPU: sparc
  • Submitted: 2001-08-24
  • Updated: 2001-09-28
  • Resolved: 2001-09-28
Description

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

Comments
WORK AROUND Name: ddT132432 Date: 08/24/2001 No work around. ======================================================================
11-06-2004

EVALUATION THis bug can not be reproduced. I am going to close it as "not a bug". ###@###.### 2001-09-28
28-09-2001